use serde::Deserialize;
#[derive(Clone, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum Strategy {
FirstMatch,
UniformRandom {
#[serde(default)]
seed: Option<u64>,
},
WeightedRandom {
#[serde(default)]
seed: Option<u64>,
},
Priority {
#[serde(default)]
tiebreaker: PriorityTiebreaker,
},
}
#[derive(Clone, Deserialize, Debug, Default)]
#[serde(rename_all = "snake_case")]
pub enum PriorityTiebreaker {
#[default]
FirstMatch,
UniformRandom,
}
impl Default for Strategy {
fn default() -> Self {
Self::FirstMatch
}
}
impl std::fmt::Display for Strategy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::FirstMatch => write!(f, "first_match"),
Self::UniformRandom { .. } => write!(f, "uniform_random"),
Self::WeightedRandom { .. } => write!(f, "weighted_random"),
Self::Priority { .. } => write!(f, "priority"),
}
}
}
pub struct Xorshift64(u64);
impl Xorshift64 {
pub fn new(seed: u64) -> Self {
Self(if seed == 0 { 0xdeadbeef_cafebabe } else { seed })
}
pub fn next(&mut self) -> u64 {
let mut x = self.0;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
self.0 = x;
x
}
pub fn next_index(&mut self, len: usize) -> usize {
(self.next() % len as u64) as usize
}
}
pub fn make_rng(seed: Option<u64>) -> Xorshift64 {
let s = seed.unwrap_or_else(|| {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_nanos() as u64)
.unwrap_or(0xc0ffee)
});
Xorshift64::new(s)
}