use rand::SeedableRng;
use std::collections::HashMap;
pub trait ContextValueTag: 'static {
type Value: Clone;
}
#[derive(Debug)]
pub struct Context {
values: HashMap<std::any::TypeId, Box<dyn std::any::Any>>,
rng: rand_chacha::ChaCha12Rng,
}
impl Context {
pub fn new(seed: usize) -> Self {
Self {
values: Default::default(),
rng: rand_chacha::ChaCha12Rng::seed_from_u64(seed as u64),
}
}
}
impl Context {
pub fn insert<CVT: ContextValueTag>(&mut self, value: CVT::Value) {
self.values.insert(
std::any::TypeId::of::<CVT>(),
Box::new(value) as Box<dyn std::any::Any>,
);
}
pub fn lookup<CVT: ContextValueTag>(&self) -> Option<&CVT::Value> {
let stored = self.values.get(&std::any::TypeId::of::<CVT>())?;
stored.downcast_ref::<CVT::Value>()
}
pub fn rng(&mut self) -> &mut dyn rand::Rng {
&mut self.rng
}
}
pub trait ValueGenerator<'l>: for<'a> Fn(&'a mut Context) -> Option<Self::Value> {
type Value: 'l + Clone;
}
impl<'l, V: 'l + Clone, F: for<'a> Fn(&'a mut Context) -> Option<V>> ValueGenerator<'l> for F {
type Value = V;
}
mod impls;
pub use impls::*;
pub trait ValueGeneratorList<'l> {
type OutputTuple: 'l;
fn generate(&self, ctx: &mut Context) -> Option<Self::OutputTuple>;
}
impl<'l> ValueGeneratorList<'l> for () {
type OutputTuple = ();
fn generate(&self, _ctx: &mut Context) -> Option<Self::OutputTuple> {
Some(())
}
}
impl<'l, V0: ValueGenerator<'l>> ValueGeneratorList<'l> for (V0,) {
type OutputTuple = (V0::Value,);
fn generate(&self, ctx: &mut Context) -> Option<Self::OutputTuple> {
Some((self.0(ctx)?,))
}
}
impl<'l, V0: ValueGenerator<'l>, V1: ValueGenerator<'l>> ValueGeneratorList<'l> for (V0, V1) {
type OutputTuple = (V0::Value, V1::Value);
fn generate(&self, ctx: &mut Context) -> Option<Self::OutputTuple> {
Some((self.0(ctx)?, self.1(ctx)?))
}
}
impl<'l, V0: ValueGenerator<'l>, V1: ValueGenerator<'l>, V2: ValueGenerator<'l>>
ValueGeneratorList<'l> for (V0, V1, V2)
{
type OutputTuple = (V0::Value, V1::Value, V2::Value);
fn generate(&self, ctx: &mut Context) -> Option<Self::OutputTuple> {
Some((self.0(ctx)?, self.1(ctx)?, self.2(ctx)?))
}
}
impl<
'l,
V0: ValueGenerator<'l>,
V1: ValueGenerator<'l>,
V2: ValueGenerator<'l>,
V3: ValueGenerator<'l>,
> ValueGeneratorList<'l> for (V0, V1, V2, V3)
{
type OutputTuple = (V0::Value, V1::Value, V2::Value, V3::Value);
fn generate(&self, ctx: &mut Context) -> Option<Self::OutputTuple> {
Some((self.0(ctx)?, self.1(ctx)?, self.2(ctx)?, self.3(ctx)?))
}
}
impl<
'l,
V0: ValueGenerator<'l>,
V1: ValueGenerator<'l>,
V2: ValueGenerator<'l>,
V3: ValueGenerator<'l>,
V4: ValueGenerator<'l>,
> ValueGeneratorList<'l> for (V0, V1, V2, V3, V4)
{
type OutputTuple = (V0::Value, V1::Value, V2::Value, V3::Value, V4::Value);
fn generate(&self, ctx: &mut Context) -> Option<Self::OutputTuple> {
Some((
self.0(ctx)?,
self.1(ctx)?,
self.2(ctx)?,
self.3(ctx)?,
self.4(ctx)?,
))
}
}
pub trait UnaryInputSpec: super::UnaryOpSpec {
fn gen<'l>() -> impl ValueGeneratorList<'l, OutputTuple = Self::Params<'l>>;
}
pub trait BinaryInputSpec: super::BinaryOpSpec {
fn gen<'l>() -> impl ValueGeneratorList<'l, OutputTuple = Self::Params<'l>>;
}