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 = 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!() } }