protoflow_blocks/
stdio.rs

1// This is free and unencumbered software released into the public domain.
2
3extern crate std;
4
5use crate::{types::Encoding, ReadStdin, SysBlocks, System, WriteStderr, WriteStdout};
6use protoflow_core::prelude::{BTreeMap, FromStr, String, Vec};
7
8pub trait StdioSystem {
9    fn build_system(config: StdioConfig) -> Result<System, StdioError>;
10}
11
12#[derive(Debug, Default, Clone)]
13pub struct StdioConfig {
14    pub encoding: Encoding,
15    pub params: BTreeMap<String, String>,
16}
17
18impl StdioConfig {
19    pub fn reject_any(&self) -> Result<(), StdioError> {
20        if !self.params.is_empty() {
21            return Err(StdioError::UnknownParameter(
22                self.params.keys().next().unwrap().clone(),
23            ));
24        }
25        Ok(())
26    }
27
28    pub fn allow_only(&self, keys: Vec<&'static str>) -> Result<(), StdioError> {
29        for key in self.params.keys() {
30            if !keys.contains(&key.as_str()) {
31                return Err(StdioError::UnknownParameter(key.clone()));
32            }
33        }
34        Ok(())
35    }
36
37    pub fn get<T: FromStr>(&self, key: &'static str) -> Result<T, StdioError> {
38        self.get_string(key)?
39            .parse::<T>()
40            .map_err(|_| StdioError::InvalidParameter(key))
41    }
42
43    pub fn get_opt<T: FromStr>(&self, key: &'static str) -> Result<Option<T>, StdioError> {
44        match self.params.get(key) {
45            Some(value) => value
46                .parse::<T>()
47                .map_err(|_| StdioError::InvalidParameter(key))
48                .map(Some),
49            None => Ok(None),
50        }
51    }
52
53    pub fn get_string(&self, key: &'static str) -> Result<String, StdioError> {
54        let Some(value) = self.params.get(key).map(String::clone) else {
55            return Err(StdioError::MissingParameter(key))?;
56        };
57        Ok(value)
58    }
59
60    pub fn read_stdin(&self, system: &mut System) -> ReadStdin {
61        system.read_stdin() // TODO: support override
62    }
63
64    pub fn write_stdout(&self, system: &mut System) -> WriteStdout {
65        system.write_stdout() // TODO: support override
66    }
67
68    pub fn write_stderr(&self, system: &mut System) -> WriteStderr {
69        system.write_stderr() // TODO: support override
70    }
71}
72
73#[derive(Clone, Debug)]
74pub enum StdioError {
75    UnknownSystem(String),
76    UnknownParameter(String),
77    MissingParameter(&'static str),
78    InvalidParameter(&'static str),
79}
80
81impl std::error::Error for StdioError {}
82
83impl std::fmt::Display for StdioError {
84    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
85        use StdioError::*;
86        match self {
87            UnknownSystem(system) => {
88                write!(f, "unknown system: {}", system)
89            }
90            UnknownParameter(parameter) => {
91                write!(f, "unknown parameter: {}", parameter)
92            }
93            MissingParameter(parameter) => {
94                write!(f, "missing parameter: {}", parameter)
95            }
96            InvalidParameter(parameter) => {
97                write!(f, "invalid parameter: {}", parameter)
98            }
99        }
100    }
101}