use super::super::rand::R;
use super::base::{BoxGenerator, Generator};
use std::sync::Arc;
#[derive(Clone)]
pub struct OneOf<T> {
data: Box<[T]>,
}
impl<T: Clone> Generator for OneOf<T> {
type Item = T;
fn generate(&self, r: &mut R) -> Self::Item {
let nb = r.num_range(0, self.data.len() - 1);
self.data[nb].clone()
}
}
#[derive(Clone)]
pub struct Choose<T> {
generators: Arc<Box<[Box<dyn Generator<Item = T>>]>>,
}
impl<T> Choose<T> {
fn new(vec: Vec<Box<dyn Generator<Item = T>>>) -> Self {
assert!(!vec.is_empty());
Choose {
generators: Arc::new(vec.into()),
}
}
}
impl<T> Generator for Choose<T> {
type Item = T;
fn generate(&self, r: &mut R) -> Self::Item {
let nb = r.num_range(0, self.generators.len() - 1);
(self.generators[nb]).generate(&mut r.sub())
}
}
#[derive(Clone)]
pub struct Frequency<T> {
frequencies: Box<[usize]>,
generators: Arc<Box<[WeightedBoxGenerator<T>]>>,
}
type WeightedBoxGenerator<T> = (usize, BoxGenerator<T>);
impl<T> Frequency<T> {
fn new(gens: Vec<(usize, BoxGenerator<T>)>) -> Self {
let total: usize = gens.iter().map(|x| x.0).sum();
let mut frequencies = Vec::with_capacity(total);
for (i, (nb, _)) in gens.iter().enumerate() {
for _ in 0..*nb {
frequencies.push(i)
}
}
Frequency {
frequencies: frequencies.into(),
generators: Arc::new(gens.into()),
}
}
}
impl<T> Generator for Frequency<T> {
type Item = T;
fn generate(&self, r: &mut R) -> Self::Item {
let nb = r.num_range(0, self.frequencies.len() - 1);
let idx = self.frequencies[nb];
(&self.generators[idx].1).generate(&mut r.sub())
}
}
pub fn one_of<T: Clone>(slice: &[T]) -> OneOf<T> {
let copied: Vec<_> = slice.to_vec();
OneOf {
data: copied.into_boxed_slice(),
}
}
pub fn choose<T>(gens: Vec<Box<dyn Generator<Item = T>>>) -> Choose<T> {
assert!(!gens.is_empty());
Choose::new(gens)
}
pub fn frequency<T>(gens: Vec<(usize, Box<dyn Generator<Item = T>>)>) -> Frequency<T> {
assert!(!gens.is_empty());
let mut frequencies_gen = Vec::new();
for (freq, generator) in gens.into_iter() {
frequencies_gen.push((freq, BoxGenerator(generator)))
}
Frequency::new(frequencies_gen)
}