PronounsToday/src/weighted_table.rs

64 lines
2.2 KiB
Rust

use crate::Pronoun;
use time::{Date, Month, OffsetDateTime};
/// The start of the COVID-19 lockdowns
///
/// This is used as an epoch in order to convert from a given date to an integer seed. This is
/// specified as part of the algorithm for randomly selecting from a weighted list.
pub const COVID_EPOCH: Date = match Date::from_calendar_date(2020, Month::January, 26) {
Ok(d) => d,
Err(_) => Date::MIN, // This never runs, but we can't unwrap, so this is what we're stuck with
};
/// A list of pronouns and their associated weights, used for random selection
///
/// Weights are typically representative of a user's preference towards a pronoun. A pronoun with
/// a weight of 10 is twice as likely to be selected as a pronoun with a weight of 5.
///
/// This struct is use to represent these weights before they are used to randomly select a
/// pronoun. Additional methods are provided to perform this random selection on a weighted list,
/// using as a seed both an arbitrary string of bytes and a Date.
pub struct WeightedTable<'a>(pub Vec<(&'a Pronoun, u8)>);
impl<'a> WeightedTable<'a> {
/// A shorthand for calling [`WeightedTable::select_on_date()`] with today's date
///
/// The date is generated for the system's time and timezone
pub fn select_today(&self, seed: &[u8]) -> &Pronoun {
self.select_on_date(
seed,
OffsetDateTime::now_local()
.unwrap_or_else(|_| OffsetDateTime::now_utc())
.date()
)
}
/// Randomly select a pronoun set for a given date and name.
///
/// Is a wrapper for calling [`WeightedTable::select`] with the given date mixed into the seed.
pub fn select_on_date(&self, seed: &[u8], date: Date) -> &Pronoun {
let mut new_seed: Vec<u8> = Vec::with_capacity(seed.len() + 4);
new_seed.extend(
(
(date - COVID_EPOCH)
.whole_days()
as u32
).to_le_bytes()
);
new_seed.extend(seed);
self.select(seed.as_ref())
}
/// Randomly select a pronoun set for a given seed
///
/// This function is *pure*, and any randomness is produced internally using PRNG seeded with
/// the given date and seed. That is to say, for any given seed, this table must always
/// produce the same pronoun set.
pub fn select(&self, seed: &[u8]) -> &Pronoun {
todo!()
}
}