kahlo 0.0.3

Optimized software rendering library.
Documentation
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>>;
}