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