photonic 0.1.1

Dynamic light controller and animator
Documentation
use std::marker::PhantomData;

use anyhow::Result;
use async_trait::async_trait;
use palette::convert::{FromColorUnclamped, IntoColorUnclamped};

use crate::{Buffer, BufferReader, Node, NodeBuilder, NodeDecl, RenderContext};

use super::Boxed;

#[async_trait(? Send)]
pub trait DynNodeDecl<E> {
    async fn materialize(self: Box<Self>, builder: &mut NodeBuilder<'_>) -> Result<BoxedNode<E>>;
}

#[async_trait(? Send)]
impl<T, E> DynNodeDecl<E> for T
where
    T: NodeDecl + 'static,
    E: Default + Copy + FromColorUnclamped<<<T as NodeDecl>::Node as Node>::Element> + 'static,
{
    async fn materialize(self: Box<Self>, builder: &mut NodeBuilder<'_>) -> Result<BoxedNode<E>> {
        let node = <T as NodeDecl>::materialize(*self, builder).await?;
        let node = WrappedNode {
            node,
            buffer: Buffer::with_default(builder.size),
            target: PhantomData,
        };

        return Ok(Box::new(node));
    }
}

impl<T, E> Boxed<dyn DynNodeDecl<E>> for T
where
    T: NodeDecl + 'static,
    E: Default + Copy + FromColorUnclamped<<<T as NodeDecl>::Node as Node>::Element> + 'static,
{
    fn boxed(self) -> Box<dyn DynNodeDecl<E>> {
        return Box::new(self);
    }
}

pub type BoxedNodeDecl<E> = Box<dyn DynNodeDecl<E>>;

impl<E> NodeDecl for BoxedNodeDecl<E>
where E: Default + Copy
{
    const KIND: &'static str = "boxed";

    type Node = BoxedNode<E>;

    async fn materialize(self, builder: &mut NodeBuilder<'_>) -> Result<Self::Node> {
        return DynNodeDecl::materialize(self, builder).await;
    }
}

struct WrappedNode<N, E>
where
    N: Node,
    E: Default + Copy + FromColorUnclamped<<N as Node>::Element>,
{
    node: N,
    buffer: Buffer<<N as Node>::Element>,
    target: PhantomData<E>,
}

impl<N, E> Node for WrappedNode<N, E>
where
    N: Node,
    E: Default + Copy + FromColorUnclamped<<N as Node>::Element>,
{
    type Element = E;

    fn update(&mut self, ctx: &RenderContext, out: &mut Buffer<Self::Element>) -> Result<()> {
        self.node.update(ctx, &mut self.buffer)?;

        out.blit_from(self.buffer.map(|e| e.into_color_unclamped()));
        return Ok(());
    }
}

pub trait DynNode<E> {
    fn update(&mut self, ctx: &RenderContext, out: &mut Buffer<E>) -> Result<()>;
}

impl<N, E> DynNode<E> for WrappedNode<N, E>
where
    N: Node,
    E: Default + Copy + FromColorUnclamped<<N as Node>::Element>,
{
    fn update(&mut self, ctx: &RenderContext, out: &mut Buffer<E>) -> Result<()> {
        return Node::update(self, ctx, out);
    }
}

pub type BoxedNode<E> = Box<dyn DynNode<E>>;

impl<E> Node for BoxedNode<E>
where E: Default + Copy
{
    type Element = E;

    fn update(&mut self, ctx: &RenderContext, out: &mut Buffer<Self::Element>) -> Result<()> {
        return DynNode::update(self.as_mut(), ctx, out);
    }
}