indradb/models/
json.rs

1use std::cmp::Ordering;
2use std::convert::TryFrom;
3use std::hash::{Hash, Hasher};
4use std::ops::Deref;
5use std::str::FromStr;
6use std::sync::Arc;
7
8use serde::{Deserialize, Deserializer, Serialize, Serializer};
9
10/// Similar to `serde_json::json!`, this allows you to create JSON literals.
11/// It's called `ijson` to not conflict with `serde_json::json!`.
12#[macro_export]
13macro_rules! ijson {
14    ($($json:tt)+) => {
15        $crate::Json::new(serde_json::json!($($json)+))
16    }
17}
18
19fn hash<H: Hasher>(value: &serde_json::Value, state: &mut H) {
20    match value {
21        serde_json::Value::Null => {
22            state.write_u8(0);
23        }
24        serde_json::Value::Bool(v) => {
25            state.write_u8(1);
26            v.hash(state);
27        }
28        serde_json::Value::Number(v) => {
29            state.write_u8(2);
30            if v.is_i64() {
31                v.as_i64().unwrap().hash(state);
32            } else if v.is_u64() {
33                v.as_u64().unwrap().hash(state);
34            } else {
35                // Note that there are 16m different NaN values, and they won't hash the same here
36                v.as_f64().unwrap().to_bits().hash(state);
37            }
38        }
39        serde_json::Value::String(v) => {
40            state.write_u8(3);
41            v.hash(state);
42        }
43        serde_json::Value::Array(v) => {
44            state.write_u8(4);
45            for sv in v {
46                hash(sv, state);
47            }
48        }
49        serde_json::Value::Object(v) => {
50            state.write_u8(5);
51            for (sk, sv) in v {
52                sk.hash(state);
53                hash(sv, state);
54            }
55        }
56    }
57}
58
59fn partial_cmp(first: &serde_json::Value, second: &serde_json::Value) -> Option<Ordering> {
60    match (first, second) {
61        (serde_json::Value::Null, serde_json::Value::Null) => Some(Ordering::Equal),
62        (serde_json::Value::Bool(v1), serde_json::Value::Bool(v2)) => v1.partial_cmp(v2),
63        (serde_json::Value::Number(v1), serde_json::Value::Number(v2)) => {
64            if v1.is_i64() {
65                let v1 = v1.as_i64().unwrap();
66                if v2.is_i64() {
67                    v1.partial_cmp(&v2.as_i64().unwrap())
68                } else if v2.is_u64() {
69                    match i64::try_from(v2.as_u64().unwrap()) {
70                        Ok(v2) => v1.partial_cmp(&v2),
71                        Err(_) => Some(Ordering::Less),
72                    }
73                } else {
74                    (v1 as f64).partial_cmp(&v2.as_f64().unwrap())
75                }
76            } else if v1.is_u64() {
77                let v1 = v1.as_u64().unwrap();
78                if v2.is_i64() {
79                    match u64::try_from(v2.as_i64().unwrap()) {
80                        Ok(v2) => v1.partial_cmp(&v2),
81                        Err(_) => Some(Ordering::Greater),
82                    }
83                } else if v2.is_u64() {
84                    v1.partial_cmp(&v2.as_u64().unwrap())
85                } else {
86                    (v1 as f64).partial_cmp(&v2.as_f64().unwrap())
87                }
88            } else {
89                let v1 = v1.as_f64().unwrap();
90                if v2.is_i64() {
91                    v1.partial_cmp(&(v2.as_i64().unwrap() as f64))
92                } else if v2.is_u64() {
93                    v1.partial_cmp(&(v2.as_u64().unwrap() as f64))
94                } else {
95                    v1.partial_cmp(&v2.as_f64().unwrap())
96                }
97            }
98        }
99        (serde_json::Value::String(v1), serde_json::Value::String(v2)) => v1.partial_cmp(v2),
100        (serde_json::Value::Array(v1), serde_json::Value::Array(v2)) => {
101            partial_cmp_by(v1.iter(), v2.iter(), partial_cmp)
102        }
103        (serde_json::Value::Object(v1), serde_json::Value::Object(v2)) => {
104            partial_cmp_by(v1.iter(), v2.iter(), |v1, v2| {
105                let (v1_key, v1_value) = v1;
106                let (v2_key, v2_value) = v2;
107                match v1_key.partial_cmp(v2_key) {
108                    Some(Ordering::Equal) => partial_cmp(v1_value, v2_value),
109                    non_eq => non_eq,
110                }
111            })
112        }
113        _ => None,
114    }
115}
116
117fn partial_cmp_by<I, F>(mut first: I, mut second: I, mut f: F) -> Option<Ordering>
118where
119    I: Iterator,
120    F: FnMut(I::Item, I::Item) -> Option<Ordering>,
121{
122    loop {
123        let x = match first.next() {
124            None => {
125                if second.next().is_none() {
126                    return Some(Ordering::Equal);
127                } else {
128                    return Some(Ordering::Less);
129                }
130            }
131            Some(val) => val,
132        };
133
134        let y = match second.next() {
135            None => return Some(Ordering::Greater),
136            Some(val) => val,
137        };
138
139        match f(x, y) {
140            Some(Ordering::Equal) => (),
141            non_eq => return non_eq,
142        }
143    }
144}
145
146/// Wraps `serde_json::Value` in an `Arc` to make it more cheaply cloneable, as
147/// well as implements extra traits useful for datastore storage and querying.
148#[derive(Clone, Eq, Debug)]
149pub struct Json(pub Arc<serde_json::Value>);
150
151impl Json {
152    /// Constructs a new JSON type.
153    ///
154    /// # Arguments
155    /// * `value`: The JSON value.
156    pub fn new(value: serde_json::Value) -> Self {
157        Self(Arc::new(value))
158    }
159}
160
161impl From<serde_json::Value> for Json {
162    fn from(value: serde_json::Value) -> Self {
163        Self(Arc::new(value))
164    }
165}
166
167impl From<Arc<serde_json::Value>> for Json {
168    fn from(value: Arc<serde_json::Value>) -> Self {
169        Self(value)
170    }
171}
172
173impl Hash for Json {
174    fn hash<H: Hasher>(&self, state: &mut H) {
175        hash(&self.0, state);
176    }
177}
178
179impl PartialEq for Json {
180    fn eq(&self, other: &Self) -> bool {
181        self.partial_cmp(other) == Some(Ordering::Equal)
182    }
183}
184
185impl PartialOrd for Json {
186    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
187        partial_cmp(&self.0, &other.0)
188    }
189}
190
191impl Deref for Json {
192    type Target = serde_json::Value;
193    fn deref(&self) -> &Self::Target {
194        &self.0
195    }
196}
197
198impl Serialize for Json {
199    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
200    where
201        S: Serializer,
202    {
203        (*self.0).serialize(serializer)
204    }
205}
206
207impl<'de> Deserialize<'de> for Json {
208    fn deserialize<D>(deserializer: D) -> Result<Json, D::Error>
209    where
210        D: Deserializer<'de>,
211    {
212        let v: serde_json::Value = Deserialize::deserialize(deserializer)?;
213        Ok(Json::new(v))
214    }
215}
216
217impl FromStr for Json {
218    type Err = serde_json::Error;
219
220    fn from_str(s: &str) -> Result<Self, Self::Err> {
221        let sj = serde_json::from_str(s)?;
222        Ok(Self::new(sj))
223    }
224}
225
226#[cfg(test)]
227mod tests {
228    use super::Json;
229    use std::collections::HashSet;
230
231    fn json_u64() -> Json {
232        Json::new(serde_json::Value::Number(serde_json::Number::from(u64::max_value())))
233    }
234
235    fn json_i64() -> Json {
236        Json::new(serde_json::Value::Number(serde_json::Number::from(i64::min_value())))
237    }
238
239    #[test]
240    fn should_hash() {
241        assert_eq!(HashSet::from([ijson!(null)]), HashSet::from([ijson!(null)]));
242        assert_eq!(HashSet::from([json_i64()]), HashSet::from([json_i64()]));
243        assert_eq!(HashSet::from([json_u64()]), HashSet::from([json_u64()]));
244        assert_eq!(HashSet::from([ijson!(3.0)]), HashSet::from([ijson!(3.0)]));
245        assert_eq!(HashSet::from([ijson!("foo")]), HashSet::from([ijson!("foo")]));
246        assert_eq!(HashSet::from([ijson!(["foo"])]), HashSet::from([ijson!(["foo"])]));
247        assert_eq!(
248            HashSet::from([ijson!({"foo": true})]),
249            HashSet::from([ijson!({"foo": true})])
250        );
251    }
252
253    #[test]
254    fn should_compare() {
255        assert!(ijson!("foo1") < ijson!("foo2"));
256        assert_eq!(ijson!(null), ijson!(null));
257        assert!(ijson!(true) > ijson!(false));
258        assert!(ijson!(3) < ijson!(4));
259        assert!(ijson!(3) < ijson!(4.0));
260        assert_eq!(ijson!(4.0), ijson!(4.0));
261        assert!(ijson!(3.0) < ijson!(4));
262        assert!(ijson!([3.0, 4.0]) < ijson!([4.0, 3.0]));
263
264        assert_eq!(json_u64(), json_u64());
265        assert!(ijson!(3) < json_u64());
266        assert!(json_u64() > ijson!(3.0));
267        assert!(ijson!(3.0) < json_u64());
268
269        assert!(json_u64() > json_i64());
270        assert!(json_i64() < json_u64());
271        assert!(ijson!(3) > json_i64());
272        assert!(json_i64() < ijson!(3.0));
273
274        assert!(ijson!({}) == ijson!({}));
275        assert!(ijson!({"key": "value0"}) < ijson!({"key": "value1"}));
276        assert!(ijson!({"key": "value1"}) > ijson!({"key": "value0"}));
277        assert!(ijson!({"key1": "value0"}) > ijson!({"key0": "value1"}));
278        assert_eq!(ijson!({"key": "value"}), ijson!({"key": "value"}));
279        assert!(ijson!({"key": "value"}) > ijson!({}));
280        assert!(ijson!({}) < ijson!({"key": "value"}));
281        assert!(ijson!({"key": "value"}) > ijson!({}));
282    }
283}