streamson_lib/handler/
indenter.rs

1//! Handler which alters indentation of matched data
2//!
3//! # Example
4//! ```
5//! use streamson_lib::{handler, matcher, strategy::{self, Strategy}};
6//! use std::sync::{Arc, Mutex};
7//!
8//! let handler = Arc::new(Mutex::new(handler::Indenter::new(Some(2))));
9//! let mut all = strategy::All::new();
10//! all.set_convert(true);
11//!
12//! // Set the handler for all strategy
13//! all.add_handler(handler);
14//!
15//! for input in vec![
16//!     br#"{"users": [{"password": "1234", "name": "first"}, {"#.to_vec(),
17//!     br#""password": "0000", "name": "second}]}"#.to_vec(),
18//! ] {
19//!     for converted_data in all.process(&input).unwrap() {
20//!         println!("{:?}", converted_data);
21//!     }
22//! }
23//! ```
24
25use super::Handler;
26use crate::{
27    error,
28    path::{Element, Path},
29    streamer::{ParsedKind, Token},
30};
31use std::{any::Any, str::FromStr};
32
33/// Handler which alters indentation of matched data
34#[derive(Debug)]
35pub struct Indenter {
36    /// How many spaces should be used for indentation
37    spaces: Option<usize>,
38    /// Currently processed element on each level
39    stack: Option<Vec<(usize, ParsedKind)>>,
40}
41
42impl Indenter {
43    /// Creates a new handler which alters indentation
44    ///
45    /// # Arguments
46    /// * spaces - how many spaces should be used for indentation (if None - no indentation or newline should be added)
47    pub fn new(spaces: Option<usize>) -> Self {
48        Self {
49            spaces,
50            stack: None,
51        }
52    }
53
54    fn write_indent_level(&self, buff: &mut Vec<u8>) {
55        if let Some(stack) = self.stack.as_ref() {
56            for _ in 0..(stack.len() - 1) * self.spaces.unwrap_or(0) {
57                buff.push(b' ');
58            }
59        }
60    }
61}
62
63impl FromStr for Indenter {
64    type Err = error::Handler;
65    fn from_str(intend_str: &str) -> Result<Self, Self::Err> {
66        if intend_str.is_empty() {
67            Ok(Self::new(None))
68        } else {
69            Ok(Self::new(Some(
70                intend_str.parse::<usize>().map_err(error::Handler::new)?,
71            )))
72        }
73    }
74}
75
76impl Handler for Indenter {
77    fn start(
78        &mut self,
79        path: &Path,
80        _matcher_idx: usize,
81        token: Token,
82    ) -> Result<Option<Vec<u8>>, error::Handler> {
83        let kind = if let Token::Start(_, kind) = token {
84            kind
85        } else {
86            unreachable![];
87        };
88
89        let mut res = vec![];
90        self.stack = if let Some(mut stack) = self.stack.take() {
91            stack.push((0, kind));
92            // We need to add separators for nested elements
93            if stack.len() > 1 {
94                if stack[stack.len() - 2].0 != 0 {
95                    res.push(b',');
96                }
97                if self.spaces.is_some() {
98                    res.push(b'\n');
99                }
100            }
101            Some(stack)
102        } else {
103            // stack will always have one element
104            Some(vec![(0, kind)])
105        };
106
107        self.write_indent_level(&mut res);
108        // stack  should have at least one element now
109        let stack = self.stack.as_ref().unwrap();
110        if stack.len() > 1 {
111            // Write key of parent object
112            if matches!(stack[stack.len() - 2].1, ParsedKind::Obj) {
113                if let Element::Key(key) = &path.get_path()[path.depth() - 1] {
114                    res.push(b'"');
115                    res.extend(key.as_bytes());
116                    res.extend(br#"":"#);
117                    if self.spaces.is_some() {
118                        res.push(b' ');
119                    }
120                } else {
121                    unreachable!();
122                }
123            }
124        }
125
126        match kind {
127            ParsedKind::Arr => {
128                res.push(b'[');
129            }
130            ParsedKind::Obj => {
131                res.push(b'{');
132            }
133            _ => {}
134        }
135
136        if res.is_empty() {
137            Ok(None)
138        } else {
139            Ok(Some(res))
140        }
141    }
142
143    fn feed(
144        &mut self,
145        data: &[u8],
146        _matcher_idx: usize,
147    ) -> Result<Option<Vec<u8>>, error::Handler> {
148        let mut result = vec![];
149        if let Some(stack) = self.stack.as_ref() {
150            if let Some((_, kind)) = stack.last() {
151                match kind {
152                    ParsedKind::Obj | ParsedKind::Arr => {}
153                    _ => {
154                        result.extend(data.to_vec());
155                    }
156                }
157            }
158        }
159        Ok(Some(result))
160    }
161
162    fn end(
163        &mut self,
164        _path: &Path,
165        _matcher_idx: usize,
166        token: Token,
167    ) -> Result<Option<Vec<u8>>, error::Handler> {
168        let kind = if let Token::End(_, kind) = token {
169            kind
170        } else {
171            unreachable![];
172        };
173
174        let mut res = vec![];
175        if let Some(stack) = self.stack.as_ref() {
176            match kind {
177                ParsedKind::Arr => {
178                    if stack.last().unwrap().0 != 0 && self.spaces.is_some() {
179                        res.push(b'\n');
180                        self.write_indent_level(&mut res);
181                    }
182                    res.push(b']');
183                }
184                ParsedKind::Obj => {
185                    if stack.last().unwrap().0 != 0 && self.spaces.is_some() {
186                        res.push(b'\n');
187                        self.write_indent_level(&mut res);
188                    }
189                    res.push(b'}');
190                }
191                _ => {}
192            };
193        }
194
195        if let Some(stack) = self.stack.as_mut() {
196            // remove item from stack and increase parent count
197            stack.pop();
198            // Increase count
199            if let Some((idx, _)) = stack.last_mut() {
200                *idx += 1;
201            }
202
203            // finish newline
204            if stack.is_empty() && self.spaces.is_some() {
205                res.push(b'\n');
206                self.stack = None;
207            }
208        }
209
210        if res.is_empty() {
211            Ok(None)
212        } else {
213            Ok(Some(res))
214        }
215    }
216
217    fn is_converter(&self) -> bool {
218        true
219    }
220
221    fn as_any(&self) -> &dyn Any {
222        self
223    }
224}
225
226#[cfg(test)]
227mod tests {
228    use super::Indenter;
229    use crate::strategy::{All, OutputConverter, Strategy};
230    use rstest::*;
231    use std::sync::{Arc, Mutex};
232
233    fn make_all_with_spaces(level: Option<usize>) -> All {
234        let mut all = All::new();
235        all.set_convert(true);
236        all.add_handler(Arc::new(Mutex::new(Indenter::new(level))));
237        all
238    }
239
240    #[rstest(
241        spaces,
242        input,
243        output,
244        case::null_none(None, b"null", b"null"),
245        case::null_0(Some(0), b"null", b"null\n"),
246        case::null_2(Some(2), b"null", b"null\n"),
247        case::obj_none(None, b"{}", b"{}"),
248        case::obj_0(Some(0), b"{}", b"{}\n"),
249        case::obj_2(Some(2), b"{}", b"{}\n"),
250        case::arr_none(None, b"[]", b"[]"),
251        case::arr_0(Some(0), b"[]", b"[]\n"),
252        case::arr_2(Some(2), b"[]", b"[]\n"),
253        case::str_none(None, br#""str""#, br#""str""#),
254        case::str_0(Some(0), br#""str""#, b"\"str\"\n"),
255        case::str_2(Some(2), br#""str""#, b"\"str\"\n"),
256        before => [b"\n\n", b"\n", b" ", b""],
257        after => [b"\n\n", b"\n", b" "]
258    )]
259    fn leafs(spaces: Option<usize>, input: &[u8], output: &[u8], before: &[u8], after: &[u8]) {
260        let mut all = make_all_with_spaces(spaces);
261        let mut final_input = vec![];
262        final_input.extend(before);
263        final_input.extend(input);
264        final_input.extend(after);
265        let result = OutputConverter::new().convert(&all.process(&final_input).unwrap());
266
267        assert_eq!(result.len(), 1);
268        assert_eq!((None, output.to_vec()), result[0]);
269    }
270
271    #[test]
272    fn flat_array() {
273        let input = b" [ \n 3 \n , null,true,\n false, \"10\"\n]".to_vec();
274
275        // No indentation or spaces
276        let mut all = make_all_with_spaces(None);
277        assert_eq!(
278            br#"[3,null,true,false,"10"]"#.to_vec(),
279            OutputConverter::new().convert(&all.process(&input).unwrap())[0].1
280        );
281
282        // No indentation
283        let mut all = make_all_with_spaces(Some(0));
284        assert_eq!(
285            b"[\n3,\nnull,\ntrue,\nfalse,\n\"10\"\n]\n".to_vec(),
286            OutputConverter::new().convert(&all.process(&input).unwrap())[0].1
287        );
288
289        // 2 indentation
290        let mut all = make_all_with_spaces(Some(2));
291        assert_eq!(
292            b"[\n  3,\n  null,\n  true,\n  false,\n  \"10\"\n]\n".to_vec(),
293            OutputConverter::new().convert(&all.process(&input).unwrap())[0].1
294        );
295    }
296
297    #[test]
298    fn nested_array() {
299        let input = b" [ \n [3] \n , [],null,[[]], \"10\"\n,[[[]]]]".to_vec();
300
301        // No indentation or spaces
302        let mut all = make_all_with_spaces(None);
303        assert_eq!(
304            br#"[[3],[],null,[[]],"10",[[[]]]]"#.to_vec(),
305            OutputConverter::new().convert(&all.process(&input).unwrap())[0].1
306        );
307
308        // No indentation
309        let mut all = make_all_with_spaces(Some(0));
310        assert_eq!(
311            b"[\n[\n3\n],\n[],\nnull,\n[\n[]\n],\n\"10\",\n[\n[\n[]\n]\n]\n]\n".to_vec(),
312            OutputConverter::new().convert(&all.process(&input).unwrap())[0].1
313        );
314
315        // 2 indentation
316        let mut all = make_all_with_spaces(Some(2));
317        assert_eq!(
318            b"[\n  [\n    3\n  ],\n  [],\n  null,\n  [\n    []\n  ],\n  \"10\",\n  [\n    [\n      []\n    ]\n  ]\n]\n".to_vec(),
319            OutputConverter::new().convert(&all.process(&input).unwrap())[0].1
320        );
321    }
322
323    #[test]
324    fn flat_object() {
325        let input =
326            b" { \n \"1\" \n: 1 , \"2\":\"2\",   \"3\": null\n, \"4\":\n\nfalse\n\n\n}".to_vec();
327
328        // No indentation or spaces
329        let mut all = make_all_with_spaces(None);
330        assert_eq!(
331            br#"{"1":1,"2":"2","3":null,"4":false}"#.to_vec(),
332            OutputConverter::new().convert(&all.process(&input).unwrap())[0].1
333        );
334
335        // No indentation
336        let mut all = make_all_with_spaces(Some(0));
337        assert_eq!(
338            b"{\n\"1\": 1,\n\"2\": \"2\",\n\"3\": null,\n\"4\": false\n}\n".to_vec(),
339            OutputConverter::new().convert(&all.process(&input).unwrap())[0].1
340        );
341
342        // 2 indentation
343        let mut all = make_all_with_spaces(Some(2));
344        assert_eq!(
345            b"{\n  \"1\": 1,\n  \"2\": \"2\",\n  \"3\": null,\n  \"4\": false\n}\n".to_vec(),
346            OutputConverter::new().convert(&all.process(&input).unwrap())[0].1
347        );
348    }
349
350    #[test]
351    fn nested_object() {
352        let input =
353            b" { \n \"1\" \n: {} , \"2\":{\"2a\": {}},   \"3\": null\n, \"4\":\n\n{\"4a\": {\"4aa\": {}}}\n\n\n}".to_vec();
354
355        // No indentation or spaces
356        let mut all = make_all_with_spaces(None);
357        assert_eq!(
358            br#"{"1":{},"2":{"2a":{}},"3":null,"4":{"4a":{"4aa":{}}}}"#.to_vec(),
359            OutputConverter::new().convert(&all.process(&input).unwrap())[0].1
360        );
361
362        // No indentation
363        let mut all = make_all_with_spaces(Some(0));
364        assert_eq!(
365            b"{\n\"1\": {},\n\"2\": {\n\"2a\": {}\n},\n\"3\": null,\n\"4\": {\n\"4a\": {\n\"4aa\": {}\n}\n}\n}\n".to_vec(),
366            OutputConverter::new().convert(&all.process(&input).unwrap())[0].1
367        );
368
369        // 2 indentation
370        let mut all = make_all_with_spaces(Some(2));
371        assert_eq!(
372            b"{\n  \"1\": {},\n  \"2\": {\n    \"2a\": {}\n  },\n  \"3\": null,\n  \"4\": {\n    \"4a\": {\n      \"4aa\": {}\n    }\n  }\n}\n".to_vec(),
373            OutputConverter::new().convert(&all.process(&input).unwrap())[0].1
374        );
375    }
376
377    #[test]
378    fn complex() {
379        let input =
380            b" { \n \"1\" \n: [] , \"2\":{\"2a\": []},   \"3\": null\n, \"4\":\n\n[ {\"4aa\": {}}]\n\n\n}".to_vec();
381
382        // No indentation or spaces
383        let mut all = make_all_with_spaces(None);
384        assert_eq!(
385            br#"{"1":[],"2":{"2a":[]},"3":null,"4":[{"4aa":{}}]}"#.to_vec(),
386            OutputConverter::new().convert(&all.process(&input).unwrap())[0].1
387        );
388
389        // No indentation
390        let mut all = make_all_with_spaces(Some(0));
391        assert_eq!(
392            b"{\n\"1\": [],\n\"2\": {\n\"2a\": []\n},\n\"3\": null,\n\"4\": [\n{\n\"4aa\": {}\n}\n]\n}\n".to_vec(),
393            OutputConverter::new().convert(&all.process(&input).unwrap())[0].1
394        );
395
396        // 2 indentation
397        let mut all = make_all_with_spaces(Some(2));
398        assert_eq!(
399            b"{\n  \"1\": [],\n  \"2\": {\n    \"2a\": []\n  },\n  \"3\": null,\n  \"4\": [\n    {\n      \"4aa\": {}\n    }\n  ]\n}\n".to_vec(),
400            OutputConverter::new().convert(&all.process(&input).unwrap())[0].1
401        );
402    }
403}