streamson_lib/handler/
unstringify.rs

1//! Handler which unstringifies matched data
2//! it can be used e.g. shorten long strings
3//! `"{\"aa\": {\"bb\":2}, \"cc\": \"dd\"}"` -> `{"aa": {"bb": 2}, "cc": "dd"}`
4//!
5//! # Example
6//! ```
7//! use streamson_lib::{handler, matcher, strategy::{self, Strategy}};
8//! use std::sync::{Arc, Mutex};
9//!
10//! let handler = Arc::new(Mutex::new(handler::Unstringify::new()));
11//! let matcher = matcher::Simple::new(r#"{"stringified_strings"}[]"#).unwrap();
12//!
13//! let mut convert = strategy::Convert::new();
14//!
15//! // Set the matcher for convert strategy
16//! convert.add_matcher(Box::new(matcher), handler);
17//!
18//! for input in vec![
19//!     br#"{"stringified_strings": ["\"string\"", "{}", "[]"]}"#.to_vec(),
20//! ] {
21//!     for converted_data in convert.process(&input).unwrap() {
22//!         println!("{:?}", converted_data);
23//!     }
24//! }
25//! ```
26
27use super::Handler;
28use crate::{
29    error,
30    streamer::{ParsedKind, Token},
31    Path,
32};
33use std::{any::Any, str::FromStr};
34
35#[derive(Debug)]
36pub enum State {
37    Initial,
38    Escaping,
39    Processing,
40    Terminated,
41}
42
43impl Default for State {
44    fn default() -> Self {
45        Self::Initial
46    }
47}
48
49fn _processing_error() -> error::Handler {
50    error::Handler::new("Wrong unstringify format")
51}
52
53/// Handler which unstringifies the matched data
54///
55#[derive(Debug, Default)]
56pub struct Unstringify {
57    state: State,
58}
59
60impl Unstringify {
61    /// Creates a new handler which unstringifies matched data
62    pub fn new() -> Self {
63        Default::default()
64    }
65}
66
67impl FromStr for Unstringify {
68    type Err = error::Handler;
69    fn from_str(input: &str) -> Result<Self, Self::Err> {
70        if input.is_empty() {
71            Ok(Self::default())
72        } else {
73            Err(error::Handler::new("Analyser handler accepts no argument"))
74        }
75    }
76}
77
78impl Handler for Unstringify {
79    fn start(
80        &mut self,
81        _path: &Path,
82        _matcher_idx: usize,
83        token: Token,
84    ) -> Result<Option<Vec<u8>>, error::Handler> {
85        self.state = State::Initial;
86        if let Token::Start(_, kind) = token {
87            if !matches!(kind, ParsedKind::Str) {
88                return Err(error::Handler::new(
89                    "Unstringified data is supposed to be a string.",
90                ));
91            }
92            Ok(None)
93        } else {
94            unreachable!();
95        }
96    }
97
98    fn feed(
99        &mut self,
100        data: &[u8],
101        _matcher_idx: usize,
102    ) -> Result<Option<Vec<u8>>, error::Handler> {
103        let mut result: Vec<u8> = vec![];
104        for byte in data.iter() {
105            match self.state {
106                State::Initial => {
107                    // skip first character
108                    self.state = State::Processing;
109                    continue;
110                }
111                State::Processing => {
112                    match *byte {
113                        b'\\' => self.state = State::Escaping,
114                        b'"' => {
115                            // terminate handler matching
116                            self.state = State::Terminated;
117                            break;
118                        }
119                        byte => result.push(byte),
120                    }
121                }
122                State::Escaping => {
123                    // Just append next byte
124                    result.push(*byte);
125                    self.state = State::Processing;
126                }
127                State::Terminated => return Err(_processing_error()),
128            }
129        }
130
131        Ok(Some(result))
132    }
133
134    fn end(
135        &mut self,
136        _path: &Path,
137        _matcher_idx: usize,
138        _token: Token,
139    ) -> Result<Option<Vec<u8>>, error::Handler> {
140        if !matches!(self.state, State::Terminated) {
141            return Err(error::Handler::new("String does not ended"));
142        }
143        Ok(None)
144    }
145
146    fn is_converter(&self) -> bool {
147        true
148    }
149
150    fn as_any(&self) -> &dyn Any {
151        self
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use super::Unstringify;
158    use crate::{
159        matcher::Simple,
160        strategy::{Convert, OutputConverter, Strategy},
161    };
162    use std::sync::{Arc, Mutex};
163
164    #[test]
165    fn unstringify_handler_ok() {
166        let mut convert = Convert::new();
167        let shorten_handler = Arc::new(Mutex::new(Unstringify::new()));
168        let matcher = Simple::new(r#"[]{"stringified"}[]"#).unwrap();
169
170        convert.add_matcher(Box::new(matcher), shorten_handler.clone());
171        let mut output = convert
172            .process(br#"[{"stringified": ["true", "false", "null", "11", "\"\""]},"#)
173            .unwrap();
174
175        output.extend(
176            convert
177                .process(br#" {"stringified": ["\"inner\"", "[]", "{}", "{\"key\": \"value\"}"]}]"#)
178                .unwrap(),
179        );
180
181        let output: Vec<u8> = OutputConverter::new()
182            .convert(&output)
183            .into_iter()
184            .map(|e| e.1)
185            .flatten()
186            .collect();
187
188        assert_eq!(
189            String::from_utf8(output).unwrap(),
190            r#"[{"stringified": [true, false, null, 11, ""]}, {"stringified": ["inner", [], {}, {"key": "value"}]}]"#
191        );
192    }
193}