protoflow_blocks/blocks/hash/
hash.rs1use crate::{
4 prelude::{vec, Bytes},
5 types::HashAlgorithm,
6 StdioConfig, StdioError, StdioSystem, System,
7};
8use blake3::Hasher;
9use protoflow_core::{Block, BlockResult, BlockRuntime, InputPort, OutputPort, Port, PortError};
10use protoflow_derive::Block;
11use simple_mermaid::mermaid;
12
13#[doc = mermaid!("../../../doc/hash/hash.mmd")]
18#[doc = mermaid!("../../../doc/hash/hash.seq.mmd" framed)]
21#[derive(Block, Clone)]
48pub struct Hash {
49 #[input]
51 pub input: InputPort<Bytes>,
52
53 #[output]
55 pub output: OutputPort<Bytes>,
56
57 #[output]
59 pub hash: OutputPort<Bytes>,
60
61 #[parameter]
63 pub algorithm: HashAlgorithm,
64
65 #[state]
67 hasher: Hasher,
68}
69
70impl Hash {
71 pub fn new(
72 input: InputPort<Bytes>,
73 output: OutputPort<Bytes>,
74 hash: OutputPort<Bytes>,
75 ) -> Self {
76 Self::with_params(input, output, hash, None)
77 }
78
79 pub fn with_params(
80 input: InputPort<Bytes>,
81 output: OutputPort<Bytes>,
82 hash: OutputPort<Bytes>,
83 algorithm: Option<HashAlgorithm>,
84 ) -> Self {
85 Self {
86 input,
87 output,
88 hash,
89 algorithm: algorithm.unwrap_or_default(),
90 hasher: Hasher::new(),
91 }
92 }
93
94 pub fn with_system(system: &System, algorithm: Option<HashAlgorithm>) -> Self {
95 use crate::SystemBuilding;
96 Self::with_params(system.input(), system.output(), system.output(), algorithm)
97 }
98}
99
100impl Block for Hash {
101 fn execute(&mut self, runtime: &dyn BlockRuntime) -> BlockResult {
102 while let Some(message) = self.input.recv()? {
103 self.hasher.update(&message);
104
105 if self.output.is_connected() {
106 self.output.send(&message)?;
107 } else {
108 drop(message);
109 }
110 }
111 self.output.close()?;
112
113 runtime.wait_for(&self.hash)?;
114
115 let hash = Bytes::from(self.hasher.finalize().as_bytes().to_vec());
116 match self.hash.send(&hash) {
117 Ok(()) => {}
118 Err(PortError::Closed | PortError::Disconnected) => {
119 }
121 Err(e) => return Err(e)?,
122 };
123
124 Ok(())
125 }
126}
127
128#[cfg(feature = "std")]
129impl StdioSystem for Hash {
130 fn build_system(config: StdioConfig) -> Result<System, StdioError> {
131 use crate::{HashBlocks, IoBlocks, SystemBuilding};
132
133 config.allow_only(vec!["algorithm"])?;
135
136 Ok(System::build(|s| {
137 let stdin = config.read_stdin(s);
138 let hasher = s.hash_blake3();
139 let hex_encoder = s.encode_hex();
140 let stdout = config.write_stdout(s);
141 s.connect(&stdin.output, &hasher.input);
142 s.connect(&hasher.hash, &hex_encoder.input);
143 s.connect(&hex_encoder.output, &stdout.input);
144 }))
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::Hash;
151 use crate::{System, SystemBuilding};
152
153 #[test]
154 fn instantiate_block() {
155 let _ = System::build(|s| {
157 let _ = s.block(Hash::new(s.input(), s.output(), s.output()));
158 });
159 }
160}