protoflow_blocks/blocks/sys/
read_dir.rs

1// This is free and unencumbered software released into the public domain.
2
3extern crate std;
4
5use crate::{
6    prelude::{vec, String, ToString},
7    StdioConfig, StdioError, StdioSystem, System,
8};
9use protoflow_core::{Block, BlockResult, BlockRuntime, InputPort, OutputPort};
10use protoflow_derive::Block;
11use simple_mermaid::mermaid;
12
13/// A block that reads file names from a file system directory.
14///
15/// # Block Diagram
16#[doc = mermaid!("../../../doc/sys/read_dir.mmd")]
17///
18/// # Sequence Diagram
19#[doc = mermaid!("../../../doc/sys/read_dir.seq.mmd" framed)]
20///
21/// # Examples
22///
23/// ## Using the block in a system
24///
25/// ```rust
26/// # use protoflow_blocks::*;
27/// # fn main() {
28/// System::build(|s| {
29///     let path_param = s.const_string("/tmp");
30///     let dir_reader = s.read_dir();
31///     let line_encoder = s.encode_lines();
32///     let stdout = s.write_stdout();
33///     s.connect(&path_param.output, &dir_reader.path);
34///     s.connect(&dir_reader.output, &line_encoder.input);
35///     s.connect(&line_encoder.output, &stdout.input);
36/// });
37/// # }
38/// ```
39///
40/// ## Running the block via the CLI
41///
42/// ```console
43/// $ protoflow execute ReadDir path=/tmp
44/// ```
45///
46#[derive(Block, Clone)]
47pub struct ReadDir {
48    /// The path to the directory to read.
49    #[input]
50    pub path: InputPort<String>,
51
52    /// The output message stream.
53    #[output]
54    pub output: OutputPort<String>,
55}
56
57impl ReadDir {
58    pub fn new(path: InputPort<String>, output: OutputPort<String>) -> Self {
59        Self { path, output }
60    }
61
62    pub fn with_system(system: &System) -> Self {
63        use crate::SystemBuilding;
64        Self::new(system.input(), system.output())
65    }
66}
67
68impl Block for ReadDir {
69    fn execute(&mut self, runtime: &dyn BlockRuntime) -> BlockResult {
70        runtime.wait_for(&self.path)?;
71        let dir_path = self.path.recv()?.unwrap();
72        //self.path.close()?; // FIXME
73
74        let dir = std::fs::read_dir(dir_path)?;
75        for dir_entry in dir {
76            let file_path = dir_entry?.path();
77            //let file_path = file_path.strip_prefix("./").unwrap(); // TODO: parameter
78            let file_path = file_path.to_string_lossy().to_string();
79            self.output.send(&file_path)?;
80        }
81
82        self.output.close()?;
83        Ok(())
84    }
85}
86
87#[cfg(feature = "std")]
88impl StdioSystem for ReadDir {
89    fn build_system(config: StdioConfig) -> Result<System, StdioError> {
90        use crate::{CoreBlocks, IoBlocks, SysBlocks, SystemBuilding};
91
92        config.allow_only(vec!["path"])?;
93        let path = config.get_string("path")?;
94
95        Ok(System::build(|s| {
96            let path_param = s.const_string(path);
97            let dir_reader = s.read_dir();
98            let line_encoder = s.encode_with(config.encoding);
99            let stdout = config.write_stdout(s);
100            s.connect(&path_param.output, &dir_reader.path);
101            s.connect(&dir_reader.output, &line_encoder.input);
102            s.connect(&line_encoder.output, &stdout.input);
103        }))
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use super::ReadDir;
110    use crate::{System, SystemBuilding};
111
112    #[test]
113    fn instantiate_block() {
114        // Check that the block is constructible:
115        let _ = System::build(|s| {
116            let _ = s.block(ReadDir::new(s.input(), s.output()));
117        });
118    }
119}