2021-10-21 18:37:37 +00:00
|
|
|
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> {
|
|
|
|
|
2021-10-21 18:38:37 +00:00
|
|
|
/// A shorthand for calling [`WeightedTable::select_on_date()`] with today's date
|
2021-10-21 18:37:37 +00:00
|
|
|
///
|
|
|
|
/// 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.
|
|
|
|
///
|
2021-10-21 18:38:37 +00:00
|
|
|
/// Is a wrapper for calling [`WeightedTable::select`] with the given date mixed into the seed.
|
2021-10-21 18:37:37 +00:00
|
|
|
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!()
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|