use std::marker::PhantomData;
use crate::prelude::*;
use crate::{Limit, Prng};
pub struct FnBuilder<I, O, IC, OD> {
input_codie: IC,
output_die: OD,
prng: Prng,
limit: Limit,
_i: PhantomData<I>,
_o: PhantomData<O>,
}
impl<I, O, IC, OD> FnBuilder<I, O, IC, OD>
where
IC: Codie<I>,
OD: DieOnce<O>,
{
pub fn build_fn_once(mut self) -> impl FnOnce(I) -> O {
move |input| {
let output_die = self.output_die;
let randomness = self.input_codie.coroll(input);
let prng = &mut self.prng;
prng.reseed(randomness);
let limit = self.limit;
let fate = Fate::new(prng, limit);
output_die.roll_once(fate)
}
}
}
impl<I, O, IC, OD> FnBuilder<I, O, IC, OD>
where
IC: Codie<I>,
OD: Die<O>,
{
pub fn build_fn(self) -> impl Fn(I) -> O {
move |input| {
let output_die = &self.output_die;
let randomness = self.input_codie.coroll(input);
let prng = &mut self.prng.clone();
prng.reseed(randomness);
let limit = self.limit;
let fate = Fate::new(prng, limit);
output_die.roll(fate)
}
}
pub fn build_fn_mut(mut self) -> impl FnMut(I) -> O {
move |input| {
let output_die = &self.output_die;
let randomness = self.input_codie.coroll(input);
let prng = &mut self.prng;
prng.reseed(randomness);
let limit = self.limit;
let fate = Fate::new(prng, limit);
output_die.roll(fate)
}
}
}
pub fn fn_builder<I, O, IC, OD>(
input_codie: IC,
output_die: OD,
) -> impl DieOnce<FnBuilder<I, O, IC, OD>>
where
IC: Codie<I>,
OD: DieOnce<O>,
{
dice::from_fn_once(|mut fate| FnBuilder {
input_codie,
output_die,
prng: fate.fork_prng(),
limit: fate.limit(),
_i: PhantomData,
_o: PhantomData,
})
}