json_node/models/
json_property_map.rs

1use std::ops::{Index, IndexMut};
2
3use crate::{models::JsonNode, errors::JsonNodeError};
4
5#[derive(Debug, Clone, PartialEq)]
6pub struct JsonPropertyMap(Vec<(String, JsonNode)>);
7
8impl JsonPropertyMap {
9    /// Create a new property map with no mappings.
10    pub fn new() -> Self {
11        Self(Vec::new())
12    }
13
14    /// Get the `JsonNode` associated with a name.
15    /// 
16    /// # Arguments
17    /// 
18    /// * `property_name` - The name of the property you want.
19    /// 
20    /// # Examples
21    /// 
22    /// ```
23    /// use json_node::{JsonNode, JsonPropertyMap};
24    /// 
25    /// // Create node with mappings.
26    /// let object_node = JsonNode::Object(JsonPropertyMap::from([
27    ///     ("name".to_owned(), JsonNode::String("John Doe".to_owned())),
28    ///     ("age".to_owned(), JsonNode::Integer(42)),
29    /// ]));
30    /// 
31    /// let map = object_node.as_object().unwrap(); // &JsonPropertyMap.
32    /// let property = map.get("name").unwrap(); // &JsonNode.
33    /// let name = property.as_string().unwrap(); // &str.
34    /// 
35    /// assert_eq!(name, "John Doe");
36    /// ```
37    pub fn get(&self, property_name: &str) -> Option<&JsonNode> {
38        self.0.iter()
39              .find(|(k, _)| k == property_name)
40              .map(|(_, v)| v)
41    }
42
43    /// Get the `JsonNode` associated with a name as a mutable value.
44    /// 
45    /// # Arguments
46    /// 
47    /// * `property_name` - The name of the property you want.
48    /// 
49    /// # Examples
50    /// 
51    /// ```
52    /// use json_node::{JsonNode, JsonPropertyMap};
53    /// 
54    /// // Create node with mappings.
55    /// let mut object_node = JsonNode::Object(JsonPropertyMap::from([
56    ///     ("name".to_owned(), JsonNode::String("John Doe".to_owned())),
57    ///     ("age".to_owned(), JsonNode::Integer(42)),
58    /// ]));
59    /// 
60    /// let mut_map = object_node.as_object_mut().unwrap(); // &mut JsonPropertyMap.
61    /// let mut_property = mut_map.get_mut("name").unwrap(); // &mut JsonNode.
62    /// let mut_name = mut_property.as_string_mut().unwrap(); // &mut str.
63    /// 
64    /// mut_name.make_ascii_uppercase(); // Mutates the string slice.
65    /// 
66    /// let map = object_node.as_object().unwrap(); // &JsonPropertyMap.
67    /// let property = map.get("name").unwrap(); // &JsonNode.
68    /// let name = property.as_string().unwrap(); // &String.
69    /// 
70    /// assert_eq!(name, "JOHN DOE");
71    /// ```
72    pub fn get_mut(&mut self, property_name: &str) -> Option<&mut JsonNode> {
73        self.0.iter_mut()
74              .find(|(k, _)| k == property_name)
75              .map(|(_, v)| v)
76    }
77
78    /// Adds a new mapping to the object.
79    /// 
80    /// # Arguments
81    /// 
82    /// * `property_name` - Name of the new property.
83    /// * `json_node` - The `JsonNode` to be associated with the `property_name`.
84    /// 
85    /// # Examples
86    /// 
87    /// ```
88    /// use json_node::{JsonNode, JsonPropertyMap};
89    /// 
90    /// let mut map = JsonPropertyMap::new();
91    /// 
92    /// map.add("number", JsonNode::Integer(42));
93    /// 
94    /// let expected = JsonPropertyMap::from([
95    ///     ("number".to_owned(), JsonNode::Integer(42))
96    /// ]);
97    /// 
98    /// assert_eq!(map, expected);
99    /// ```
100    pub fn add(&mut self, property_name: &str, json_node: JsonNode) {
101        if self.contains_property(&property_name) {
102            return;
103        }
104
105        self.0.push((property_name.to_owned(), json_node));
106    }
107
108    /// Removes a mapping from the object if it exists.
109    /// 
110    /// # Arguments
111    /// 
112    /// * `property_name` - Name of the property to be removed.
113    /// 
114    /// # Examples
115    /// 
116    /// ```
117    /// use json_node::{JsonNode, JsonPropertyMap};
118    /// 
119    /// let mut map = JsonPropertyMap::from([
120    ///     ("number".to_owned(), JsonNode::Integer(42))
121    /// ]);
122    /// 
123    /// map.remove("number");
124    /// 
125    /// let expected = JsonPropertyMap::new();
126    /// assert_eq!(map, expected);
127    /// ```
128    pub fn remove(&mut self, property_name: &str) -> crate::Result<JsonNode> {
129        if self.0.iter().filter(|(k, _)| k == property_name).count() > 1 {
130            return Err(JsonNodeError::MultiplePropertiesWithSameKey(property_name.to_string()))
131        }
132
133        self.0.iter()
134              .position(|(k, _)| k == property_name)
135              .map(|i| self.0.remove(i).1)
136              .ok_or(JsonNodeError::KeyNotFound(property_name.to_string()))
137    }
138
139    /// Checks if a property with the name `property_name` exists.
140    /// 
141    /// # Arguments
142    /// 
143    /// * `property_name` - The name to check for.
144    /// 
145    /// # Examples
146    /// 
147    /// ```
148    /// use json_node::{JsonNode, JsonPropertyMap};
149    /// 
150    /// let mut map = JsonPropertyMap::from([
151    ///     ("number".to_owned(), JsonNode::Integer(42))
152    /// ]);
153    /// 
154    /// assert!(map.contains_property("number"));
155    /// assert!(!map.contains_property("name"));
156    /// ```
157    pub fn contains_property(&self, property_name: &str) -> bool {
158        self.0.iter().any(|(k, _)| k == property_name)
159    }
160
161    /// Gets all property names in the object.
162    pub fn property_names(&self) -> Vec<&String> {
163        self.0.iter().map(|(k, _)| k).collect()
164    }
165
166    pub fn property_names_mut(&mut self) -> Vec<&mut String> {
167        self.0.iter_mut().map(|(k, _)| k).collect()
168    }
169
170    /// Gets all child nodes in the object.
171    pub fn nodes(&self) -> Vec<&JsonNode> {
172        self.0.iter().map(|(_, v)| v).collect()
173    }
174
175    /// Gets all child nodes in the object as mutable references.
176    pub fn nodes_mut(&mut self) -> Vec<&mut JsonNode> {
177        self.0.iter_mut().map(|(_, v)| v).collect()
178    }
179
180    /// Clears the map of all mappings.
181    pub fn clear(&mut self) {
182        self.0.clear();
183    }
184
185    /// Returns an iterator over the mappings represented as tuples.
186    pub fn iter(&self) -> std::slice::Iter<(String, JsonNode)> {
187        self.0.iter()
188    }
189
190    /// Returns an iterator over the mappings represented as tuples that allows modifying each element and its name.
191    pub fn iter_mut(&mut self) -> std::slice::IterMut<(String, JsonNode)> {
192        self.0.iter_mut()
193    }
194    
195    /// Returns the number of mappings in the object.
196    pub fn len(&self) -> usize {
197        self.0.len()
198    }
199
200    /// Returns true if the object has zero mappings.
201    pub fn is_empty(&self) -> bool {
202        self.len() == 0
203    }
204
205    /// Serialized the object as a JSON object string.
206    /// 
207    /// # Remarks
208    /// 
209    /// This function does zero formatting meaning the JSON string will have no spaces or new-lines.
210    pub fn to_json_string(&self) -> String {
211        let mut result = "{".to_string();
212
213        for (key, value) in &self.0 {
214            result.push_str(&format!("\"{}\":{},", key, value.to_json_string()));
215        }
216
217        result.pop(); // Pops the trailing comma
218        result.push('}');
219
220        result
221    }
222}
223
224impl Index<usize> for JsonPropertyMap {
225    type Output = (String, JsonNode);
226
227    fn index(&self, index: usize) -> &Self::Output {
228        &self.0[index]
229    }
230}
231
232impl IndexMut<usize> for JsonPropertyMap {
233    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
234        &mut self.0[index]
235    }
236}
237
238impl FromIterator<(String, JsonNode)> for JsonPropertyMap {
239    fn from_iter<T: IntoIterator<Item = (String, JsonNode)>>(iter: T) -> Self {
240        Self(iter.into_iter().collect())
241    }
242}
243
244impl From<Vec<(String, JsonNode)>> for JsonPropertyMap {
245    fn from(value: Vec<(String, JsonNode)>) -> Self {
246        Self(value)
247    }
248}
249
250impl<const COUNT: usize> From<[(String, JsonNode); COUNT]> for JsonPropertyMap {
251    fn from(value: [(String, JsonNode); COUNT]) -> Self {
252        Self(value.to_vec())
253    }
254}
255
256#[cfg(test)]
257mod tests {
258    #[test]
259    fn get_mut() {
260        use crate::{JsonNode, JsonPropertyMap};
261        
262        // Create node with mappings.
263        let mut object_node = JsonNode::Object(JsonPropertyMap::from([
264            ("name".to_owned(), JsonNode::String("John Doe".to_owned())),
265            ("age".to_owned(), JsonNode::Integer(42)),
266        ]));
267        
268        let mut_map = object_node.as_object_mut().unwrap(); // &mut JsonPropertyMap.
269        let mut_property = mut_map.get_mut("name").unwrap(); // &mut JsonNode.
270        let mut_name = mut_property.as_string_mut().unwrap(); // &mut JsonValue.
271
272        mut_name.make_ascii_uppercase(); // Mutates the string slice.
273
274        let map = object_node.as_object().unwrap(); // &JsonPropertyMap.
275        let property = map.get("name").unwrap(); // &JsonNode.
276        let name = property.as_string().unwrap(); // &JsonValue.
277        
278        assert_eq!(name, "JOHN DOE");
279    }
280}