immutable_json/
object.rs

1use crate::api::{Number, Value};
2use crate::array::Array;
3use imbl::HashMap;
4use imbl::hashmap::Iter;
5use imbl::shared_ptr::DefaultSharedPtr;
6use crate::api::Number::{Decimal, Integer};
7
8#[derive(Clone, Debug)]
9pub struct Object {
10    map: HashMap<String, Value>,
11}
12
13impl Default for Object {
14    fn default() -> Self {
15        Self::new()
16    }
17}
18
19impl FromIterator<(String, Value)> for Object {
20    fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
21        let mut result = Object::new();
22
23        for i in iter {
24            result = result.add(&i.0, i.1);
25        }
26
27        result
28    }
29}
30
31impl<'a> IntoIterator for &'a Object {
32    type Item = (String, Value);
33    type IntoIter = ObjectIter<'a>;
34
35    fn into_iter(self) -> ObjectIter<'a> {
36        self.iter()
37    }
38}
39
40impl PartialEq for Object {
41    fn eq(&self, other: &Self) -> bool {
42        self.map == other.map
43    }
44}
45
46impl Object {
47    /// Adds a field to an object.
48    /// ```rust
49    /// # use immutable_json::api::Value::String;
50    /// # use immutable_json::object::Object;
51    /// # fn main() {
52    /// assert_eq!(Some("test".to_string()),
53    ///     Object::new().add("test", String("test".to_string())).get_string("test"));
54    /// # }
55    /// ```
56    pub fn add(&self, key: &str, value: Value) -> Self {
57        let mut new_map = self.map.clone();
58
59        new_map.insert(key.to_string(), value);
60        Object { map: new_map }
61    }
62
63    /// Adds a field to an object as an array.
64    /// ```rust
65    /// # use immutable_json::array::Array;
66    /// # use immutable_json::object::Object;
67    /// # fn main() {
68    /// assert_eq!(Some(1),
69    ///     Object::new()
70    ///         .add_array("test", Array::new().add_integer(1))
71    ///         .get_array("test").and_then(|a| a.get_integer(0).ok()?));
72    /// # }
73    /// ```
74    pub fn add_array(&self, key: &str, value: Array) -> Self {
75        self.add(key, Value::Array(value))
76    }
77
78    /// Adds a field to an object as a bool.
79    /// ```rust
80    /// # use immutable_json::object::Object;
81    /// # fn main() {
82    /// assert_eq!(Some(true), Object::new().add_bool("test", true).get_bool("test"));
83    /// # }
84    /// ```
85    pub fn add_bool(&self, key: &str, value: bool) -> Self {
86        self.add(key, Value::Bool(value))
87    }
88
89    /// Adds a field to an object as a decimal.
90    /// ```rust
91    /// # use immutable_json::object::Object;
92    /// # fn main() {
93    /// assert_eq!(Some(3.0), Object::new().add_decimal("test", 3.0).get_decimal("test"));
94    /// # }
95    /// ```
96    pub fn add_decimal(&self, key: &str, value: f64) -> Self {
97        self.add(key, Value::Number(Decimal(value)))
98    }
99
100    /// Adds a field to an object as an integer.
101    /// ```rust
102    /// # use immutable_json::object::Object;
103    /// # fn main() {
104    /// assert_eq!(Some(3), Object::new().add_integer("test", 3).get_integer("test"));
105    /// # }
106    /// ```
107    pub fn add_integer(&self, key: &str, value: i128) -> Self {
108        self.add(key, Value::Number(Integer(value)))
109    }
110
111    /// Adds a field to an object as a number.
112    /// ```rust
113    /// # use immutable_json::object::Object;
114    /// # use immutable_json::api::Number::Integer;
115    /// # fn main() {
116    /// assert_eq!(Some(3),
117    ///     Object::new()
118    ///         .add_number("test", Integer(3))
119    ///         .get_number("test").and_then(|n| n.as_integer()));
120    /// # }
121    /// ```
122    pub fn add_number(&self, key: &str, value: Number) -> Self {
123        self.add(key, Value::Number(value))
124    }
125
126    /// Adds a field to an object as an object.
127    /// ```rust
128    /// # use immutable_json::object::Object;
129    /// # use immutable_json::api::Number::Integer;
130    /// # fn main() {
131    /// assert_eq!(Some(1),
132    ///     Object::new()
133    ///         .add_object("test", Object::new().add_integer("test", 1))
134    ///         .get_object("test").and_then(|o| o.get_integer("test")));
135    /// # }
136    /// ```
137    pub fn add_object(&self, key: &str, value: Object) -> Self {
138        self.add(key, Value::Object(value))
139    }
140
141    /// Adds a field to an object as an integer.
142    /// ```rust
143    /// # use immutable_json::object::Object;
144    /// # fn main() {
145    /// assert_eq!(Some("test".to_string()),
146    ///     Object::new().add_string("test", "test").get_string("test"));
147    /// # }
148    /// ```
149    pub fn add_string(&self, key: &str, value: &str) -> Self {
150        self.add(key, Value::String(value.to_string()))
151    }
152
153    /// Returns a value from the object if it exists at the given key.
154    /// ```rust
155    /// # use immutable_json::object::Object;
156    /// # fn main() {
157    /// let object = Object::new().add_string("test1", "test");
158    ///
159    /// assert_eq!(Some("test".to_string()), object.get_string("test1"));
160    /// assert_eq!(None, object.get_string("test2"));
161    /// # }
162    /// ```
163    pub fn get(&self, key: &str) -> Option<&Value> {
164        self.map.get(&key.to_string())
165    }
166
167    /// Returns a value from the object if it exists at the given key and if it is an array.
168    /// ```rust
169    /// # use immutable_json::array::Array;
170    /// # use immutable_json::object::Object;
171    /// # fn main() {
172    /// let object = Object::new()
173    ///     .add_array("test1", Array::new().add_integer(3))
174    ///     .add_integer("test2", 3);
175    ///
176    /// assert_eq!(Some(3), object.get_array("test1").and_then(|a| a.get_integer(0).ok()?));
177    /// assert_eq!(None, object.get_array("test2"));
178    /// # }
179    /// ```
180    pub fn get_array(&self, key: &str) -> Option<Array> {
181        self.get(key).and_then(|v| v.as_array())
182    }
183
184    /// Returns a value from the object if it exists at the given key and if it is a bool.
185    /// ```rust
186    /// # use immutable_json::object::Object;
187    /// # fn main() {
188    /// let object = Object::new()
189    ///     .add_bool("test1", true)
190    ///     .add_integer("test2", 3);
191    ///
192    /// assert_eq!(Some(true), object.get_bool("test1"));
193    /// assert_eq!(None, object.get_string("test2"));
194    /// # }
195    /// ```
196    pub fn get_bool(&self, key: &str) -> Option<bool> {
197        self.get(key).and_then(|v| v.as_bool())
198    }
199
200    /// Returns a value from the object if it exists at the given key and if it is a decimal.
201    /// ```rust
202    /// # use immutable_json::object::Object;
203    /// # fn main() {
204    /// let object = Object::new()
205    ///     .add_decimal("test1", 3.0)
206    ///     .add_integer("test2", 3);
207    ///
208    /// assert_eq!(Some(3.0), object.get_decimal("test1"));
209    /// assert_eq!(None, object.get_string("test2"));
210    /// # }
211    /// ```
212    pub fn get_decimal(&self, key: &str) -> Option<f64> {
213        self.get(key).and_then(|v| v.as_decimal())
214    }
215
216    /// Returns a value from the object if it exists at the given key and if it is an integer.
217    /// ```rust
218    /// # use immutable_json::object::Object;
219    /// # fn main() {
220    /// let object = Object::new()
221    ///     .add_decimal("test1", 3.0)
222    ///     .add_integer("test2", 3);
223    ///
224    /// assert_eq!(Some(3.0), object.get_decimal("test1"));
225    /// assert_eq!(None, object.get_string("test2"));
226    /// # }
227    /// ```
228    pub fn get_integer(&self, key: &str) -> Option<i128> {
229        self.get(key).and_then(|v| v.as_integer())
230    }
231
232    /// Returns a value from the object if it exists at the given key and if it is a number.
233    /// ```rust
234    /// # use immutable_json::api::Number;
235    /// # use immutable_json::object::Object;
236    /// # fn main() {
237    /// let object = Object::new()
238    ///     .add_number("test1", Number::Decimal(3.0))
239    ///     .add_integer("test2", 3);
240    ///
241    /// assert_eq!(Some(3.0), object.get_number("test1").and_then(|n| n.as_decimal()));
242    /// assert_eq!(None, object.get_string("test2"));
243    /// # }
244    /// ```
245    pub fn get_number(&self, key: &str) -> Option<Number> {
246        self.get(key).and_then(|v| v.as_number())
247    }
248
249    /// Returns a value from the object if it exists at the given key and if it is an object.
250    /// ```rust
251    /// # use immutable_json::object::Object;
252    /// # fn main() {
253    /// let object = Object::new()
254    ///     .add_object("test1", Object::new().add_integer("test", 3))
255    ///     .add_integer("test2", 3);
256    ///
257    /// assert_eq!(Some(3), object.get_object("test1").and_then(|a| a.get_integer("test")));
258    /// assert_eq!(None, object.get_array("test2"));
259    /// # }
260    /// ```
261    pub fn get_object(&self, key: &str) -> Option<Object> {
262        self.get(key).and_then(|v| v.as_object())
263    }
264
265    /// Returns a value from the object if it exists at the given key and if it is a string.
266    /// ```rust
267    /// # use immutable_json::object::Object;
268    /// # fn main() {
269    /// let object = Object::new()
270    ///     .add_string("test1", "test")
271    ///     .add_integer("test2", 3);
272    ///
273    /// assert_eq!(Some("test".to_string()), object.get_string("test1"));
274    /// assert_eq!(None, object.get_string("test2"));
275    /// # }
276    /// ```
277    pub fn get_string(&self, key: &str) -> Option<String> {
278        self.get(key).and_then(|v| v.as_string())
279    }
280
281    /// Returns `true` if the object has a field with the given key.
282    /// ```rust
283    /// # use immutable_json::object::Object;
284    /// # fn main() {
285    /// let object = Object::new().add_string("test1", "test");
286    ///
287    /// assert_eq!(true, object.has_key("test1"));
288    /// assert_eq!(false, object.has_key("test2"));
289    /// # }
290    /// ```
291    pub fn has_key(&self, key: &str) -> bool {
292        self.map.contains_key(&key.to_string())
293    }
294
295    /// Returns an iterator over the key/value tuples of the object.
296    /// ```rust
297    /// # use immutable_json::object::Object;
298    /// # fn main() {
299    /// let object = Object::new().add_string("test1", "test1").add_integer("test2", 1);
300    ///
301    /// assert_eq!(object, Object::from_iter(object.iter()));
302    /// # }
303    /// ```
304    pub fn iter(&'_ self) -> ObjectIter<'_> {
305        ObjectIter {
306            iter: self.map.iter(),
307        }
308    }
309
310    pub fn new() -> Self {
311        Object {
312            map: HashMap::new(),
313        }
314    }
315
316    /// Removes the field with the given key from the object.
317    /// ```rust
318    /// # use immutable_json::object::Object;
319    /// # fn main() {
320    /// let object = Object::new().add_string("test", "test");
321    ///
322    /// assert_eq!(true, object.has_key("test"));
323    /// assert_eq!(false, object.remove("test").has_key("test"));
324    /// # }
325    /// ```
326    pub fn remove(&self, key: &str) -> Self {
327        let mut new_map = self.map.clone();
328
329        new_map.remove(&key.to_string());
330        Object { map: new_map }
331    }
332}
333
334#[derive(Clone)]
335pub struct ObjectIter<'a> {
336    iter: Iter<'a, String, Value, DefaultSharedPtr>,
337}
338
339impl<'a> Iterator for ObjectIter<'a> {
340    type Item = (String, Value);
341
342    fn next(&mut self) -> Option<Self::Item> {
343        self.iter.next().map(|i| (i.0.clone(), i.1.clone()))
344    }
345}