jsonm/
unpacker.rs

1extern crate regex;
2extern crate serde;
3extern crate serde_json;
4
5use self::regex::Regex;
6use self::serde::Deserialize;
7use serde_json::Value;
8use std::collections::HashMap;
9use std::error::Error;
10use std::fmt;
11use std::vec::Vec;
12
13//const OLD_MESSAGE: i32 = -99;
14const MIN_DICT_INDEX: u64 = 3;
15const TYPE_ARRAY: i64 = 0;
16const TYPE_VALUE: i64 = 1;
17const TYPE_STRING: i64 = 2;
18const MAX_PACK_COMPLEX_OBJECT_SIZE: usize = 12;
19
20#[derive(Default, Debug)]
21pub struct Unpacker {
22    dict: HashMap<u64, String>,
23    dict_index: u64,
24    sequence_id: i64,
25    max_dict_size: u64,
26    pending_unpacks: Vec<i32>,
27}
28
29#[derive(Debug, Clone)]
30pub struct UnpackerError {
31    pub cause: String,
32}
33
34impl fmt::Display for UnpackerError {
35    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36        write!(f, "UnpackerError")
37    }
38}
39
40impl Error for UnpackerError {
41    fn description(&self) -> &str {
42        "Unpacker Error"
43    }
44
45    fn cause(&self) -> Option<&dyn Error> {
46        None
47    }
48}
49
50impl Unpacker {
51    pub fn new() -> Unpacker {
52        Unpacker {
53            sequence_id: -1,
54            max_dict_size: 2000,
55            dict_index: MIN_DICT_INDEX,
56            ..Default::default()
57        }
58    }
59
60    /// Unpack an packed object to its original input.
61    pub fn unpack<T>(&mut self, packed_object: &Value) -> Result<T, UnpackerError>
62    where
63        for<'de> T: Deserialize<'de>,
64    {
65        if packed_object.is_null() {
66            return match serde_json::from_value(Value::Null) {
67                Ok(v) => Ok(v),
68                Err(_err) => Err(UnpackerError {
69                    cause: "wrong end type for Value::Null, use Value type instead".to_owned(),
70                }),
71            };
72        };
73
74        let packed_arr = match packed_object.as_array() {
75            Some(packed_arr) => packed_arr,
76            None => {
77                return Err(UnpackerError {
78                    cause: "packed value expected".to_owned(),
79                })
80            }
81        };
82
83        if !packed_arr[packed_arr.len() - 1].is_number() {
84            return Err(UnpackerError {
85                cause: "packed value expected".to_owned(),
86            });
87        };
88
89        let value = &packed_arr[packed_arr.len() - 1];
90        let remote_sequence_id = match value.as_i64() {
91            Some(v) => v,
92            None => {
93                return Err(UnpackerError {
94                    cause: "packed value expected".to_owned(),
95                })
96            }
97        };
98
99        if remote_sequence_id == 0 {
100            self.dict_index = MIN_DICT_INDEX;
101        } else if remote_sequence_id != (self.sequence_id + 1) {
102            return Err(UnpackerError {
103                cause: "message unpacked out of sequence or already unpacked".to_owned(),
104            });
105        };
106
107        self.sequence_id = remote_sequence_id;
108        let unpacked = match self.unpack_object(&json!(packed_arr[..(packed_arr.len() - 1)])) {
109            Ok(result) => result,
110            Err(err) => return Err(err),
111        };
112
113        let result: T = match serde_json::from_value(unpacked) {
114            Ok(result) => result,
115            Err(_err) => {
116                return Err(UnpackerError {
117                    cause: "unable to unpack to specific type".to_owned(),
118                })
119            }
120        };
121        Ok(result)
122    }
123
124    /// Unpack an object to a string.
125    pub fn unpack_string(&mut self, packed_object: &Value) -> Result<String, UnpackerError> {
126        match packed_object.as_array() {
127            Some(arr) => {
128                if arr[0] == TYPE_STRING {
129                    return self.unpack(packed_object);
130                }
131
132                match self.unpack::<Value>(packed_object) {
133                    Ok(s) => Ok(s.to_string()),
134                    Err(err) => Err(err),
135                }
136            }
137            None => match self.unpack::<Value>(packed_object) {
138                Ok(s) => Ok(s.to_string()),
139                Err(err) => Err(err),
140            },
141        }
142    }
143
144    fn unpack_object(&mut self, packed_object: &Value) -> Result<Value, UnpackerError> {
145        if packed_object.is_null() {
146            return Ok(Value::Null);
147        };
148
149        if !packed_object.is_array() {
150            return self.unpack_value(packed_object);
151        }
152
153        let packed_array = match packed_object.as_array() {
154            Some(packed_array) => packed_array,
155            None => {
156                return Err(UnpackerError {
157                    cause: "wrong packed object".to_owned(),
158                })
159            }
160        };
161
162        let type_value = &packed_array[0];
163        let type_id = match type_value.as_i64() {
164            Some(i) => i,
165            None => -1,
166        };
167
168        if type_id == TYPE_ARRAY {
169            return packed_array[1..]
170                .iter()
171                .map(|v| self.unpack_object(&v))
172                .collect();
173        }
174        if type_id == TYPE_STRING {
175            return match packed_array[1..]
176                .iter()
177                .map(|v| self.unpack_object(&v))
178                .collect::<Result<Value, _>>()
179            {
180                Ok(arr) => {
181                    let vec = match arr.as_array() {
182                        Some(a) => a,
183                        None => {
184                            return Err(UnpackerError {
185                                cause: "expected array, got something else".to_owned(),
186                            })
187                        }
188                    };
189                    Ok(json!(vec.iter().fold("".to_owned(), |acc, x| {
190                        if acc.is_empty() {
191                            x.as_str().unwrap().to_owned()
192                        } else {
193                            acc + "\n" + x.as_str().unwrap()
194                        }
195                    })))
196                }
197                Err(err) => return Err(err),
198            };
199        }
200        if type_id == TYPE_VALUE {
201            return self.unpack_value(&packed_array[1]);
202        }
203
204        let mut contains_unmemoised = false;
205        let mut processed_object: Vec<Value> = Vec::new();
206        for item in packed_array {
207            if item.is_object() || item.is_array() {
208                let value = match self.unpack_object(&item) {
209                    Ok(v) => v,
210                    Err(err) => return Err(err),
211                };
212                contains_unmemoised = true;
213                processed_object.push(value);
214            } else {
215                if !item.is_number() {
216                    contains_unmemoised = true;
217                }
218                let value = match self.unpack_value(&item) {
219                    Ok(v) => v,
220                    Err(err) => return Err(err),
221                };
222
223                processed_object.push(value);
224            }
225        }
226
227        let mut result: HashMap<String, Value> = HashMap::new();
228        let key_count = processed_object.len() / 2;
229        for i in 0..key_count {
230            let key_value = &processed_object[i];
231            let key = match processed_object[i].as_str() {
232                Some(s) => s.to_string(),
233                None => key_value.to_string(),
234            };
235            result.insert(key, processed_object[i + key_count].clone());
236        }
237
238        let json_result = json!(result);
239        if !contains_unmemoised && packed_array.len() <= MAX_PACK_COMPLEX_OBJECT_SIZE {
240            self.add_to_dict(&json_result.to_string());
241        }
242
243        Ok(json_result)
244    }
245
246    fn unpack_value(&mut self, packed_object: &Value) -> Result<Value, UnpackerError> {
247        if packed_object.is_number() {
248            return match packed_object.as_i64() {
249                Some(v) => {
250                    if v < 0 {
251                        return Ok(json!(v * -1));
252                    }
253                    let index = packed_object.as_u64().unwrap();
254                    let string = match self.dict.get(&index) {
255                        Some(s) => s,
256                        None => {
257                            return Err(UnpackerError {
258                                cause: "no stored value".to_owned(),
259                            })
260                        }
261                    };
262                    let json: serde_json::Value = match serde_json::from_str(&string) {
263                        Ok(parsed) => parsed,
264                        Err(_err) => json!(string),
265                    };
266
267                    Ok(json)
268                }
269                None => Err(UnpackerError {
270                    cause: "unknown".to_owned(),
271                }),
272            };
273        };
274
275        if packed_object.is_string() {
276            let string = match packed_object.as_str() {
277                Some(s) => s,
278                None => {
279                    return Err(UnpackerError {
280                        cause: "unknown".to_owned(),
281                    })
282                }
283            };
284
285            let re = Regex::new(r"^-?[0-9]+\.").unwrap();
286            if re.is_match(string) {
287                let _p: Value = match string.parse::<f64>() {
288                    Ok(parse_number) => {
289                        self.add_to_dict(string);
290                        return Ok(json!(parse_number));
291                    }
292                    Err(_err) => Value::Null,
293                };
294            };
295
296            let re = Regex::new(r"^-?[0-9\.]").unwrap();
297            if re.is_match(string) {
298                let _p: Value = match string.parse::<i64>() {
299                    Ok(parse_number) => {
300                        self.add_to_dict(string);
301                        return Ok(json!(parse_number));
302                    }
303                    Err(_err) => Value::Null,
304                };
305            };
306
307            let value = if !string.is_empty() && &string[0..1] == "~" {
308                &string[1..]
309            } else {
310                string
311            };
312
313            self.add_to_dict(&json!(value).to_string());
314            return Ok(json!(value));
315        }
316        Ok(json!(packed_object))
317    }
318
319    fn add_to_dict(&mut self, str_value: &str) {
320        self.dict.insert(self.dict_index, str_value.to_owned());
321        self.dict_index += 1;
322        if self.dict_index >= (self.max_dict_size + MIN_DICT_INDEX) {
323            self.dict_index = MIN_DICT_INDEX;
324        }
325    }
326
327    /// Set the maximum dictionary size. Must match the dictionary size used by the packer.
328    /// Default - 2000.
329    pub fn set_max_dict_size(&mut self, value: u64) {
330        self.max_dict_size = value;
331    }
332}