photonic 0.1.1

Dynamic light controller and animator
Documentation
use anyhow::Result;

use crate::attr::{Attr, AttrValue, Bounded, Bounds};
use crate::decl::{BoundAttrDecl, FreeAttrDecl};
use crate::input::{Input, InputValue, Poll};
use crate::scene::{AttrBuilder, InputHandle};
use crate::{input, scene};

#[derive(Debug)]
pub struct InputAttrDecl<A>
where A: AttrValue + input::Coerced
{
    input: InputHandle<A::Input>,
    initial: A,
}

impl<A> BoundAttrDecl<A> for InputAttrDecl<A>
where A: AttrValue + input::Coerced + Bounded
{
    const KIND: &'static str = "input";

    type Attr = BoundInputAttr<A>;

    fn materialize(self, bounds: Bounds<A>, builder: &mut AttrBuilder) -> Result<Self::Attr> {
        let initial = bounds.ensure(self.initial)?;

        let input = builder.input("value", self.input)?;

        return Ok(Self::Attr {
            bounds,
            input,
            current: initial,
        });
    }
}

impl<A> FreeAttrDecl<A> for InputAttrDecl<A>
where A: AttrValue + input::Coerced
{
    const KIND: &'static str = "input";

    type Attr = FreeInputAttr<A>;

    fn materialize(self, builder: &mut AttrBuilder) -> Result<Self::Attr> {
        let input = builder.input("value", self.input)?;

        return Ok(Self::Attr {
            input,
            current: self.initial,
        });
    }
}

#[derive(Debug)]
pub struct BoundInputAttr<A>
where A: AttrValue + input::Coerced + Bounded
{
    input: Input<A::Input>,
    current: A,

    bounds: Bounds<A>,
}

impl<A> Attr<A> for BoundInputAttr<A>
where A: AttrValue + input::Coerced + Bounded
{
    fn update(&mut self, _ctx: &scene::RenderContext) -> A {
        if let Poll::Update(update) = self.input.poll(|value| {
            let value = A::try_from_input(value)?;
            let value = self.bounds.ensure(value)?;
            return anyhow::Ok(value);
        }) {
            self.current = update;
        }

        return self.current;
    }
}

#[derive(Debug)]
pub struct FreeInputAttr<A>
where A: AttrValue + input::Coerced
{
    input: Input<A::Input>,
    current: A,
}

impl<A> Attr<A> for FreeInputAttr<A>
where A: AttrValue + input::Coerced
{
    fn update(&mut self, _ctx: &scene::RenderContext) -> A {
        if let Poll::Update(update) = self.input.poll(A::try_from_input) {
            self.current = update;
        }

        return self.current;
    }
}

impl<I> InputHandle<I>
where I: InputValue
{
    pub fn attr<A>(self, initial: A) -> InputAttrDecl<A>
    where A: AttrValue + input::Coerced<Input = I> {
        return InputAttrDecl {
            input: self,
            initial,
        };
    }
}