jmap_tools/json/
value.rs

1use crate::json::index::Index;
2use crate::json::key::Key;
3use crate::json::num::{N, Number};
4pub use crate::json::object_vec::ObjectAsVec;
5use core::fmt;
6use core::hash::Hash;
7use std::borrow::Cow;
8use std::fmt::{Debug, Display};
9use std::str::FromStr;
10
11/// Represents any valid JMAP value.
12#[derive(Clone, Eq, PartialEq, Hash, Default)]
13pub enum Value<'ctx, P: Property, E: Element> {
14    #[default]
15    Null,
16    Bool(bool),
17    Number(Number),
18    Element(E),
19    Str(Cow<'ctx, str>),
20    Array(Vec<Value<'ctx, P, E>>),
21    Object(ObjectAsVec<'ctx, P, E>),
22}
23
24pub trait Property: Debug + Clone + PartialEq + Eq + PartialOrd + Ord + Hash {
25    fn try_parse(key: Option<&Key<'_, Self>>, value: &str) -> Option<Self>;
26    fn to_cow(&self) -> Cow<'static, str>;
27}
28
29pub trait Element: Clone + PartialEq + Eq + Hash + Debug + Sized {
30    type Property: Property;
31
32    fn try_parse<P>(key: &Key<'_, Self::Property>, value: &str) -> Option<Self>;
33    fn to_cow(&self) -> Cow<'_, str>;
34}
35
36impl<'ctx, P: Property, E: Element<Property = P>> Value<'ctx, P, E> {
37    pub fn new_boolean_set(set: impl IntoIterator<Item = (Key<'ctx, P>, bool)>) -> Self {
38        let mut obj = Vec::new();
39        for (key, value) in set {
40            obj.push((key, value.into()));
41        }
42        Value::Object(obj.into())
43    }
44
45    pub fn parse_json(json: &'ctx str) -> Result<Self, String> {
46        serde_json::from_str(json).map_err(|e| e.to_string())
47    }
48
49    /// Returns a reference to the value corresponding to the key.
50    #[inline]
51    pub fn get<I: Index<'ctx, P, E>>(&'ctx self, index: I) -> &'ctx Value<'ctx, P, E> {
52        index.index_into(self).unwrap_or(&Value::Null)
53    }
54
55    pub fn is_object_and_contains_key(&self, key: &Key<'_, P>) -> bool {
56        match self {
57            Value::Object(obj) => obj.contains_key(key),
58            _ => false,
59        }
60    }
61
62    pub fn is_object_and_contains_any_key(&self, keys: &[Key<'_, P>]) -> bool {
63        match self {
64            Value::Object(obj) => obj.contains_any_key(keys),
65            _ => false,
66        }
67    }
68
69    /// Returns true if `Value` is Value::Null.
70    pub fn is_null(&self) -> bool {
71        matches!(self, Value::Null)
72    }
73
74    /// Returns true if `Value` is Value::Array.
75    pub fn is_array(&self) -> bool {
76        matches!(self, Value::Array(_))
77    }
78
79    /// Returns true if `Value` is Value::Object.
80    pub fn is_object(&self) -> bool {
81        matches!(self, Value::Object(_))
82    }
83
84    /// Returns true if `Value` is Value::Bool.
85    pub fn is_bool(&self) -> bool {
86        matches!(self, Value::Bool(_))
87    }
88
89    /// Returns true if `Value` is Value::Number.
90    pub fn is_number(&self) -> bool {
91        matches!(self, Value::Number(_))
92    }
93
94    /// Returns true if `Value` is Value::Str.
95    pub fn is_string(&self) -> bool {
96        matches!(self, Value::Str(_))
97    }
98
99    /// Returns true if the Value is an integer between i64::MIN and i64::MAX.
100    /// For any Value on which is_i64 returns true, as_i64 is guaranteed to return the integer
101    /// value.
102    pub fn is_i64(&self) -> bool {
103        match self {
104            Value::Number(n) => n.is_i64(),
105            _ => false,
106        }
107    }
108
109    /// Returns true if the Value is an integer between zero and u64::MAX.
110    /// For any Value on which is_u64 returns true, as_u64 is guaranteed to return the integer
111    /// value.
112    pub fn is_u64(&self) -> bool {
113        match self {
114            Value::Number(n) => n.is_u64(),
115            _ => false,
116        }
117    }
118
119    /// Returns true if the Value is a f64 number.
120    pub fn is_f64(&self) -> bool {
121        match self {
122            Value::Number(n) => n.is_f64(),
123            _ => false,
124        }
125    }
126
127    /// If the Value is an Array, returns an iterator over the elements in the array.
128    pub fn iter_array(&self) -> Option<impl Iterator<Item = &Value<'_, P, E>>> {
129        match self {
130            Value::Array(arr) => Some(arr.iter()),
131            _ => None,
132        }
133    }
134
135    /// If the Value is an Object, returns an iterator over the elements in the object.
136    pub fn iter_object(&self) -> Option<impl Iterator<Item = (&Key<'_, P>, &Value<'_, P, E>)>> {
137        match self {
138            Value::Object(arr) => Some(arr.iter()),
139            _ => None,
140        }
141    }
142
143    /// If the Value is an Array, returns the associated Array. Returns None otherwise.
144    pub fn as_array(&self) -> Option<&[Value<'ctx, P, E>]> {
145        match self {
146            Value::Array(arr) => Some(arr),
147            _ => None,
148        }
149    }
150
151    pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value<'ctx, P, E>>> {
152        match self {
153            Value::Array(arr) => Some(arr),
154            _ => None,
155        }
156    }
157
158    pub fn into_array(self) -> Option<Vec<Value<'ctx, P, E>>> {
159        match self {
160            Value::Array(arr) => Some(arr),
161            _ => None,
162        }
163    }
164
165    /// If the Value is an Object, returns the associated Object. Returns None otherwise.
166    pub fn as_object(&self) -> Option<&ObjectAsVec<'ctx, P, E>> {
167        match self {
168            Value::Object(obj) => Some(obj),
169            _ => None,
170        }
171    }
172
173    pub fn as_object_mut(&mut self) -> Option<&mut ObjectAsVec<'ctx, P, E>> {
174        match self {
175            Value::Object(obj) => Some(obj),
176            _ => None,
177        }
178    }
179
180    pub fn into_object(self) -> Option<ObjectAsVec<'ctx, P, E>> {
181        match self {
182            Value::Object(obj) => Some(obj),
183            _ => None,
184        }
185    }
186
187    pub fn into_owned(self) -> Value<'static, P, E> {
188        match self {
189            Value::Null => Value::Null,
190            Value::Bool(b) => Value::Bool(b),
191            Value::Number(n) => Value::Number(n),
192            Value::Element(e) => Value::Element(e),
193            Value::Str(s) => Value::Str(Cow::Owned(s.into_owned())),
194            Value::Array(arr) => {
195                let owned_arr: Vec<Value<'static, P, E>> =
196                    arr.into_iter().map(|v| v.into_owned()).collect();
197                Value::Array(owned_arr)
198            }
199            Value::Object(obj) => Value::Object(
200                obj.into_vec()
201                    .into_iter()
202                    .map(|(k, v)| (k.into_owned(), v.into_owned()))
203                    .collect(),
204            ),
205        }
206    }
207
208    pub fn into_expanded_object(self) -> impl Iterator<Item = (Key<'ctx, P>, Value<'ctx, P, E>)> {
209        self.into_object()
210            .map(|obj| obj.into_vec())
211            .unwrap_or_default()
212            .into_iter()
213    }
214
215    pub fn into_expanded_boolean_set(self) -> impl Iterator<Item = (Key<'ctx, P>, bool)> {
216        self.into_object()
217            .map(|obj| obj.into_vec())
218            .unwrap_or_default()
219            .into_iter()
220            .filter_map(|(key, value)| value.as_bool().map(|b| (key, b)))
221    }
222
223    pub fn into_element(self) -> Option<E> {
224        match self {
225            Value::Element(element) => Some(element),
226            _ => None,
227        }
228    }
229
230    /// If the Value is a Boolean, returns the associated bool. Returns None otherwise.
231    pub fn as_bool(&self) -> Option<bool> {
232        match self {
233            Value::Bool(b) => Some(*b),
234            _ => None,
235        }
236    }
237
238    /// If the Value is a String, returns the associated str. Returns None otherwise.
239    pub fn as_str(&self) -> Option<Cow<'_, str>> {
240        match self {
241            Value::Str(text) => Some(text.as_ref().into()),
242            Value::Element(element) => Some(element.to_cow()),
243            _ => None,
244        }
245    }
246
247    pub fn into_string(self) -> Option<String> {
248        match self {
249            Value::Str(text) => Some(text.into_owned()),
250            Value::Element(element) => Some(element.to_cow().into_owned()),
251            _ => None,
252        }
253    }
254
255    /// If the Value is an integer, represent it as i64 if possible. Returns None otherwise.
256    pub fn as_i64(&self) -> Option<i64> {
257        match self {
258            Value::Number(n) => n.as_i64(),
259            _ => None,
260        }
261    }
262
263    /// If the Value is an integer, represent it as u64 if possible. Returns None otherwise.
264    pub fn as_u64(&self) -> Option<u64> {
265        match self {
266            Value::Number(n) => n.as_u64(),
267            _ => None,
268        }
269    }
270
271    /// If the Value is a number, represent it as f64 if possible. Returns None otherwise.
272    pub fn as_f64(&self) -> Option<f64> {
273        match self {
274            Value::Number(n) => n.as_f64(),
275            _ => None,
276        }
277    }
278}
279
280impl<P: Property, E: Element> From<bool> for Value<'_, P, E> {
281    fn from(val: bool) -> Self {
282        Value::Bool(val)
283    }
284}
285
286impl<'a, P: Property, E: Element> From<&'a str> for Value<'a, P, E> {
287    fn from(val: &'a str) -> Self {
288        Value::Str(Cow::Borrowed(val))
289    }
290}
291
292impl<P: Property, E: Element> From<String> for Value<'_, P, E> {
293    fn from(val: String) -> Self {
294        Value::Str(Cow::Owned(val))
295    }
296}
297
298impl<'x, P: Property, E: Element> From<Cow<'x, str>> for Value<'x, P, E> {
299    fn from(val: Cow<'x, str>) -> Self {
300        Value::Str(val)
301    }
302}
303
304impl<'a, P: Property, E: Element, T: Into<Value<'a, P, E>>> From<Vec<T>> for Value<'a, P, E> {
305    fn from(val: Vec<T>) -> Self {
306        Value::Array(val.into_iter().map(Into::into).collect())
307    }
308}
309
310impl<'a, P: Property, E: Element, T: Clone + Into<Value<'a, P, E>>> From<&[T]> for Value<'a, P, E> {
311    fn from(val: &[T]) -> Self {
312        Value::Array(val.iter().map(Clone::clone).map(Into::into).collect())
313    }
314}
315
316impl<P: Property, E: Element> Debug for Value<'_, P, E> {
317    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
318        match self {
319            Value::Null => formatter.write_str("Null"),
320            Value::Bool(boolean) => write!(formatter, "Bool({})", boolean),
321            Value::Number(number) => match number.n {
322                N::PosInt(n) => write!(formatter, "Number({:?})", n),
323                N::NegInt(n) => write!(formatter, "Number({:?})", n),
324                N::Float(n) => write!(formatter, "Number({:?})", n),
325            },
326            Value::Str(string) => write!(formatter, "Str({:?})", string),
327            Value::Array(vec) => {
328                formatter.write_str("Array ")?;
329                Debug::fmt(vec, formatter)
330            }
331            Value::Object(map) => {
332                formatter.write_str("Object ")?;
333                Debug::fmt(map, formatter)
334            }
335            Value::Element(element) => write!(formatter, "Element({})", element.to_cow()),
336        }
337    }
338}
339
340// We just convert to serde_json::Value to Display
341impl<P: Property, E: Element> Display for Value<'_, P, E> {
342    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343        write!(f, "{}", serde_json::Value::from(self.clone()))
344    }
345}
346
347impl<P: Property, E: Element> From<u64> for Value<'_, P, E> {
348    fn from(val: u64) -> Self {
349        Value::Number(val.into())
350    }
351}
352
353impl<P: Property, E: Element> From<i64> for Value<'_, P, E> {
354    fn from(val: i64) -> Self {
355        Value::Number(val.into())
356    }
357}
358
359impl<P: Property, E: Element> From<f64> for Value<'_, P, E> {
360    fn from(val: f64) -> Self {
361        Value::Number(val.into())
362    }
363}
364
365impl<P: Property, E: Element> From<Value<'_, P, E>> for serde_json::Value {
366    fn from(val: Value<'_, P, E>) -> Self {
367        match val {
368            Value::Null => serde_json::Value::Null,
369            Value::Bool(val) => serde_json::Value::Bool(val),
370            Value::Number(val) => serde_json::Value::Number(val.into()),
371            Value::Str(val) => serde_json::Value::String(val.to_string()),
372            Value::Array(vals) => {
373                serde_json::Value::Array(vals.into_iter().map(|val| val.into()).collect())
374            }
375            Value::Object(vals) => serde_json::Value::Object(vals.into()),
376            Value::Element(element) => serde_json::Value::String(element.to_cow().to_string()),
377        }
378    }
379}
380
381impl<P: Property, E: Element> From<&Value<'_, P, E>> for serde_json::Value {
382    fn from(val: &Value<'_, P, E>) -> Self {
383        match val {
384            Value::Null => serde_json::Value::Null,
385            Value::Bool(val) => serde_json::Value::Bool(*val),
386            Value::Number(val) => serde_json::Value::Number((*val).into()),
387            Value::Str(val) => serde_json::Value::String(val.to_string()),
388            Value::Array(vals) => {
389                serde_json::Value::Array(vals.iter().map(|val| val.into()).collect())
390            }
391            Value::Object(vals) => serde_json::Value::Object(vals.into()),
392            Value::Element(element) => serde_json::Value::String(element.to_cow().to_string()),
393        }
394    }
395}
396
397impl<'ctx, P: Property, E: Element> From<&'ctx serde_json::Value> for Value<'ctx, P, E> {
398    fn from(value: &'ctx serde_json::Value) -> Self {
399        match value {
400            serde_json::Value::Null => Value::Null,
401            serde_json::Value::Bool(b) => Value::Bool(*b),
402            serde_json::Value::Number(n) => {
403                if let Some(n) = n.as_i64() {
404                    Value::Number(n.into())
405                } else if let Some(n) = n.as_u64() {
406                    Value::Number(n.into())
407                } else if let Some(n) = n.as_f64() {
408                    Value::Number(n.into())
409                } else {
410                    unreachable!()
411                }
412            }
413            serde_json::Value::String(val) => Value::Str(Cow::Borrowed(val)),
414            serde_json::Value::Array(arr) => {
415                let out: Vec<Value<'ctx, P, E>> = arr.iter().map(|v| v.into()).collect();
416                Value::Array(out)
417            }
418            serde_json::Value::Object(obj) => {
419                let mut ans = ObjectAsVec(Vec::with_capacity(obj.len()));
420                for (k, v) in obj {
421                    ans.insert(Key::Borrowed(k.as_str()), v.into());
422                }
423                Value::Object(ans)
424            }
425        }
426    }
427}
428
429#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
430pub struct Null;
431
432impl Display for Null {
433    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
434        write!(f, "null")
435    }
436}
437
438impl AsRef<str> for Null {
439    fn as_ref(&self) -> &str {
440        "null"
441    }
442}
443
444impl FromStr for Null {
445    type Err = ();
446
447    fn from_str(_: &str) -> Result<Self, Self::Err> {
448        Err(())
449    }
450}
451
452impl Property for Null {
453    fn try_parse(_: Option<&Key<'_, Self>>, _: &str) -> Option<Self> {
454        None
455    }
456
457    fn to_cow(&self) -> Cow<'static, str> {
458        "".into()
459    }
460}
461
462impl Element for Null {
463    type Property = Null;
464
465    fn try_parse<P>(_: &Key<'_, Self::Property>, _: &str) -> Option<Self> {
466        None
467    }
468
469    fn to_cow(&self) -> Cow<'_, str> {
470        "".into()
471    }
472}
473
474#[cfg(test)]
475mod tests {
476    use std::io;
477
478    use super::*;
479
480    #[test]
481    fn from_serde() {
482        let value = &serde_json::json!({
483            "a": 1,
484            "b": "2",
485            "c": [3, 4],
486            "d": {"e": "alo"}
487        });
488
489        let value: Value<'_, Null, Null> = value.into();
490        assert_eq!(value.get("a"), &Value::Number(1i64.into()));
491        assert_eq!(value.get("b"), &Value::Str("2".into()));
492        assert_eq!(value.get("c").get(0), &Value::Number(3i64.into()));
493        assert_eq!(value.get("c").get(1), &Value::Number(4i64.into()));
494        assert_eq!(value.get("d").get("e"), &Value::Str("alo".into()));
495    }
496
497    #[test]
498    fn number_test() -> io::Result<()> {
499        let data = r#"{"val1": 123.5, "val2": 123, "val3": -123}"#;
500        let value: Value<'_, Null, Null> = serde_json::from_str(data)?;
501        assert!(value.get("val1").is_f64());
502        assert!(!value.get("val1").is_u64());
503        assert!(!value.get("val1").is_i64());
504
505        assert!(!value.get("val2").is_f64());
506        assert!(value.get("val2").is_u64());
507        assert!(value.get("val2").is_i64());
508
509        assert!(!value.get("val3").is_f64());
510        assert!(!value.get("val3").is_u64());
511        assert!(value.get("val3").is_i64());
512
513        assert!(value.get("val1").as_f64().is_some());
514        assert!(value.get("val2").as_f64().is_some());
515        assert!(value.get("val3").as_f64().is_some());
516
517        assert!(value.get("val1").as_u64().is_none());
518        assert!(value.get("val2").as_u64().is_some());
519        assert!(value.get("val3").as_u64().is_none());
520
521        assert!(value.get("val1").as_i64().is_none());
522        assert!(value.get("val2").as_i64().is_some());
523        assert!(value.get("val3").as_i64().is_some());
524
525        Ok(())
526    }
527}