Skip to main content

immutable_json/
object.rs

1use crate::api::Number::{Decimal, Integer};
2use crate::api::{Number, Value};
3use crate::array::Array;
4use crate::pointer::JsonPointer;
5use imbl::HashMap;
6use imbl::hashmap::Iter;
7use imbl::shared_ptr::DefaultSharedPtr;
8use imbl_util::hashmap;
9use std::fmt::{Debug, Display, Formatter};
10use std::hash::{Hash, Hasher};
11
12/// Represents a JSON object.
13#[derive(Clone, Debug, Eq, PartialEq)]
14pub struct Object {
15    map: HashMap<String, Value>,
16}
17
18impl Default for Object {
19    fn default() -> Self {
20        Self::new()
21    }
22}
23
24impl Display for Object {
25    /**
26    Converts a JSON object to a string.
27    ```rust
28    # use immutable_json::api::Value;
29    # use immutable_json::error::Error;
30    # use std::str::FromStr;
31    # fn main() -> Result<(), Error>{
32    let data = r#"
33       {
34           "string": "string",
35           "int": 43,
36           "float": 5.8,
37           "boolean": true,
38           "object": {"test": "test"},
39           "array": [
40               "string",
41               1,
42               3.0,
43               false,
44               {"test": "test"},
45               [1]
46           ]
47       }"#;
48
49    let v: serde_json::Value = serde_json::from_str(data)?;
50
51    assert_eq!(Some(v), serde_json::from_str(&Value::from_str(data)?.to_string()).ok());
52    #   Ok(())
53    # }
54    ```
55    */
56    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
57        Display::fmt(&Value::Object(self.clone()), f)
58    }
59}
60
61impl FromIterator<(String, Value)> for Object {
62    /// Iterates over the key/value pairs of a JSON object.
63    fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
64        iter.into_iter()
65            .fold(Self::new(), |o, (k, v)| o.add(&k, &v))
66    }
67}
68
69impl Hash for Object {
70    fn hash<H: Hasher>(&self, state: &mut H) {
71        self.map.iter().for_each(|(k, v)| {
72            k.hash(state);
73            v.hash(state)
74        })
75    }
76}
77
78impl<'a> IntoIterator for &'a Object {
79    type Item = (String, Value);
80    type IntoIter = ObjectIter<'a>;
81
82    fn into_iter(self) -> ObjectIter<'a> {
83        self.iter()
84    }
85}
86
87impl Object {
88    /**
89    Adds a field to an object.
90    ```rust
91    # use immutable_json::api::Value::String;
92    # use immutable_json::object::Object;
93    # fn main() {
94    assert_eq!(Some("test".to_string()),
95        Object::new().add("test", &String("test".to_string())).get_string("test"));
96    # }
97    ```
98    */
99    pub fn add(&self, key: &str, value: &Value) -> Self {
100        Self {
101            map: hashmap::insert(&self.map, key.to_string(), value.clone()).0,
102        }
103    }
104
105    /**
106    Adds a field to an object as an array.
107    ```rust
108    # use immutable_json::array::Array;
109    # use immutable_json::object::Object;
110    # fn main() {
111    assert_eq!(Some(1),
112        Object::new()
113            .add_array("test", &Array::new().add_integer(1))
114            .get_array("test").and_then(|a| a.get_integer(0).ok()?));
115    # }
116    ```
117    */
118    pub fn add_array(&self, key: &str, value: &Array) -> Self {
119        self.add(key, &Value::Array(value.clone()))
120    }
121
122    pub fn add_array_p(&self, pointer: &str, value: &Array) -> Option<Self> {
123        self.add_p(pointer, &Value::Array(value.clone()))
124    }
125
126    /**
127    Adds a field to an object as a bool.
128    ```rust
129    # use immutable_json::object::Object;
130    # fn main() {
131    assert_eq!(Some(true), Object::new().add_bool("test", true).get_bool("test"));
132    # }
133    ```
134    */
135    pub fn add_bool(&self, key: &str, value: bool) -> Self {
136        self.add(key, &Value::Bool(value))
137    }
138
139    pub fn add_bool_p(&self, pointer: &str, value: bool) -> Option<Self> {
140        self.add_p(pointer, &Value::Bool(value))
141    }
142
143    /**
144    Adds a field to an object as a decimal.
145    ```rust
146    # use immutable_json::object::Object;
147    # fn main() {
148    assert_eq!(Some(3.0), Object::new().add_decimal("test", 3.0).get_decimal("test"));
149    # }
150    ```
151    */
152    pub fn add_decimal(&self, key: &str, value: f64) -> Self {
153        self.add(key, &Value::Number(Decimal(value)))
154    }
155
156    pub fn add_decimal_p(&self, pointer: &str, value: f64) -> Option<Self> {
157        self.add_p(pointer, &Value::Number(Number::Decimal(value)))
158    }
159
160    /**
161    Adds a field to an object as an integer.
162    ```rust
163    # use immutable_json::object::Object;
164    # fn main() {
165    assert_eq!(Some(3), Object::new().add_integer("test", 3).get_integer("test"));
166    # }
167    ```
168    */
169    pub fn add_integer(&self, key: &str, value: i128) -> Self {
170        self.add(key, &Value::Number(Integer(value)))
171    }
172
173    pub fn add_integer_p(&self, pointer: &str, value: i128) -> Option<Self> {
174        self.add_p(pointer, &Value::Number(Number::Integer(value)))
175    }
176
177    /**
178    Adds a field to an object as a number.
179    ```rust
180    # use immutable_json::object::Object;
181    # use immutable_json::api::Number::Integer;
182    # fn main() {
183    assert_eq!(Some(3),
184        Object::new()
185            .add_number("test", Integer(3))
186            .get_number("test").and_then(|n| n.as_integer()));
187    # }
188    ```
189    */
190    pub fn add_number(&self, key: &str, value: Number) -> Self {
191        self.add(key, &Value::Number(value))
192    }
193
194    pub fn add_number_p(&self, pointer: &str, value: Number) -> Option<Self> {
195        self.add_p(pointer, &Value::Number(value))
196    }
197
198    /**
199    Adds a field to an object as an object.
200    ```rust
201    # use immutable_json::object::Object;
202    # use immutable_json::api::Number::Integer;
203    # fn main() {
204    assert_eq!(Some(1),
205        Object::new()
206            .add_object("test", &Object::new().add_integer("test", 1))
207            .get_object("test").and_then(|o| o.get_integer("test")));
208    # }
209    ```
210    */
211    pub fn add_object(&self, key: &str, value: &Object) -> Self {
212        self.add(key, &Value::Object(value.clone()))
213    }
214
215    pub fn add_object_p(&self, pointer: &str, value: &Object) -> Option<Self> {
216        self.add_p(pointer, &Value::Object(value.clone()))
217    }
218
219    pub fn add_p(&self, pointer: &str, value: &Value) -> Option<Self> {
220        JsonPointer::add_pointer(pointer, &Value::Object(self.clone()), value)
221            .and_then(|v| v.as_object())
222    }
223
224    /**
225    Adds a field to an object as an integer.
226    ```rust
227    # use immutable_json::object::Object;
228    # fn main() {
229    assert_eq!(Some("test".to_string()),
230        Object::new().add_string("test", "test").get_string("test"));
231    # }
232    ```
233    */
234    pub fn add_string(&self, key: &str, value: &str) -> Self {
235        self.add(key, &Value::String(value.to_string()))
236    }
237
238    pub fn add_string_p(&self, pointer: &str, value: &str) -> Option<Self> {
239        self.add_p(pointer, &Value::String(value.to_string()))
240    }
241
242    /**
243    Returns a value from the object if it exists at the given key.
244    ```rust
245    # use immutable_json::object::Object;
246    # fn main() {
247    let object = Object::new().add_string("test1", "test");
248
249    assert_eq!(Some("test".to_string()), object.get_string("test1"));
250    assert_eq!(None, object.get_string("test2"));
251    # }
252    ```
253    */
254    pub fn get(&self, key: &str) -> Option<&Value> {
255        self.map.get(&key.to_string())
256    }
257
258    /**
259    Returns a value from the object if it exists at the given key and if it is an array.
260    Otherwise, `None` is returned.
261    ```rust
262    # use immutable_json::array::Array;
263    # use immutable_json::object::Object;
264    # fn main() {
265    let object = Object::new()
266        .add_array("test1", &Array::new().add_integer(3))
267        .add_integer("test2", 3);
268
269    assert_eq!(Some(3), object.get_array("test1").and_then(|a| a.get_integer(0).ok()?));
270    assert_eq!(None, object.get_array("test2"));
271    # }
272    ```
273    */
274    pub fn get_array(&self, key: &str) -> Option<Array> {
275        self.get(key).and_then(|v| v.as_array())
276    }
277
278    pub fn get_array_p(&self, pointer: &str) -> Option<Array> {
279        self.get_p(pointer).and_then(|v| v.as_array())
280    }
281
282    /**
283    Returns a value from the object if it exists at the given key and if it is a bool.
284    Otherwise, `None` is returned.
285    ```rust
286    # use immutable_json::object::Object;
287    # fn main() {
288    let object = Object::new()
289        .add_bool("test1", true)
290        .add_integer("test2", 3);
291
292    assert_eq!(Some(true), object.get_bool("test1"));
293    assert_eq!(None, object.get_string("test2"));
294    # }
295    ```
296    */
297    pub fn get_bool(&self, key: &str) -> Option<bool> {
298        self.get(key).and_then(|v| v.as_bool())
299    }
300
301    pub fn get_bool_p(&self, pointer: &str) -> Option<bool> {
302        self.get_p(pointer).and_then(|v| v.as_bool())
303    }
304
305    /**
306    Returns a value from the object if it exists at the given key and if it is a decimal.
307    Otherwise, `None` is returned.
308    ```rust
309    # use immutable_json::object::Object;
310    # fn main() {
311    let object = Object::new()
312        .add_decimal("test1", 3.0)
313        .add_integer("test2", 3);
314
315    assert_eq!(Some(3.0), object.get_decimal("test1"));
316    assert_eq!(None, object.get_string("test2"));
317    # }
318    ```
319    */
320    pub fn get_decimal(&self, key: &str) -> Option<f64> {
321        self.get(key).and_then(|v| v.as_decimal())
322    }
323
324    pub fn get_decimal_p(&self, pointer: &str) -> Option<f64> {
325        self.get_p(pointer).and_then(|v| v.as_decimal())
326    }
327
328    /**
329    Returns a value from the object if it exists at the given key and if it is an integer.
330    Otherwise, `None` is returned.
331    ```rust
332    # use immutable_json::object::Object;
333    # fn main() {
334    let object = Object::new()
335        .add_decimal("test1", 3.0)
336        .add_integer("test2", 3);
337
338    assert_eq!(Some(3.0), object.get_decimal("test1"));
339    assert_eq!(None, object.get_string("test2"));
340    # }
341    ```
342    */
343    pub fn get_integer(&self, key: &str) -> Option<i128> {
344        self.get(key).and_then(|v| v.as_integer())
345    }
346
347    pub fn get_integer_p(&self, pointer: &str) -> Option<i128> {
348        self.get_p(pointer).and_then(|v| v.as_integer())
349    }
350
351    /**
352    Returns a value from the object if it exists at the given key and if it is a number.
353    Otherwise, `None` is returned.
354    ```rust
355    # use immutable_json::api::Number;
356    # use immutable_json::object::Object;
357    # fn main() {
358    let object = Object::new()
359        .add_number("test1", Number::Decimal(3.0))
360        .add_integer("test2", 3);
361
362    assert_eq!(Some(3.0), object.get_number("test1").and_then(|n| n.as_decimal()));
363    assert_eq!(None, object.get_string("test2"));
364    # }
365    ```
366    */
367    pub fn get_number(&self, key: &str) -> Option<Number> {
368        self.get(key).and_then(|v| v.as_number())
369    }
370
371    pub fn get_number_p(&self, pointer: &str) -> Option<Number> {
372        self.get_p(pointer).and_then(|v| v.as_number())
373    }
374
375    /**
376    Returns a value from the object if it exists at the given key and if it is an object.
377    Otherwise, `None` is returned.
378    ```rust
379    # use immutable_json::object::Object;
380    # fn main() {
381    let object = Object::new()
382        .add_object("test1", &Object::new().add_integer("test", 3))
383        .add_integer("test2", 3);
384
385    assert_eq!(Some(3), object.get_object("test1").and_then(|a| a.get_integer("test")));
386    assert_eq!(None, object.get_array("test2"));
387    # }
388    ```
389    */
390    pub fn get_object(&self, key: &str) -> Option<Object> {
391        self.get(key).and_then(|v| v.as_object())
392    }
393
394    pub fn get_object_p(&self, pointer: &str) -> Option<Object> {
395        self.get_p(pointer).and_then(|v| v.as_object())
396    }
397
398    pub fn get_p(&self, pointer: &str) -> Option<Value> {
399        JsonPointer::get_pointer(pointer, &Value::Object(self.clone()))
400    }
401
402    /**
403    Returns a value from the object if it exists at the given key and if it is a string.
404    Otherwise, `None` is returned.
405    ```rust
406    # use immutable_json::object::Object;
407    # fn main() {
408    let object = Object::new()
409        .add_string("test1", "test")
410        .add_integer("test2", 3);
411
412    assert_eq!(Some("test".to_string()), object.get_string("test1"));
413    assert_eq!(None, object.get_string("test2"));
414    # }
415    ```
416    */
417    pub fn get_string(&self, key: &str) -> Option<String> {
418        self.get(key).and_then(|v| v.as_string())
419    }
420
421    pub fn get_string_p(&self, pointer: &str) -> Option<String> {
422        self.get_p(pointer).and_then(|v| v.as_string())
423    }
424
425    /**
426    Returns `true` if the object has a field with the given key.
427    ```rust
428    # use immutable_json::object::Object;
429    # fn main() {
430    let object = Object::new().add_string("test1", "test");
431
432    assert_eq!(true, object.has_key("test1"));
433    assert_eq!(false, object.has_key("test2"));
434    # }
435    ```
436    */
437    pub fn has_key(&self, key: &str) -> bool {
438        self.map.contains_key(&key.to_string())
439    }
440
441    /**
442    Returns an iterator over the key/value tuples of the object.
443    ```rust
444    # use immutable_json::object::Object;
445    # fn main() {
446    let object = Object::new().add_string("test1", "test1").add_integer("test2", 1);
447
448    assert_eq!(object, Object::from_iter(object.iter()));
449    # }
450    ```
451    */
452    pub fn iter(&'_ self) -> ObjectIter<'_> {
453        ObjectIter {
454            iter: self.map.iter(),
455        }
456    }
457
458    /**
459    Merges the other object into this one, overwriting existing entries.
460    ```rust
461    # use immutable_json::object::Object;
462    # fn main() {
463    let object = Object::new().add_string("test1", "test1").add_integer("test2", 1);
464    let other = Object::new().add_string("test1", "changed").add_integer("test3", 2);
465    let merged = Object::new().add_string("test1", "changed").add_integer("test2", 1).add_integer("test3", 2);
466
467    assert_eq!(merged, object.merge(&other));
468    # }
469    ```
470    */
471    pub fn merge(&self, other: &Object) -> Self {
472        Self {
473            map: hashmap::merge(&other.map, &self.map),
474        }
475    }
476
477    /// Create an empty JSON object.
478    pub fn new() -> Self {
479        Self {
480            map: HashMap::new(),
481        }
482    }
483
484    /**
485    Removes the field with the given key from the object.
486    ```rust
487    # use immutable_json::object::Object;
488    # fn main() {
489    let object = Object::new().add_string("test", "test");
490
491    assert_eq!(true, object.has_key("test"));
492    assert_eq!(false, object.remove("test").has_key("test"));
493    # }
494    ```
495    */
496    pub fn remove(&self, key: &str) -> Self {
497        Self {
498            map: hashmap::remove(&self.map, &key.to_string()).0,
499        }
500    }
501
502    pub fn remove_p(&self, pointer: &str) -> Option<Self> {
503        JsonPointer::remove_pointer(pointer, &Value::Object(self.clone()))
504            .and_then(|v| v.as_object())
505    }
506
507    /**
508    Sets a field to an object.
509    ```rust
510    # use immutable_json::api::Value::String;
511    # use immutable_json::object::Object;
512    # fn main() {
513    assert_eq!(Some("test".to_string()),
514        Object::new().set("test", &String("test".to_string())).get_string("test"));
515    # }
516    ```
517    */
518    pub fn set(&self, key: &str, value: &Value) -> Self {
519        Self {
520            map: self.map.update(key.to_string(), value.clone()),
521        }
522    }
523
524    /**
525    Sets a field to an object as an array.
526    ```rust
527    # use immutable_json::array::Array;
528    # use immutable_json::object::Object;
529    # fn main() {
530    assert_eq!(Some(1),
531        Object::new()
532            .set_array("test", &Array::new().add_integer(1))
533            .get_array("test").and_then(|a| a.get_integer(0).ok()?));
534    # }
535    ```
536    */
537    pub fn set_array(&self, key: &str, value: &Array) -> Self {
538        self.set(key, &Value::Array(value.clone()))
539    }
540
541    pub fn set_array_p(&self, pointer: &str, value: &Array) -> Option<Self> {
542        self.set_p(pointer, &Value::Array(value.clone()))
543    }
544
545    /**
546    Sets a field to an object as a bool.
547    ```rust
548    # use immutable_json::object::Object;
549    # fn main() {
550    assert_eq!(Some(true), Object::new().set_bool("test", true).get_bool("test"));
551    # }
552    ```
553    */
554    pub fn set_bool(&self, key: &str, value: bool) -> Self {
555        self.set(key, &Value::Bool(value))
556    }
557
558    pub fn set_bool_p(&self, pointer: &str, value: bool) -> Option<Self> {
559        self.set_p(pointer, &Value::Bool(value))
560    }
561
562    /**
563    Sets a field to an object as a decimal.
564    ```rust
565    # use immutable_json::object::Object;
566    # fn main() {
567    assert_eq!(Some(3.0), Object::new().set_decimal("test", 3.0).get_decimal("test"));
568    # }
569    ```
570    */
571    pub fn set_decimal(&self, key: &str, value: f64) -> Self {
572        self.set(key, &Value::Number(Decimal(value)))
573    }
574
575    pub fn set_decimal_p(&self, pointer: &str, value: f64) -> Option<Self> {
576        self.set_p(pointer, &Value::Number(Number::Decimal(value)))
577    }
578
579    /**
580    Sets a field to an object as an integer.
581    ```rust
582    # use immutable_json::object::Object;
583    # fn main() {
584    assert_eq!(Some(3), Object::new().set_integer("test", 3).get_integer("test"));
585    # }
586    ```
587    */
588    pub fn set_integer(&self, key: &str, value: i128) -> Self {
589        self.set(key, &Value::Number(Integer(value)))
590    }
591
592    pub fn set_integer_p(&self, pointer: &str, value: i128) -> Option<Self> {
593        self.set_p(pointer, &Value::Number(Number::Integer(value)))
594    }
595
596    /**
597    Sets a field to an object as a number.
598    ```rust
599    # use immutable_json::object::Object;
600    # use immutable_json::api::Number::Integer;
601    # fn main() {
602    assert_eq!(Some(3),
603        Object::new()
604            .set_number("test", Integer(3))
605            .get_number("test").and_then(|n| n.as_integer()));
606    # }
607    ```
608    */
609    pub fn set_number(&self, key: &str, value: Number) -> Self {
610        self.add(key, &Value::Number(value))
611    }
612
613    pub fn set_number_p(&self, pointer: &str, value: Number) -> Option<Self> {
614        self.add_p(pointer, &Value::Number(value))
615    }
616
617    /**
618    Sets a field to an object as an object.
619    ```rust
620    # use immutable_json::object::Object;
621    # use immutable_json::api::Number::Integer;
622    # fn main() {
623    assert_eq!(Some(1),
624        Object::new()
625            .set_object("test", &Object::new().add_integer("test", 1))
626            .get_object("test").and_then(|o| o.get_integer("test")));
627    # }
628    ```
629    */
630    pub fn set_object(&self, key: &str, value: &Object) -> Self {
631        self.set(key, &Value::Object(value.clone()))
632    }
633
634    pub fn set_object_p(&self, pointer: &str, value: &Object) -> Option<Self> {
635        self.set_p(pointer, &Value::Object(value.clone()))
636    }
637
638    pub fn set_p(&self, pointer: &str, value: &Value) -> Option<Self> {
639        JsonPointer::set_pointer(pointer, &Value::Object(self.clone()), value)
640            .and_then(|v| v.as_object())
641    }
642
643    /**
644    Sets a field to an object as an integer.
645    ```rust
646    # use immutable_json::object::Object;
647    # fn main() {
648    assert_eq!(Some("test".to_string()),
649        Object::new().set_string("test", "test").get_string("test"));
650    # }
651    ```
652    */
653    pub fn set_string(&self, key: &str, value: &str) -> Self {
654        self.set(key, &Value::String(value.to_string()))
655    }
656
657    pub fn set_string_p(&self, pointer: &str, value: &str) -> Option<Self> {
658        self.set_p(pointer, &Value::String(value.to_string()))
659    }
660}
661
662#[derive(Clone)]
663pub struct ObjectIter<'a> {
664    iter: Iter<'a, String, Value, DefaultSharedPtr>,
665}
666
667impl<'a> Iterator for ObjectIter<'a> {
668    type Item = (String, Value);
669
670    fn next(&mut self) -> Option<Self::Item> {
671        self.iter.next().map(|i| (i.0.clone(), i.1.clone()))
672    }
673}