protoflow_blocks/blocks/core/
const.rs

1// This is free and unencumbered software released into the public domain.
2
3use crate::{
4    prelude::{vec, String},
5    StdioConfig, StdioError, StdioSystem, System,
6};
7use protoflow_core::{Block, BlockResult, BlockRuntime, Message, OutputPort};
8use protoflow_derive::Block;
9use simple_mermaid::mermaid;
10
11/// A block for sending a constant value.
12///
13/// This block sends a constant value on its output port.
14/// It can also be used to send a constant value to multiple blocks.
15///
16/// The value to send is specified as a parameter, and can be of any
17/// type that implements the [`Message`] trait.
18///
19/// The block waits for the output port to be connected before sending
20/// the value, and closes the port after the value is sent.
21///
22/// The block does not have any input ports nor state.
23///
24/// # Block Diagram
25#[doc = mermaid!("../../../doc/core/const.mmd")]
26///
27/// # Sequence Diagram
28#[doc = mermaid!("../../../doc/core/const.seq.mmd" framed)]
29///
30/// # Examples
31///
32/// ## Using the block in a system
33///
34/// ```rust
35/// # use protoflow_blocks::*;
36/// # fn main() {
37/// System::build(|s| {
38///     let const_value = s.const_string("Hello, world!");
39///     let line_encoder = s.encode_lines();
40///     let stdout = s.write_stdout();
41///     s.connect(&const_value.output, &line_encoder.input);
42///     s.connect(&line_encoder.output, &stdout.input);
43/// });
44/// # }
45/// ```
46///
47/// ## Running the block via the CLI
48///
49/// ```console
50/// $ protoflow execute Const value=Hello
51/// ```
52///
53#[derive(Block, Clone)]
54pub struct Const<T: Message = String> {
55    /// The port to send the value on.
56    #[output]
57    pub output: OutputPort<T>,
58
59    /// A parameter for the value to send.
60    #[parameter]
61    pub value: T,
62}
63
64impl<T: Message + Default> Const<T> {
65    pub fn new(output: OutputPort<T>) -> Self {
66        Self::with_params(output, T::default())
67    }
68}
69
70impl<T: Message> Const<T> {
71    pub fn with_params(output: OutputPort<T>, value: T) -> Self {
72        Self { output, value }
73    }
74}
75
76impl<T: Message + 'static> Const<T> {
77    pub fn with_system(system: &System, value: T) -> Self {
78        use crate::SystemBuilding;
79        Self::with_params(system.output(), value)
80    }
81}
82
83impl<T: Message> Block for Const<T> {
84    fn execute(&mut self, runtime: &dyn BlockRuntime) -> BlockResult {
85        runtime.wait_for(&self.output)?;
86
87        self.output.send(&self.value)?;
88
89        Ok(())
90    }
91}
92
93#[cfg(feature = "std")]
94impl<T: Message> StdioSystem for Const<T> {
95    fn build_system(config: StdioConfig) -> Result<System, StdioError> {
96        use crate::{CoreBlocks, IoBlocks, SystemBuilding};
97
98        config.allow_only(vec!["value"])?;
99        let value = config.get_string("value")?;
100
101        Ok(System::build(|s| {
102            let const_value = s.const_string(value); // FIXME
103            let line_encoder = s.encode_with(config.encoding);
104            let stdout = config.write_stdout(s);
105            s.connect(&const_value.output, &line_encoder.input);
106            s.connect(&line_encoder.output, &stdout.input);
107        }))
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::Const;
114    use crate::{System, SystemBuilding};
115
116    #[test]
117    fn instantiate_block() {
118        // Check that the block is constructible:
119        let _ = System::build(|s| {
120            let _ = s.block(Const::<i32>::with_params(s.output(), 0x00BAB10C));
121        });
122    }
123}