protoflow_blocks/blocks/core/
random.rs

1// This is free and unencumbered software released into the public domain.
2
3use crate::{prelude::vec, StdioConfig, StdioError, StdioSystem, System};
4use protoflow_core::{Block, BlockResult, BlockRuntime, Message, OutputPort};
5use protoflow_derive::Block;
6use simple_mermaid::mermaid;
7
8/// A block for generating and sending a random value.
9///
10/// # Block Diagram
11#[doc = mermaid!("../../../doc/core/random.mmd")]
12///
13/// # Sequence Diagram
14#[doc = mermaid!("../../../doc/core/random.seq.mmd" framed)]
15///
16/// # Examples
17///
18/// ## Using the block in a system
19///
20/// ```rust
21/// # use protoflow_blocks::*;
22/// # fn main() {
23/// System::build(|s| {
24///     let random_generator = s.random::<u64>();
25///     let number_encoder = s.encode_lines();
26///     let stdout = s.write_stdout();
27///     s.connect(&random_generator.output, &number_encoder.input);
28///     s.connect(&number_encoder.output, &stdout.input);
29/// });
30/// # }
31/// ```
32///
33/// ## Running the block via the CLI
34///
35/// ```console
36/// $ protoflow execute Random
37/// ```
38///
39/// ```console
40/// $ protoflow execute Random seed=42
41/// ```
42///
43#[derive(Block, Clone)]
44pub struct Random<T: Message = u64> {
45    /// The port to send the value on.
46    #[output]
47    pub output: OutputPort<T>,
48
49    /// A parameter for the random seed to use.
50    #[parameter]
51    pub seed: Option<u64>,
52}
53
54impl<T: Message> Random<T> {
55    pub fn new(output: OutputPort<T>) -> Self {
56        Self::with_params(output, None)
57    }
58
59    pub fn with_params(output: OutputPort<T>, seed: Option<u64>) -> Self {
60        Self { output, seed }
61    }
62}
63
64impl<T: Message + 'static> Random<T> {
65    pub fn with_system(system: &System, seed: Option<u64>) -> Self {
66        use crate::SystemBuilding;
67        Self::with_params(system.output(), seed)
68    }
69}
70
71impl<T: Message + Default> Block for Random<T> {
72    fn execute(&mut self, runtime: &dyn BlockRuntime) -> BlockResult {
73        runtime.wait_for(&self.output)?;
74
75        self.output.send(&T::default())?; // TODO
76
77        Ok(())
78    }
79}
80
81#[cfg(feature = "std")]
82impl StdioSystem for Random<u64> {
83    fn build_system(config: StdioConfig) -> Result<System, StdioError> {
84        use crate::{CoreBlocks, IoBlocks, SystemBuilding};
85
86        config.allow_only(vec!["seed"])?;
87        let seed = config.get_opt::<u64>("seed")?;
88
89        Ok(System::build(|s| {
90            let random_generator = s.random_seeded::<u64>(seed);
91            let number_encoder = s.encode_with::<u64>(config.encoding);
92            let stdout = config.write_stdout(s);
93            s.connect(&random_generator.output, &number_encoder.input);
94            s.connect(&number_encoder.output, &stdout.input);
95        }))
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::Random;
102    use crate::{System, SystemBuilding};
103
104    #[test]
105    fn instantiate_block() {
106        // Check that the block is constructible:
107        let _ = System::build(|s| {
108            let _ = s.block(Random::<i32>::new(s.output()));
109        });
110    }
111}