photonic 0.1.1

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

use anyhow::Result;
use async_trait::async_trait;
use palette::rgb::Rgb;
use palette::{FromColor, IntoColor};

use crate::{BufferReader, Output, OutputDecl};

use super::Boxed;

#[async_trait(?Send)]
pub trait DynOutputDecl {
    async fn materialize(self: Box<Self>) -> Result<BoxedOutput>;
}

#[async_trait(?Send)]
impl<T> DynOutputDecl for T
where
    T: OutputDecl + 'static,
    <<T as OutputDecl>::Output as Output>::Element: Copy + FromColor<Rgb>,
{
    async fn materialize(self: Box<Self>) -> Result<BoxedOutput> {
        let output = <T as OutputDecl>::materialize(*self).await?;
        return Ok(Box::new(output));
    }
}

impl<T> Boxed<dyn DynOutputDecl> for T
where
    T: OutputDecl + 'static,
    <T as OutputDecl>::Output: Sized + 'static,
    <<T as OutputDecl>::Output as Output>::Element: Copy + FromColor<Rgb>,
{
    fn boxed(self) -> Box<dyn DynOutputDecl> {
        return Box::new(self);
    }
}

pub type BoxedOutputDecl = Box<dyn DynOutputDecl>;

impl OutputDecl for BoxedOutputDecl {
    const KIND: &'static str = "boxed";

    type Output = BoxedOutput;

    fn materialize(self) -> impl Future<Output = Result<Self::Output>> {
        return DynOutputDecl::materialize(self);
    }
}

#[async_trait(?Send)]
pub trait DynOutput {
    async fn render(&mut self, out: &dyn BufferReader<Element = Rgb>) -> Result<()>;

    fn size(&self) -> usize;
}

#[async_trait(?Send)]
impl<T> DynOutput for T
where
    T: Output,
    <T as Output>::Element: Copy + FromColor<Rgb>,
{
    async fn render(&mut self, out: &dyn BufferReader<Element = Rgb>) -> Result<()> {
        return Output::render(self, OutputBuffer::wrap(out)).await;
    }

    fn size(&self) -> usize {
        return Output::size(self);
    }
}

pub type BoxedOutput = Box<dyn DynOutput>;

impl Output for BoxedOutput {
    const KIND: &'static str = todo!();

    type Element = Rgb;

    async fn render(&mut self, out: impl BufferReader<Element = Self::Element>) -> Result<()> {
        return DynOutput::render(self.as_mut(), &out).await;
    }

    fn size(&self) -> usize {
        return DynOutput::size(self.as_ref());
    }
}

struct OutputBuffer<'a, E> {
    buffer: &'a dyn BufferReader<Element = Rgb>,
    phantom: PhantomData<E>,
}

impl<'a, E> OutputBuffer<'a, E> {
    pub fn wrap(buffer: &'a dyn BufferReader<Element = Rgb>) -> Self {
        return Self {
            buffer,
            phantom: PhantomData,
        };
    }
}

impl<E> BufferReader for OutputBuffer<'_, E>
where E: Copy + FromColor<Rgb>
{
    type Element = E;

    fn get(&self, index: usize) -> Self::Element {
        return self.buffer.get(index).into_color();
    }

    fn size(&self) -> usize {
        return self.buffer.size();
    }
}