reproto_derive/
json.rs

1use Opaque;
2use core;
3use core::errors::Result;
4use format;
5use linked_hash_map::LinkedHashMap;
6use serde_json as json;
7use sir::{FieldSir, Sir};
8use utils::is_datetime;
9
10#[derive(Debug)]
11pub struct Json;
12
13impl format::Format for Json {
14    fn decode(&self, object: &core::Source) -> Result<Sir> {
15        let mut der = json::Deserializer::from_reader(object.read()?).into_iter::<json::Value>();
16
17        let value: Result<json::Value> = der.next()
18            .ok_or_else(|| format!("Expected at least one JSON value").into())
19            .and_then(|v| v.map_err(|e| format!("Bad JSON: {}", e).into()));
20
21        let value = value?;
22        let sir = from_json(&value)?;
23
24        Ok(sir)
25    }
26}
27
28impl format::Object for json::Map<String, json::Value> {
29    type Value = json::Value;
30
31    fn get(&self, key: &str) -> Option<&Self::Value> {
32        self.get(key)
33    }
34}
35
36impl format::Value for json::Value {
37    fn as_object(&self) -> Option<&format::Object<Value = Self>> {
38        match *self {
39            json::Value::Object(ref object) => Some(object as &format::Object<Value = Self>),
40            _ => None,
41        }
42    }
43
44    fn as_str(&self) -> Option<&str> {
45        match *self {
46            json::Value::String(ref string) => Some(string),
47            _ => None,
48        }
49    }
50}
51
52/// Calculate fingerprint from JSON value.
53fn from_json(value: &json::Value) -> Result<Sir> {
54    let f = match *value {
55        json::Value::Number(ref number) if number.is_u64() => {
56            let number = number
57                .as_u64()
58                .ok_or_else(|| format!("Expected u64, got: {}", number))?;
59
60            Sir::U64(Opaque::new(vec![number]))
61        }
62        json::Value::Number(ref number) if number.is_i64() => {
63            let number = number
64                .as_i64()
65                .ok_or_else(|| format!("Expected i64, got: {}", number))?;
66
67            Sir::I64(Opaque::new(vec![number]))
68        }
69        json::Value::Number(ref number) => {
70            // Find best representation, float or double.
71
72            let number = number
73                .as_f64()
74                .ok_or_else(|| format!("Expected f64, got: {}", number))?;
75
76            let diff = (((number as f32) as f64) - number).abs();
77
78            if diff != 0f64 {
79                Sir::Double
80            } else {
81                Sir::Float
82            }
83        }
84        json::Value::Bool(_) => Sir::Boolean,
85        json::Value::String(ref string) => {
86            if is_datetime(string) {
87                Sir::DateTime(Opaque::new(vec![string.to_string()]))
88            } else {
89                Sir::String(Opaque::new(vec![string.to_string()]))
90            }
91        }
92        json::Value::Null => Sir::Any,
93        json::Value::Array(ref array) => Sir::process_array(&array, from_json)?,
94        json::Value::Object(ref map) => {
95            let mut entries = LinkedHashMap::new();
96
97            for (key, value) in map {
98                let value = from_json(value)?;
99
100                let field = FieldSir {
101                    optional: value == Sir::Any,
102                    field: value,
103                };
104
105                entries.insert(key.to_string(), field);
106            }
107
108            Sir::Object(entries)
109        }
110    };
111
112    return Ok(f);
113}