photonic_output_split/
lib.rs

1use anyhow::Result;
2use palette::rgb::Rgb;
3
4use photonic::boxed::{BoxedOutput, BoxedOutputDecl};
5use photonic::{BufferReader, Output, OutputDecl};
6
7#[derive(Default)]
8pub struct Split {
9    outputs: Vec<BoxedOutputDecl>,
10}
11
12impl Split {
13    pub fn new(outputs: Vec<BoxedOutputDecl>) -> Self {
14        return Self {
15            outputs,
16        };
17    }
18}
19
20impl OutputDecl for Split {
21    const KIND: &'static str = "split";
22    type Output = SplitOutput;
23
24    async fn materialize(self) -> Result<Self::Output>
25    where Self::Output: Sized {
26        let mut size = 0usize;
27
28        let mut outputs = Vec::new();
29        for output in self.outputs {
30            let output = output.materialize().await?;
31            let offset = size;
32
33            size += output.size();
34
35            outputs.push((offset, output));
36        }
37
38        return Ok(Self::Output {
39            size,
40            outputs,
41        });
42    }
43}
44
45pub struct SplitOutput {
46    size: usize,
47    outputs: Vec<(usize, BoxedOutput)>,
48}
49
50impl Output for SplitOutput {
51    const KIND: &'static str = "null";
52
53    type Element = Rgb;
54
55    async fn render(&mut self, buf: impl BufferReader<Element = Self::Element>) -> Result<()> {
56        for (offset, output) in self.outputs.iter_mut() {
57            let range = (*offset)..(*offset + output.size());
58            output.render(buf.slice(range)).await?;
59        }
60
61        return Ok(());
62    }
63
64    fn size(&self) -> usize {
65        return self.size;
66    }
67}
68
69#[cfg(feature = "dynamic")]
70pub mod dynamic {
71    use anyhow::Result;
72    use serde::Deserialize;
73
74    use photonic::boxed::{Boxed, DynOutputDecl};
75    use photonic_dynamic::config::Output;
76    use photonic_dynamic::factory::{factory, OutputFactory, Producible};
77    use photonic_dynamic::{builder, registry};
78
79    use crate::Split;
80
81    #[derive(Deserialize)]
82    pub struct Config {
83        outputs: Vec<Output>,
84    }
85
86    impl Producible<dyn DynOutputDecl> for Config {
87        type Product = Split;
88
89        fn produce<Reg: registry::Registry>(
90            config: Self,
91            mut builder: builder::OutputBuilder<'_, Reg>,
92        ) -> Result<Self::Product> {
93            let outputs = config
94                .outputs
95                .into_iter()
96                .map(|config| anyhow::Ok(builder.output(config)?.boxed()))
97                .collect::<Result<Vec<_>>>()?;
98
99            return Ok(Split {
100                outputs,
101            });
102        }
103    }
104
105    pub struct Registry;
106
107    impl registry::Registry for Registry {
108        fn output<Reg: registry::Registry>(kind: &str) -> Option<OutputFactory<Reg>> {
109            return match kind {
110                "split" => Some(factory::<Config>()),
111                _ => return None,
112            };
113        }
114    }
115}