jmap_tools/json/
value.rs

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