streamson_lib/handler/
output.rs1use super::Handler;
4use crate::{error, path::Path, streamer::Token};
5use std::{any::Any, fs, io, str::FromStr};
6
7pub struct Output<W>
9where
10 W: io::Write,
11{
12 output: W,
14
15 write_path: bool,
18
19 separator: String,
22}
23
24impl FromStr for Output<fs::File> {
25 type Err = error::Handler;
26 fn from_str(input: &str) -> Result<Self, Self::Err> {
27 Ok(Self::new(
28 fs::File::create(input).map_err(error::Handler::new)?,
29 ))
30 }
31}
32
33impl<W> Output<W>
34where
35 W: io::Write,
36{
37 pub fn new(output: W) -> Self {
43 Self {
44 output,
45 write_path: false,
46 separator: "\n".into(),
47 }
48 }
49
50 pub fn set_write_path(mut self, write_path: bool) -> Self {
63 self.write_path = write_path;
64 self
65 }
66
67 pub fn set_separator<S>(mut self, separator: S) -> Self
82 where
83 S: ToString,
84 {
85 self.separator = separator.to_string();
86 self
87 }
88}
89
90impl<W> Handler for Output<W>
91where
92 W: io::Write + Send + 'static,
93{
94 fn start(
95 &mut self,
96 path: &Path,
97 _matcher_idx: usize,
98 _token: Token,
99 ) -> Result<Option<Vec<u8>>, error::Handler> {
100 if self.write_path {
101 self.output
102 .write(format!("{}: ", path).as_bytes())
103 .map_err(|err| error::Handler::new(err.to_string()))?;
104 }
105 Ok(None)
106 }
107
108 fn feed(
109 &mut self,
110 data: &[u8],
111 _matcher_idx: usize,
112 ) -> Result<Option<Vec<u8>>, error::Handler> {
113 self.output
114 .write(data)
115 .map_err(|err| error::Handler::new(err.to_string()))?;
116 Ok(None)
117 }
118
119 fn end(
120 &mut self,
121 _path: &Path,
122 _matcher_idx: usize,
123 _token: Token,
124 ) -> Result<Option<Vec<u8>>, error::Handler> {
125 let separator = self.separator.to_string();
126 self.output
127 .write(separator.as_bytes())
128 .map_err(|err| error::Handler::new(err.to_string()))?;
129 Ok(None)
130 }
131
132 fn as_any(&self) -> &dyn Any {
133 self
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use crate::{
140 handler, matcher,
141 strategy::{self, Strategy},
142 };
143 use std::{
144 fs, str,
145 sync::{Arc, Mutex},
146 };
147 use tempfile::NamedTempFile;
148
149 fn make_output(
150 path: &str,
151 matcher: matcher::Simple,
152 handler: handler::Output<fs::File>,
153 input: &[u8],
154 ) -> String {
155 let handler = Arc::new(Mutex::new(handler));
156 let mut trigger = strategy::Trigger::new();
157 trigger.add_matcher(Box::new(matcher), handler);
158
159 trigger.process(input).unwrap();
160 fs::read_to_string(path).unwrap()
161 }
162
163 #[test]
164 fn basic() {
165 let tmp_path = NamedTempFile::new().unwrap().into_temp_path();
166 let str_path = tmp_path.to_str().unwrap();
167
168 let matcher = matcher::Simple::new(r#"{"aa"}[]"#).unwrap();
169 let file = fs::File::create(str_path).unwrap();
170 let handler = handler::Output::new(file);
171
172 let output = make_output(
173 str_path,
174 matcher,
175 handler,
176 br#"{"aa": [1, 2, "u"], "b": true}"#,
177 );
178
179 assert_eq!(
180 output,
181 str::from_utf8(
182 br#"1
1832
184"u"
185"#
186 )
187 .unwrap()
188 );
189 }
190
191 #[test]
192 fn separator() {
193 let tmp_path = NamedTempFile::new().unwrap().into_temp_path();
194 let str_path = tmp_path.to_str().unwrap();
195
196 let matcher = matcher::Simple::new(r#"{"aa"}[]"#).unwrap();
197 let file = fs::File::create(str_path).unwrap();
198 let handler = handler::Output::new(file).set_separator("XXX");
199
200 let output = make_output(
201 str_path,
202 matcher,
203 handler,
204 br#"{"aa": [1, 2, "u"], "b": true}"#,
205 );
206
207 assert_eq!(output, str::from_utf8(br#"1XXX2XXX"u"XXX"#).unwrap());
208 }
209
210 #[test]
211 fn use_path() {
212 let tmp_path = NamedTempFile::new().unwrap().into_temp_path();
213 let str_path = tmp_path.to_str().unwrap();
214
215 let matcher = matcher::Simple::new(r#"{"aa"}[]"#).unwrap();
216 let file = fs::File::create(str_path).unwrap();
217 let handler = handler::Output::new(file).set_write_path(true);
218
219 let output = make_output(
220 str_path,
221 matcher,
222 handler,
223 br#"{"aa": [1, 2, "u"], "b": true}"#,
224 );
225
226 assert_eq!(
227 output,
228 str::from_utf8(
229 br#"{"aa"}[0]: 1
230{"aa"}[1]: 2
231{"aa"}[2]: "u"
232"#
233 )
234 .unwrap()
235 );
236 }
237}