tusk_rs/
json.rs

1use chrono::{DateTime, Utc};
2use std::{
3    collections::HashMap,
4    str::{Chars, FromStr},
5};
6use uuid::Uuid;
7
8struct JsonDecoder;
9impl JsonDecoder {
10    fn derive_key(enumerator: &mut Chars) -> String {
11        let mut current_key = String::new();
12        while let Some(key_content) = enumerator.next() {
13            if key_content != '"' {
14                current_key.push(key_content)
15            } else {
16                // Skip the colon (and spaces)
17                for t in enumerator.by_ref() {
18                    if t == ':' {
19                        break;
20                    }
21                }
22                break;
23            }
24        }
25        current_key
26    }
27
28    fn derive_value<T: Iterator<Item = char>>(enumerator: &mut T) -> String {
29        let mut value_start = ' ';
30        while value_start == ' ' || value_start == ',' {
31            if let Some(v) = enumerator.next() {
32                value_start = v;
33            } else {
34                return String::new();
35            }
36        }
37        let exec = match value_start {
38            '\"' => JsonTypeString::extract,
39            '{' => JsonTypeObject::extract,
40            '[' => JsonTypeArray::extract,
41            _ => JsonTypePrimitive::extract,
42        };
43        exec(enumerator, value_start.to_string())
44    }
45}
46
47/// A JSON structure that is formatted
48/// like the following:
49///
50/// {
51///     "key": "value"
52/// }
53#[derive(Debug)]
54pub struct JsonObject {
55    keys: HashMap<String, String>,
56}
57
58impl JsonObject {
59    /// Creates an empty JSON object.
60    /// This is useful for building a JSON
61    /// object from scratch.
62    pub fn empty() -> JsonObject {
63        JsonObject {
64            keys: HashMap::new(),
65        }
66    }
67
68    /// Builds a JSONObject from a string
69    /// containing keys and values.
70    ///
71    /// # Arguments
72    ///
73    /// * `json` — An owned string containing the JSON.
74    pub fn from_string(json: &str) -> JsonObject {
75        let mut keys: HashMap<String, String> = HashMap::new();
76        let mut enumerator = json.chars();
77        while let Some(c) = enumerator.next() {
78            if c == '"' {
79                let (k, v) = (
80                    JsonDecoder::derive_key(&mut enumerator),
81                    JsonDecoder::derive_value(&mut enumerator),
82                );
83                keys.insert(k, v);
84            }
85        }
86        // dbg!(&keys);
87        JsonObject { keys }
88    }
89
90    /// Return a key of the JSON object as a type which
91    /// implements JsonRetrieve.
92    ///
93    /// # Arguments
94    ///
95    /// * `key` — The key to retrieve from.
96    pub fn get<T: JsonRetrieve>(&self, key: &str) -> Result<T, JsonParseError> {
97        T::parse(key.to_string(), self.keys.get(key))
98    }
99
100    /// Return a key of the JSON object as a type which
101    /// implements JsonRetrieve.
102    ///
103    /// # Arguments
104    ///
105    /// * `key` — The key to retrieve from.
106    pub fn set<T: ToJson>(&mut self, key: &str, data: T) {
107        self.keys.insert(key.to_string(), data.to_json());
108    }
109}
110impl Default for JsonObject {
111    fn default() -> Self {
112        JsonObject::empty()
113    }
114}
115
116#[derive(Debug)]
117pub struct JsonArray {
118    values: Vec<String>,
119}
120impl JsonArray {
121    /// Creates an empty JSON array.
122    /// This is useful for building a JSON
123    /// array from scratch.
124    pub fn empty() -> JsonArray {
125        JsonArray { values: Vec::new() }
126    }
127
128    /// Builds a JSONArray from a string
129    /// containing children that implement
130    /// `JsonRetreive`
131    ///
132    /// # Arguments
133    ///
134    /// * `json` — An owned string containing the JSON.
135    pub fn from_string(json: &str) -> JsonArray {
136        let mut values: Vec<String> = Vec::new();
137        let mut enumerator = json.chars().peekable();
138
139        while let Some(v) = enumerator.peek() {
140            if v.is_whitespace() || *v == '[' {
141                enumerator.next();
142            } else {
143                break;
144            }
145        }
146        while enumerator.peek().is_some() {
147            if *enumerator.peek().unwrap_or(&'_') == ']' {
148                _ = enumerator.next();
149                continue;
150            }
151            let v = JsonDecoder::derive_value(&mut enumerator);
152            values.push(v);
153        }
154        JsonArray { values }
155    }
156
157    /// Gets the object at the index as a type
158    /// that implements JsonRetrieve.
159    ///
160    /// # Arguments
161    ///
162    /// * `index` — The index to retrieve from.
163    pub fn get<T: JsonRetrieve>(&self, index: usize) -> Result<T, JsonParseError> {
164        T::parse(index.to_string(), self.values.get(index))
165    }
166
167    /// Converts all elements of this JSONArray
168    /// to a type that implements JsonRetrieve.
169    /// Progagates errors if any child keys are invalid.
170    pub fn map<T: JsonRetrieve>(&self) -> Result<Vec<T>, JsonParseError> {
171        if self.values.is_empty() {
172            return Ok(Vec::new());
173        }
174        let mut build = Vec::new();
175        for i in 0..self.values.len() {
176            let value = self.values.get(i);
177            build.push(T::parse(i.to_string(), value)?);
178        }
179        Ok(build)
180    }
181
182    /// Converts all elements of this JSONArray
183    /// to a type that implements JsonRetrieve.
184    /// Silently drops any invalid children.
185    pub fn map_drop<T: JsonRetrieve>(&self) -> Vec<T> {
186        if self.values.is_empty() {
187            return Vec::new();
188        }
189        let mut build = Vec::new();
190        for i in 0..self.values.len() {
191            let value = &self.values[i];
192            if let Ok(val) = T::parse(i.to_string(), Some(value)) {
193                build.push(val);
194            }
195        }
196        build
197    }
198}
199impl Default for JsonArray {
200    fn default() -> Self {
201        JsonArray::empty()
202    }
203}
204
205trait JsonType {
206    fn extract<T: Iterator<Item = char>>(stream: &mut T, intl_value: String) -> String;
207}
208
209struct JsonTypePrimitive;
210impl JsonType for JsonTypePrimitive {
211    fn extract<T: Iterator<Item = char>>(stream: &mut T, intl_value: String) -> String {
212        let mut buf = intl_value;
213        for n in stream.by_ref() {
214            if n.is_whitespace() || n == ',' || n == '}' || n == ']' {
215                break;
216            }
217            buf.push(n);
218        }
219        buf
220    }
221}
222
223struct JsonTypeString;
224impl JsonType for JsonTypeString {
225    fn extract<T: Iterator<Item = char>>(stream: &mut T, intl_value: String) -> String {
226        let mut buf = intl_value;
227        let mut prev = '_';
228        let mut prev_prev = '_';
229        for n in stream.by_ref() {
230            buf.push(n);
231            if n == '"' && (prev != '\\' || prev_prev == '\\') {
232                break;
233            }
234            prev_prev = prev;
235            prev = n;
236        }
237        buf
238    }
239}
240
241struct JsonTypeObject;
242impl JsonType for JsonTypeObject {
243    fn extract<T: Iterator<Item = char>>(stream: &mut T, intl_value: String) -> String {
244        let mut buf = intl_value;
245        let mut sep_stack = 1;
246
247        let mut prev = '_';
248        let mut prev_prev = '_';
249        let mut is_in_string = false;
250
251        for n in stream.by_ref() {
252            if n == '"' && (prev != '\\' || prev_prev == '\\') {
253                is_in_string = !is_in_string;
254            }
255            if !is_in_string && n.is_whitespace() {
256                continue;
257            }
258            buf.push(n);
259            if n == '{' {
260                sep_stack += 1
261            } else if n == '}' {
262                sep_stack -= 1
263            }
264            if sep_stack == 0 {
265                break;
266            }
267            prev_prev = prev;
268            prev = n;
269        }
270        buf
271    }
272}
273
274struct JsonTypeArray;
275impl JsonType for JsonTypeArray {
276    fn extract<T: Iterator<Item = char>>(stream: &mut T, intl_value: String) -> String {
277        let mut buf = intl_value;
278        let mut sep_stack = 1;
279
280        let mut prev = '_';
281        let mut prev_prev = '_';
282        let mut is_in_string = false;
283
284        for n in stream.by_ref() {
285            if n == '"' && (prev != '\\' || prev_prev == '\\') {
286                is_in_string = !is_in_string;
287            }
288            if !is_in_string && n.is_whitespace() {
289                continue;
290            }
291            buf.push(n);
292            if n == '[' {
293                sep_stack += 1
294            } else if n == ']' {
295                sep_stack -= 1
296            }
297            if sep_stack == 0 {
298                break;
299            }
300            prev_prev = prev;
301            prev = n;
302        }
303        buf
304    }
305}
306
307#[derive(Debug)]
308pub enum JsonParseError {
309    NotFound(String),
310    InvalidType(String, &'static str),
311}
312
313/// ToJson is a trait that allows any conforming
314/// structs to convert to a JSON format.
315///
316/// A default implemenation is most easily
317/// obtained by deriving this trait.
318pub trait ToJson {
319    /// ToJson creates a JSON string from
320    /// anything which implements it
321    fn to_json(&self) -> String;
322}
323
324/// FromJs is a trait that allows any conforming
325/// structs to be converted from a JSON format.
326///
327/// A default implemenation is most easily
328/// obtained by deriving this trait.
329pub trait FromJson {
330    fn from_json(json: &JsonObject) -> Result<Self, JsonParseError>
331    where
332        Self: Sized;
333}
334
335impl ToJson for String {
336    fn to_json(&self) -> String {
337        let mut o = String::new();
338        o += "\"";
339        o += &self
340            .replace('\\', "\\\\")
341            .replace('"', "\\\"")
342            .replace('\n', "\\n")
343            .replace('\t', "\\t");
344        o += "\"";
345        o
346    }
347}
348impl ToJson for str {
349    fn to_json(&self) -> String {
350        let mut o = String::new();
351        o += "\"";
352        o += &self
353            .replace('\\', "\\\\")
354            .replace('"', "\\\"")
355            .replace('\n', "\\n")
356            .replace('\t', "\\t");
357        o += "\"";
358        o
359    }
360}
361impl ToJson for i32 {
362    fn to_json(&self) -> String {
363        self.to_string()
364    }
365}
366impl ToJson for i64 {
367    fn to_json(&self) -> String {
368        self.to_string()
369    }
370}
371impl ToJson for u32 {
372    fn to_json(&self) -> String {
373        self.to_string()
374    }
375}
376impl ToJson for u64 {
377    fn to_json(&self) -> String {
378        self.to_string()
379    }
380}
381impl ToJson for f32 {
382    fn to_json(&self) -> String {
383        self.to_string()
384    }
385}
386impl ToJson for f64 {
387    fn to_json(&self) -> String {
388        self.to_string()
389    }
390}
391impl ToJson for bool {
392    fn to_json(&self) -> String {
393        if *self {
394            "true".to_string()
395        } else {
396            "false".to_string()
397        }
398    }
399}
400impl<T: ToJson> ToJson for Vec<T> {
401    fn to_json(&self) -> String {
402        let mut output = String::new();
403        output += "[";
404        for i in self.iter() {
405            output += &i.to_json();
406            output += ",";
407        }
408        if !self.is_empty() {
409            output.pop();
410        }
411        output += "]";
412        output
413    }
414}
415impl<T: ToJson> ToJson for Option<T> {
416    fn to_json(&self) -> String {
417        match self {
418            Some(x) => x.to_json(),
419            None => "null".to_string(),
420        }
421    }
422}
423impl<K: ToJson, V: ToJson> ToJson for HashMap<K, V> {
424    fn to_json(&self) -> String {
425        let mut output = String::new();
426        output += "{";
427        for (k, v) in self {
428            output += "\"";
429            output += &k.to_json();
430            output += "\":";
431            output += &v.to_json();
432            output += ",";
433        }
434        output.pop();
435        output += "}";
436        output
437    }
438}
439impl ToJson for JsonObject {
440    fn to_json(&self) -> String {
441        let mut output = "{".to_string();
442        for (k, v) in &self.keys {
443            output += "\"";
444            output += k;
445            output += "\":";
446            output += v;
447            output += ",";
448        }
449        if output != "{" {
450            output.pop();
451        }
452        output += "}";
453        output
454    }
455}
456impl ToJson for JsonArray {
457    fn to_json(&self) -> String {
458        let mut output = "[".to_string();
459        for v in &self.values {
460            output += v;
461            output += ",";
462        }
463        output.pop();
464        output += "]";
465        output
466    }
467}
468
469pub trait JsonRetrieve {
470    fn parse(key: String, value: Option<&String>) -> Result<Self, JsonParseError>
471    where
472        Self: Sized;
473}
474
475impl JsonRetrieve for String {
476    fn parse(key: String, value: Option<&String>) -> Result<Self, JsonParseError> {
477        let val = value.ok_or(JsonParseError::NotFound(key.clone()))?;
478        if val.len() < 2 {
479            return Err(JsonParseError::InvalidType(key, "String"));
480        }
481        Ok(val[1..val.len() - 1].replace("\\\"", "\"").to_string())
482    }
483}
484impl JsonRetrieve for i32 {
485    fn parse(key: String, value: Option<&String>) -> Result<Self, JsonParseError> {
486        if let Some(v) = value {
487            Ok(v.parse()
488                .map_err(|_| JsonParseError::InvalidType(key, "i32"))?)
489        } else {
490            Err(JsonParseError::NotFound(key))
491        }
492    }
493}
494impl JsonRetrieve for i64 {
495    fn parse(key: String, value: Option<&String>) -> Result<Self, JsonParseError> {
496        if let Some(v) = value {
497            Ok(v.parse()
498                .map_err(|_| JsonParseError::InvalidType(key, "i64"))?)
499        } else {
500            Err(JsonParseError::NotFound(key))
501        }
502    }
503}
504impl JsonRetrieve for f32 {
505    fn parse(key: String, value: Option<&String>) -> Result<Self, JsonParseError> {
506        if let Some(v) = value {
507            Ok(v.parse()
508                .map_err(|_| JsonParseError::InvalidType(key, "f32"))?)
509        } else {
510            Err(JsonParseError::NotFound(key))
511        }
512    }
513}
514impl JsonRetrieve for f64 {
515    fn parse(key: String, value: Option<&String>) -> Result<Self, JsonParseError> {
516        if let Some(v) = value {
517            Ok(v.parse()
518                .map_err(|_| JsonParseError::InvalidType(key, "f64"))?)
519        } else {
520            Err(JsonParseError::NotFound(key))
521        }
522    }
523}
524impl JsonRetrieve for bool {
525    fn parse(key: String, value: Option<&String>) -> Result<Self, JsonParseError> {
526        if let Some(v) = value {
527            match v.as_ref() {
528                "true" => Ok(true),
529                "false" => Ok(false),
530                _ => Err(JsonParseError::InvalidType(key, "bool")),
531            }
532        } else {
533            Err(JsonParseError::NotFound(key))
534        }
535    }
536}
537impl<T: JsonRetrieve> JsonRetrieve for Vec<T> {
538    fn parse(key: String, value: Option<&String>) -> Result<Self, JsonParseError> {
539        JsonArray::from_string(value.ok_or(JsonParseError::NotFound(key))?).map()
540    }
541}
542impl<T: JsonRetrieve> JsonRetrieve for Option<T> {
543    fn parse(key: String, value: Option<&String>) -> Result<Self, JsonParseError> {
544        if let Some(v) = value {
545            if v != "null" {
546                return Ok(Some(T::parse(key, value)?));
547            }
548        }
549        Ok(None)
550    }
551}
552impl JsonRetrieve for JsonObject {
553    fn parse(key: String, value: Option<&String>) -> Result<Self, JsonParseError> {
554        Ok(JsonObject::from_string(
555            value.ok_or(JsonParseError::NotFound(key))?,
556        ))
557    }
558}
559impl JsonRetrieve for JsonArray {
560    fn parse(key: String, value: Option<&String>) -> Result<Self, JsonParseError> {
561        Ok(JsonArray::from_string(
562            value.ok_or(JsonParseError::NotFound(key))?,
563        ))
564    }
565}
566impl<T: FromJson> JsonRetrieve for T {
567    fn parse(key: String, value: Option<&String>) -> Result<Self, JsonParseError> {
568        Self::from_json(&JsonObject::from_string(
569            value.ok_or(JsonParseError::NotFound(key))?,
570        ))
571    }
572}
573
574impl JsonRetrieve for Uuid {
575    fn parse(key: String, value: Option<&String>) -> Result<Self, JsonParseError> {
576        let val = value.ok_or_else(|| JsonParseError::NotFound(key.clone()))?;
577        let string_val = val[1..val.len() - 1].replace("\\\"", "\"").to_string();
578        Uuid::from_str(&string_val).map_err(|_| JsonParseError::InvalidType(key, "UUID"))
579    }
580}
581impl ToJson for Uuid {
582    fn to_json(&self) -> String {
583        format!("\"{}\"", self)
584    }
585}
586
587impl JsonRetrieve for DateTime<Utc> {
588    fn parse(key: String, value: Option<&String>) -> Result<Self, JsonParseError> {
589        if let Some(v) = value {
590            Ok(DateTime::parse_from_rfc3339(&v.replace('\"', ""))
591                .map_err(|_| JsonParseError::InvalidType(key, "RFC3339 Date"))?
592                .with_timezone(&Utc))
593        } else {
594            Err(JsonParseError::NotFound(key))
595        }
596    }
597}
598
599impl ToJson for DateTime<Utc> {
600    fn to_json(&self) -> String {
601        format!("\"{}\"", self.to_rfc3339())
602    }
603}