photonic_output_split/
lib.rs1use 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}