From af3d4643f19056d21a2628c579a1da6d331878c8 Mon Sep 17 00:00:00 2001 From: Dustin Frisch Date: Wed, 21 Feb 2024 23:37:28 +0100 Subject: [PATCH] core: size propagation --- core/src/decl.rs | 2 +- core/src/output.rs | 2 + core/src/scene.rs | 121 +++++++++++++-------------- dyn/src/boxed/output.rs | 20 +++-- dyn/src/builder.rs | 4 +- effects/src/nodes.rs | 23 ++--- effects/src/nodes/larson.rs | 2 +- effects/src/nodes/splice.rs | 88 +++++++++++++++++++ examples/examples/maglab-dmx-demo.rs | 37 ++++++-- output-net/src/netdmx.rs | 23 +++-- output-net/src/wled.rs | 15 +++- output-null/src/lib.rs | 15 +++- output-terminal/src/lib.rs | 31 ++++--- 13 files changed, 267 insertions(+), 116 deletions(-) create mode 100644 effects/src/nodes/splice.rs diff --git a/core/src/decl.rs b/core/src/decl.rs index be0d756..b493f0b 100644 --- a/core/src/decl.rs +++ b/core/src/decl.rs @@ -13,7 +13,7 @@ pub trait NodeDecl { pub trait OutputDecl { type Output: Output; - fn materialize(self, size: usize) -> impl Future>; + fn materialize(self) -> impl Future>; } pub trait FreeAttrDecl { diff --git a/core/src/output.rs b/core/src/output.rs index c4c7334..7a80e72 100644 --- a/core/src/output.rs +++ b/core/src/output.rs @@ -9,4 +9,6 @@ pub trait Output: Sized { type Element; fn render(&mut self, out: impl BufferReader) -> impl Future>; + + fn size(&self) -> usize; } diff --git a/core/src/scene.rs b/core/src/scene.rs index c553112..07205d2 100644 --- a/core/src/scene.rs +++ b/core/src/scene.rs @@ -31,9 +31,9 @@ struct NodeBufferReader<'b, E, O> { } impl<'b, E, O> BufferReader for NodeBufferReader<'b, E, O> -where - E: Copy, - O: Copy + From, + where + E: Copy, + O: Copy + From, { type Element = O; @@ -47,7 +47,7 @@ where } impl<'ctx, Node> ops::Index> for Context<'ctx> -where Node: self::Node + where Node: self::Node { type Output = NodeContainer; @@ -57,7 +57,7 @@ where Node: self::Node } pub struct NodeHandle -where Decl: NodeDecl + where Decl: NodeDecl { /// The scene-wide unique name of the node pub name: String, @@ -67,14 +67,14 @@ where Decl: NodeDecl } pub struct NodeContainer -where Node: self::Node + where Node: self::Node { node: Node, buffer: Buffer, } impl NodeContainer -where Node: self::Node + where Node: self::Node { pub fn build(builder: &NodeBuilder, node: Node) -> Result { let buffer = Buffer::with_default(builder.size); @@ -87,7 +87,7 @@ where Node: self::Node } impl BufferReader for NodeContainer -where Node: self::Node + where Node: self::Node { type Element = Node::Element; @@ -101,7 +101,7 @@ where Node: self::Node } impl BufferReader for &NodeContainer -where Node: self::Node + where Node: self::Node { type Element = Node::Element; @@ -119,7 +119,7 @@ trait NodeHolder { } impl NodeHolder for NodeContainer -where Node: self::Node + where Node: self::Node { fn update(&mut self, ctx: &Context) -> Result<()> { return self.node.update(ctx, &mut self.buffer); @@ -127,13 +127,13 @@ where Node: self::Node } pub struct NodeRef -where Node: self::Node + 'static // TODO: Is static required? + where Node: self::Node + 'static // TODO: Is static required? { node: Ref, dyn NodeHolder>, } impl Clone for NodeRef -where Node: self::Node + where Node: self::Node { fn clone(&self) -> Self { return Self { @@ -149,7 +149,7 @@ impl Copy for NodeRef where Node: self::Node {} /// The handle represents a input registered in a [`Scene'] and can be used to get the real thing /// while manifesting the scene. pub struct InputHandle -where V: InputValue + where V: InputValue { /// The scene-wide unique name of the input pub name: String, @@ -158,7 +158,7 @@ where V: InputValue } impl InputHandle -where V: InputValue + where V: InputValue { /// Returns a sink into the input represented by this handle. pub fn sink(&self) -> InputSink { @@ -169,23 +169,12 @@ where V: InputValue /// Declaration of a scene. /// /// This is used to declare nodes, attributes and inputs. -pub struct Scene { - size: usize, -} +pub struct Scene {} impl Scene { /// Create a new scene with a given size. - /// - /// The size represents the number of lights in the scene. - pub fn new(size: usize) -> Self { - return Self { - size, - }; - } - - /// Returns the size of the scene. - pub fn size(&self) -> usize { - return self.size; + pub fn new() -> Self { + return Self {}; } /// Declares a new node in the scene. @@ -195,7 +184,7 @@ impl Scene { /// The returned handle represents the node in the scene and can be used to reference the node /// in another node. pub fn node(&mut self, name: &str, decl: Decl) -> Result> - where Decl: NodeDecl { + where Decl: NodeDecl { return Ok(NodeHandle { name: name.to_owned(), decl, @@ -209,7 +198,7 @@ impl Scene { /// The returned handle represents the input in the scene and can be used to reference the input /// in other nodes and attributes. pub fn input(&mut self, name: &str) -> Result> - where V: InputValue { + where V: InputValue { return Ok(InputHandle { name: name.to_owned(), input: Input::new(), @@ -230,14 +219,16 @@ impl Scene { root: NodeHandle, decl: Output, ) -> Result> - where - Node: NodeDecl, - Output: OutputDecl, - ::Element: FromColor<::Element>, - <::Node as self::Node>::Element: Default, // TODO: Remove this constraint + where + Node: NodeDecl, + Output: OutputDecl, + ::Element: FromColor<::Element>, + <::Node as self::Node>::Element: Default, // TODO: Remove this constraint { + let output = decl.materialize().await?; + // Materialize the node tree using a builder tracking the info object creation - let (scene, root) = SceneBuilder::build(self.size, root).await?; + let (scene, root) = SceneBuilder::build(output.size(), root).await?; let introspection = Introspection::with(scene.root); introspection.log(); @@ -245,7 +236,7 @@ impl Scene { return Ok(Loop { nodes: scene.nodes, root, - output: decl.materialize(self.size()).await?, + output, stats: FrameStats::default(), introspection, }); @@ -257,10 +248,10 @@ impl Scene { /// The rendering loop updates a scene and all its elements and then renders the root node to the /// output. pub struct Loop -where - Node: self::Node + 'static, // TODO: Is static required? - Output: self::Output, - Output::Element: FromColor, + where + Node: self::Node + 'static, // TODO: Is static required? + Output: self::Output, + Output::Element: FromColor, { nodes: Arena, @@ -273,10 +264,10 @@ where } impl<'a, Node, Output> Loop -where - Node: self::Node + 'static, - Output: self::Output, - Output::Element: FromColor + Copy, + where + Node: self::Node + 'static, + Output: self::Output, + Output::Element: FromColor + Copy, { /// Update and render a single frame. /// @@ -322,7 +313,7 @@ where } } - pub fn serve(&self, interface: impl Interface) -> impl Future> { + pub fn serve(&self, interface: impl Interface) -> impl Future> { return interface.listen(self.introspection.clone()); } } @@ -371,9 +362,9 @@ pub struct AttrBuilder<'b> { impl SceneBuilder { /// Create a node from its handle. pub async fn build(size: usize, root: NodeHandle) -> Result<(Self, NodeRef)> - where - Node: NodeDecl, - <::Node as self::Node>::Element: Default, // TODO: Remove this constraint + where + Node: NodeDecl, + <::Node as self::Node>::Element: Default, // TODO: Remove this constraint { let mut nodes = Arena::new(); @@ -417,12 +408,20 @@ impl SceneBuilder { impl NodeBuilder<'_> { pub async fn node(&mut self, key: impl Into, decl: NodeHandle) -> Result> - where - Node: NodeDecl, - <::Node as self::Node>::Element: Default, // TODO: Remove this constraint + where + Node: NodeDecl, + <::Node as self::Node>::Element: Default, // TODO: Remove this constraint + { + return self.node_with_size(key, decl, self.size).await; + } + + pub async fn node_with_size(&mut self, key: impl Into, decl: NodeHandle, size: usize) -> Result> + where + Node: NodeDecl, + <::Node as self::Node>::Element: Default, // TODO: Remove this constraint { let mut builder = NodeBuilder { - size: self.size, + size, nodes: &mut self.nodes, @@ -437,7 +436,7 @@ impl NodeBuilder<'_> { let node = Node::materialize(decl.decl, &mut builder).await?; let info = builder.info; - let buffer = Buffer::with_default(self.size); + let buffer = Buffer::with_default(size); let node = self.nodes.append(NodeContainer { node, @@ -462,8 +461,8 @@ impl NodeBuilder<'_> { decl: Attr, bounds: impl Into>, ) -> Result - where - Attr: BoundAttrDecl, + where + Attr: BoundAttrDecl, { let bounds = bounds.into(); @@ -491,7 +490,7 @@ impl NodeBuilder<'_> { /// The created attribute is registered as an attribute to the currently built node. // TODO: Rename to `free_attr` pub fn unbound_attr(&mut self, name: impl Into, decl: Attr) -> Result - where Attr: FreeAttrDecl { + where Attr: FreeAttrDecl { let mut builder = AttrBuilder { nodes: self.nodes, size: self.size, @@ -522,8 +521,8 @@ impl<'b> AttrBuilder<'b> { decl: Attr, bounds: impl Into>, ) -> Result - where - Attr: BoundAttrDecl, + where + Attr: BoundAttrDecl, { let bounds = bounds.into(); @@ -550,7 +549,7 @@ impl<'b> AttrBuilder<'b> { /// /// The created attribute is registered as an attribute to the currently built node. pub fn unbound_attr(&mut self, name: impl Into, decl: Attr) -> Result - where Attr: FreeAttrDecl { + where Attr: FreeAttrDecl { let mut builder = AttrBuilder { nodes: self.nodes, size: self.size, @@ -574,7 +573,7 @@ impl<'b> AttrBuilder<'b> { /// /// The created input is registered as an input to the currently built node. pub fn input(&mut self, name: impl Into, input: InputHandle) -> Result> - where V: InputValue { + where V: InputValue { let sink = input.sink(); let info = InputInfo { diff --git a/dyn/src/boxed/output.rs b/dyn/src/boxed/output.rs index 22097e5..8ccbc09 100644 --- a/dyn/src/boxed/output.rs +++ b/dyn/src/boxed/output.rs @@ -10,7 +10,7 @@ use photonic::{BufferReader, Output, OutputDecl}; #[async_trait(? Send)] pub trait DynOutputDecl { - async fn materialize(self: Box, size: usize) -> Result; + async fn materialize(self: Box) -> Result; } #[async_trait(? Send)] @@ -19,8 +19,8 @@ where T: OutputDecl + 'static, <::Output as Output>::Element: Copy + FromColor, { - async fn materialize(self: Box, size: usize) -> Result { - let output = ::materialize(*self, size).await?; + async fn materialize(self: Box) -> Result { + let output = ::materialize(*self).await?; return Ok(Box::new(output) as Box); } } @@ -30,14 +30,16 @@ pub type BoxedOutputDecl = Box; impl OutputDecl for BoxedOutputDecl { type Output = BoxedOutput; - fn materialize(self, size: usize) -> impl Future> { - return DynOutputDecl::materialize(self, size); + fn materialize(self) -> impl Future> { + return DynOutputDecl::materialize(self); } } #[async_trait(? Send)] pub trait DynOutput { async fn render(&mut self, out: &dyn BufferReader) -> Result<()>; + + fn size(&self) -> usize; } #[async_trait(? Send)] @@ -49,6 +51,10 @@ where async fn render(&mut self, out: &dyn BufferReader) -> Result<()> { return Output::render(self, OutputBuffer::wrap(out)).await; } + + fn size(&self) -> usize { + return Output::size(self); + } } pub type BoxedOutput = Box; @@ -61,6 +67,10 @@ impl Output for BoxedOutput { async fn render(&mut self, out: impl BufferReader) -> Result<()> { return DynOutput::render(self.as_mut(), &out).await; } + + fn size(&self) -> usize { + return DynOutput::size(self.as_ref()); + } } struct OutputBuffer<'a, E> { diff --git a/dyn/src/builder.rs b/dyn/src/builder.rs index 6c83e1f..7e0e462 100644 --- a/dyn/src/builder.rs +++ b/dyn/src/builder.rs @@ -40,8 +40,8 @@ pub struct Builder { } impl Builder { - pub fn new(size: usize) -> Self { - let scene = Scene::new(size); + pub fn new() -> Self { + let scene = Scene::new(); return Self { scene, diff --git a/effects/src/nodes.rs b/effects/src/nodes.rs index f545aa3..635332e 100644 --- a/effects/src/nodes.rs +++ b/effects/src/nodes.rs @@ -1,3 +1,15 @@ +pub use alert::Alert; +pub use blackout::Blackout; +pub use brightness::Brightness; +pub use color_wheel::ColorWheel; +pub use larson::Larson; +pub use noise::Noise; +pub use overlay::Overlay; +pub use raindrops::Raindrops; +pub use solid::Solid; +pub use splice::Splice; +pub use switch::Switch; + mod brightness; mod color_wheel; @@ -12,14 +24,5 @@ mod larson; mod noise; mod solid; mod switch; +mod splice; -pub use alert::Alert; -pub use blackout::Blackout; -pub use brightness::Brightness; -pub use color_wheel::ColorWheel; -pub use larson::Larson; -pub use noise::Noise; -pub use overlay::Overlay; -pub use raindrops::Raindrops; -pub use solid::Solid; -pub use switch::Switch; diff --git a/effects/src/nodes/larson.rs b/effects/src/nodes/larson.rs index c71ba8f..c820d29 100644 --- a/effects/src/nodes/larson.rs +++ b/effects/src/nodes/larson.rs @@ -66,7 +66,7 @@ where let width = self.width.update(ctx.duration); let speed = self.speed.update(ctx.duration); - let size = out.size() as f32; + let size = (out.size() - 1) as f32; let delta = ctx.duration.as_secs_f32() * speed; match self.direction { diff --git a/effects/src/nodes/splice.rs b/effects/src/nodes/splice.rs new file mode 100644 index 0000000..50515ac --- /dev/null +++ b/effects/src/nodes/splice.rs @@ -0,0 +1,88 @@ +use anyhow::{bail, Result}; + +use photonic::{Buffer, BufferReader, Context, Node, NodeBuilder, NodeDecl, NodeHandle, NodeRef}; +use photonic_dyn::DynamicNode; + + +#[derive(DynamicNode)] +pub struct Splice + where + N1: NodeDecl, + N2: NodeDecl, +{ + pub n1: NodeHandle, + pub n2: NodeHandle, + + pub split: isize, +} + +pub struct SpliceNode + where N1: Node + 'static, + N2: Node + 'static, +{ + n1: NodeRef, + n2: NodeRef, +} + +fn calculate_split(split: isize, size: usize) -> Result { + let size = size as isize; + + if 0 <= split && split <= size { + return Ok(split as usize); + } + + if -size <= split && split <= 0 { + let split = size + split; + return Ok(split as usize); + } + + bail!("Splice split out of bounds: {} <= {} <= {}", -size, split, size); +} + +impl NodeDecl for Splice + where + N1: NodeDecl, + N2: NodeDecl, + ::Node: Node + 'static, + ::Node: Node + 'static, + E: Default + Copy, +{ + type Node = SpliceNode; + + async fn materialize(self, builder: &mut NodeBuilder<'_>) -> Result { + let split = calculate_split(self.split, builder.size)?; + + eprintln!("split={}, size={} > {}", self.split, builder.size, split); + + return Ok(Self::Node { + n1: builder.node_with_size("n1", self.n1, split).await?, + n2: builder.node_with_size("n2", self.n2, builder.size - split).await?, + }); + } +} + +impl Node for SpliceNode + where + N1: Node + 'static, + N2: Node + 'static, + E: Default + Copy, +{ + const KIND: &'static str = "splice"; + + type Element = E; + + fn update(&mut self, ctx: &Context, out: &mut Buffer) -> Result<()> { + let n1 = &ctx[self.n1]; + let n2 = &ctx[self.n2]; + + for i in 0..out.size() { + if i < n1.size() { + out[i] = n1.get(i); + } else { + out[i] = n2.get(i - n1.size()); + } + } + + return Ok(()); + } +} diff --git a/examples/examples/maglab-dmx-demo.rs b/examples/examples/maglab-dmx-demo.rs index d8dab10..32ecd07 100644 --- a/examples/examples/maglab-dmx-demo.rs +++ b/examples/examples/maglab-dmx-demo.rs @@ -7,13 +7,13 @@ use photonic::attr::{AsFixedAttr, Range}; use photonic::{Scene, WhiteMode}; use photonic_effects::attrs::{Button, Fader, Sequence}; use photonic_effects::easing::{EasingDirection, Easings}; -use photonic_effects::nodes::{Alert, Blackout, Brightness, ColorWheel, Noise, Overlay, Raindrops, Switch}; +use photonic_effects::nodes::{Alert, Blackout, Brightness, ColorWheel, Larson, Noise, Overlay, Raindrops, Splice, Switch}; use photonic_output_net::netdmx::{Channel, Fixture, NetDmxSender}; use photonic_output_terminal::Terminal; #[tokio::main] async fn main() -> Result<()> { - let mut scene = Scene::new(100); + let mut scene = Scene::new(); let input_next = scene.input("next")?; let input_prev = scene.input("prev")?; @@ -96,29 +96,52 @@ async fn main() -> Result<()> { range: Some(0..2), })?; + let larson1 = scene.node("larson1", Larson { + hue: 0.0.fixed(), + width: 4.0.fixed(), + speed: 1.0.fixed(), + })?; + + let larson2 = scene.node("larson2", Larson { + hue: 0.0.fixed(), + width: 4.0.fixed(), + speed: 1.0.fixed(), + })?; + + let larson = scene.node("larson", Splice { + n1: larson1, + n2: larson2, + split: 8, + })?; + + let splice = scene.node("larson_splice", Splice { + n1: kitchen, + n2: larson, + split: -16, + })?; + let output = NetDmxSender::with_address("127.0.0.1:34254".parse()?) .add_fixture(Fixture { - pixel: 0, dmx_address: 500, dmx_channels: vec![Channel::Red, Channel::Green, Channel::Blue, Channel::White], white_mode: WhiteMode::Accurate, }) .add_fixture(Fixture { - pixel: 1, dmx_address: 508, dmx_channels: vec![Channel::Red, Channel::Green, Channel::Blue, Channel::White], white_mode: WhiteMode::Accurate, }) .add_fixtures(20, |n| Fixture { - pixel: n + 2, dmx_address: 1 + n * 3, dmx_channels: vec![Channel::Red, Channel::Green, Channel::Blue], white_mode: WhiteMode::None, }); - let output = Terminal::with_path("/tmp/photonic").with_waterfall(true); + let output = Terminal::new(100) + .with_path("/tmp/photonic") + .with_waterfall(true); - let scene = scene.run(kitchen, output).await?; + let scene = scene.run(splice, output).await?; let cli = photonic_interface_cli::stdio::CLI; diff --git a/output-net/src/netdmx.rs b/output-net/src/netdmx.rs index 7958be3..e9c55b5 100644 --- a/output-net/src/netdmx.rs +++ b/output-net/src/netdmx.rs @@ -1,3 +1,4 @@ +use std::future::Future; use std::net::SocketAddr; use anyhow::{bail, Result}; @@ -14,8 +15,6 @@ pub enum Channel { } pub struct Fixture { - pub pixel: usize, - pub dmx_address: usize, pub dmx_channels: Vec, @@ -62,8 +61,9 @@ pub struct NetDmxSenderOutput { impl OutputDecl for NetDmxSender { type Output = NetDmxSenderOutput; - async fn materialize(self, size: usize) -> Result - where Self::Output: Sized { + async fn materialize(self) -> Result + where Self::Output: Sized, + { let socket = tokio::net::UdpSocket::bind("127.0.0.0:0").await?; for fixture in &self.fixtures { @@ -72,11 +72,6 @@ impl OutputDecl for NetDmxSender { if addresses.0 < 1 || addresses.1 > 512 { bail!("Invalid fixture address {}:{}", addresses.0, addresses.1); } - - // Check fixtures pixel is in bounds - if fixture.pixel >= size { - bail!("Fixture pixel out of bounds: {} >= {}", fixture.pixel, size); - } } return Ok(Self::Output { @@ -93,9 +88,9 @@ impl Output for NetDmxSenderOutput { type Element = Rgb; - async fn render(&mut self, out: impl BufferReader) -> Result<()> { - for fixture in self.fixtures.iter() { - let pixel = out.get(fixture.pixel); + async fn render(&mut self, out: impl BufferReader) -> Result<()> { + for (i, fixture) in self.fixtures.iter().enumerate() { + let pixel = out.get(i); let pixel = fixture.white_mode.apply(pixel); let pixel = pixel.into_format::(); @@ -114,4 +109,8 @@ impl Output for NetDmxSenderOutput { return Ok(()); } + + fn size(&self) -> usize { + return self.fixtures.len(); + } } diff --git a/output-net/src/wled.rs b/output-net/src/wled.rs index e60cc1d..1ea2b2c 100644 --- a/output-net/src/wled.rs +++ b/output-net/src/wled.rs @@ -1,3 +1,4 @@ +use std::future::Future; use byteorder::{BigEndian, WriteBytesExt}; use anyhow::Result; @@ -35,19 +36,23 @@ impl Mode { #[derive(Default)] pub struct WledSender { pub mode: Mode, + pub size: usize, } pub struct WledSenderOutput { mode: Mode, + size: usize, } impl OutputDecl for WledSender { type Output = WledSenderOutput; - async fn materialize(self, _size: usize) -> Result - where Self::Output: Sized { + async fn materialize(self) -> Result + where Self::Output: Sized, + { return Ok(Self::Output { mode: self.mode, + size: self.size, }); } } @@ -57,7 +62,7 @@ impl Output for WledSenderOutput { type Element = Rgb; - async fn render(&mut self, out: impl BufferReader) -> anyhow::Result<()> { + async fn render(&mut self, out: impl BufferReader) -> anyhow::Result<()> { let mut buffer = Vec::::with_capacity(2 + out.size() * self.mode.element_size()); // TODO: Allocate only once and re-use buffer.write_u8(match self.mode { Mode::DRGB => 2, @@ -107,4 +112,8 @@ impl Output for WledSenderOutput { return Ok(()); } + + fn size(&self) -> usize { + return self.size; + } } diff --git a/output-null/src/lib.rs b/output-null/src/lib.rs index 81db967..827be7e 100644 --- a/output-null/src/lib.rs +++ b/output-null/src/lib.rs @@ -1,3 +1,4 @@ +use std::future::Future; use anyhow::Result; use std::marker::PhantomData; @@ -5,19 +6,23 @@ use photonic::{BufferReader, Output, OutputDecl}; #[derive(Default)] pub struct Null { + size: usize, phantom: PhantomData, } pub struct NullOutput { + size: usize, phantom: PhantomData, } impl OutputDecl for Null { type Output = NullOutput; - async fn materialize(self, _size: usize) -> Result - where Self::Output: Sized { + async fn materialize(self) -> Result + where Self::Output: Sized, + { return Ok(Self::Output { + size: self.size, phantom: self.phantom, }); } @@ -28,7 +33,11 @@ impl Output for NullOutput { type Element = E; - async fn render(&mut self, _: impl BufferReader) -> Result<()> { + async fn render(&mut self, _: impl BufferReader) -> Result<()> { return Ok(()); } + + fn size(&self) -> usize { + return self.size; + } } diff --git a/output-terminal/src/lib.rs b/output-terminal/src/lib.rs index 0262e49..021393b 100644 --- a/output-terminal/src/lib.rs +++ b/output-terminal/src/lib.rs @@ -1,3 +1,4 @@ +use std::future::Future; use std::io::Write; use std::path::{Path, PathBuf}; use std::pin::Pin; @@ -9,23 +10,23 @@ use tokio::io::{AsyncWrite, AsyncWriteExt}; use photonic::{BufferReader, Output, OutputDecl}; pub struct Terminal { - pub waterfall: bool, + pub size: usize, pub path: Option, + pub waterfall: bool, } impl Terminal { - pub fn stdout() -> Self { + pub fn new(size: usize) -> Self { return Self { - waterfall: false, + size, path: None, + waterfall: false, }; } - pub fn with_path(path: impl AsRef) -> Self { - return Self { - waterfall: false, - path: Some(path.as_ref().to_path_buf()), - }; + pub fn with_path(mut self, path: impl AsRef) -> Self { + self.path = Some(path.as_ref().to_path_buf()); + return self; } pub fn with_waterfall(mut self, waterfall: bool) -> Self { @@ -35,15 +36,18 @@ impl Terminal { } pub struct TerminalOutput { + size: usize, waterfall: bool, + out: Pin>, } impl OutputDecl for Terminal { type Output = TerminalOutput; - async fn materialize(self, _size: usize) -> Result - where Self::Output: Sized { + async fn materialize(self) -> Result + where Self::Output: Sized, + { let out: Pin> = if let Some(path) = self.path { let _ = nix::unistd::unlink(&path); nix::unistd::mkfifo(&path, nix::sys::stat::Mode::S_IRWXU) @@ -60,6 +64,7 @@ impl OutputDecl for Terminal { }; return Ok(Self::Output { + size: self.size, waterfall: self.waterfall, out, }); @@ -71,7 +76,7 @@ impl Output for TerminalOutput { type Element = Srgb; - async fn render(&mut self, out: impl BufferReader) -> Result<()> { + async fn render(&mut self, out: impl BufferReader) -> Result<()> { // TODO: Maybe with inline replacement? let mut buf = Vec::with_capacity(out.size() * 20 + 5); @@ -90,4 +95,8 @@ impl Output for TerminalOutput { return Ok(()); } + + fn size(&self) -> usize { + return self.size; + } }