platform_value/
value_map.rs

1use crate::{Error, Value};
2use indexmap::IndexMap;
3use std::cmp::Ordering;
4use std::collections::BTreeMap;
5
6pub type ValueMap = Vec<(Value, Value)>;
7
8pub trait ValueMapHelper {
9    fn sort_by_keys(&mut self);
10    fn sort_by_keys_and_inner_maps(&mut self);
11    fn sort_by_lexicographical_byte_ordering_keys(&mut self);
12    fn sort_by_lexicographical_byte_ordering_keys_and_inner_maps(&mut self);
13    fn get_key(&self, search_key: &str) -> Result<&Value, Error>;
14    fn get_optional_key(&self, key: &str) -> Option<&Value>;
15    fn get_key_mut(&mut self, search_key: &str) -> Result<&mut Value, Error>;
16    fn get_optional_key_mut(&mut self, key: &str) -> Option<&mut Value>;
17    fn get_key_mut_or_insert(&mut self, key: &str, value: Value) -> &mut Value;
18    fn get_key_by_value_mut_or_insert(&mut self, search_key: &Value, value: Value) -> &mut Value;
19    fn insert_string_key_value(&mut self, key: String, value: Value);
20    fn remove_key(&mut self, search_key: &str) -> Result<Value, Error>;
21    fn remove_optional_key(&mut self, key: &str) -> Option<Value>;
22    fn remove_optional_key_if_null(&mut self, search_key: &str);
23    fn remove_optional_key_if_empty_array(&mut self, search_key: &str);
24    fn remove_optional_key_value(&mut self, search_key_value: &Value) -> Option<Value>;
25    fn from_btree_map<K: Into<Value> + Ord, V: Into<Value>>(btree_map: BTreeMap<K, V>) -> Self;
26}
27
28impl ValueMapHelper for ValueMap {
29    fn sort_by_keys(&mut self) {
30        self.sort_by(|(key1, _), (key2, _)| key1.partial_cmp(key2).unwrap_or(Ordering::Less));
31    }
32
33    fn sort_by_keys_and_inner_maps(&mut self) {
34        self.sort_by_keys();
35        self.iter_mut().for_each(|(_, v)| {
36            if let Value::Map(m) = v {
37                m.sort_by_keys_and_inner_maps()
38            }
39        });
40    }
41
42    fn sort_by_lexicographical_byte_ordering_keys(&mut self) {
43        self.sort_by(|(key1, _), (key2, _)| {
44            if key1.is_text() && key2.is_text() {
45                let key1 = key1.to_text().unwrap();
46                let key2 = key2.to_text().unwrap();
47                match key1.len().cmp(&key2.len()) {
48                    Ordering::Less => Ordering::Less,
49                    Ordering::Equal => key1.cmp(&key2),
50                    Ordering::Greater => Ordering::Greater,
51                }
52            } else {
53                key1.partial_cmp(key2).unwrap_or(Ordering::Less)
54            }
55        })
56    }
57
58    fn sort_by_lexicographical_byte_ordering_keys_and_inner_maps(&mut self) {
59        self.sort_by_lexicographical_byte_ordering_keys();
60        self.iter_mut().for_each(|(_, v)| {
61            if let Value::Map(m) = v {
62                m.sort_by_lexicographical_byte_ordering_keys_and_inner_maps()
63            }
64        });
65    }
66
67    fn get_key(&self, search_key: &str) -> Result<&Value, Error> {
68        self.get_optional_key(search_key)
69            .ok_or(Error::StructureError(format!(
70                "required property not found {search_key}"
71            )))
72    }
73
74    fn get_optional_key(&self, search_key: &str) -> Option<&Value> {
75        self.iter().find_map(|(key, value)| {
76            if let Value::Text(text) = key {
77                if text == search_key {
78                    Some(value)
79                } else {
80                    None
81                }
82            } else {
83                None
84            }
85        })
86    }
87
88    fn get_key_mut(&mut self, search_key: &str) -> Result<&mut Value, Error> {
89        self.get_optional_key_mut(search_key)
90            .ok_or(Error::StructureError(format!(
91                "{search_key} not found, but was required"
92            )))
93    }
94
95    fn get_optional_key_mut(&mut self, search_key: &str) -> Option<&mut Value> {
96        self.iter_mut().find_map(|(key, value)| {
97            if let Value::Text(text) = key {
98                if text == search_key {
99                    Some(value)
100                } else {
101                    None
102                }
103            } else {
104                None
105            }
106        })
107    }
108
109    fn get_key_mut_or_insert(&mut self, search_key: &str, value: Value) -> &mut Value {
110        let found = self.iter().position(|(key, _)| {
111            if let Value::Text(text) = key {
112                text == search_key
113            } else {
114                false
115            }
116        });
117        match found {
118            None => {
119                self.push((Value::Text(search_key.to_string()), value));
120                let (_, value) = self.last_mut().unwrap();
121                value
122            }
123            Some(pos) => {
124                let (_, value) = self.get_mut(pos).unwrap();
125                value
126            }
127        }
128    }
129
130    fn get_key_by_value_mut_or_insert(&mut self, search_key: &Value, value: Value) -> &mut Value {
131        let found = self.iter().position(|(key, _)| search_key == key);
132        match found {
133            None => {
134                self.push((search_key.clone(), value));
135                let (_, value) = self.last_mut().unwrap();
136                value
137            }
138            Some(pos) => {
139                let (_, value) = self.get_mut(pos).unwrap();
140                value
141            }
142        }
143    }
144
145    fn insert_string_key_value(&mut self, key: String, value: Value) {
146        self.push((key.into(), value))
147    }
148
149    fn remove_key(&mut self, search_key: &str) -> Result<Value, Error> {
150        self.iter()
151            .position(|(key, _)| {
152                if let Value::Text(text) = key {
153                    text == search_key
154                } else {
155                    false
156                }
157            })
158            .map(|pos| self.remove(pos).1)
159            .ok_or(Error::StructureError(format!(
160                "trying to remove a key {} from a ValueMap that was not found",
161                search_key
162            )))
163    }
164
165    fn remove_optional_key(&mut self, search_key: &str) -> Option<Value> {
166        self.iter()
167            .position(|(key, _)| {
168                if let Value::Text(text) = key {
169                    text == search_key
170                } else {
171                    false
172                }
173            })
174            .map(|pos| self.remove(pos).1)
175    }
176
177    fn remove_optional_key_if_null(&mut self, search_key: &str) {
178        self.iter()
179            .position(|(key, value)| {
180                if let Value::Text(text) = key {
181                    if text == search_key {
182                        value.is_null()
183                    } else {
184                        false
185                    }
186                } else {
187                    false
188                }
189            })
190            .map(|pos| self.remove(pos).1);
191    }
192
193    fn remove_optional_key_if_empty_array(&mut self, search_key: &str) {
194        self.iter()
195            .position(|(key, value)| {
196                if let Value::Text(text) = key {
197                    if text == search_key {
198                        if let Some(v) = value.as_array() {
199                            v.is_empty()
200                        } else {
201                            false
202                        }
203                    } else {
204                        false
205                    }
206                } else {
207                    false
208                }
209            })
210            .map(|pos| self.remove(pos).1);
211    }
212
213    fn remove_optional_key_value(&mut self, search_key_value: &Value) -> Option<Value> {
214        self.iter()
215            .position(|(key, _)| search_key_value == key)
216            .map(|pos| self.remove(pos).1)
217    }
218    fn from_btree_map<K: Into<Value> + Ord, V: Into<Value>>(btree_map: BTreeMap<K, V>) -> Self {
219        btree_map
220            .into_iter()
221            .map(|(k, v)| (k.into(), v.into()))
222            .collect()
223    }
224}
225
226impl Value {
227    /// If the `Value` is a `Map`, returns a the associated `BTreeMap<String, Value>` data as `Ok`.
228    /// Returns `Err(Error::Structure("reason"))` otherwise.
229    ///
230    /// ```
231    /// # use std::collections::BTreeMap;
232    /// # use platform_value::{Error, Value};
233    /// #
234    /// let mut value = Value::Map(
235    ///     vec![
236    ///         (Value::Text(String::from("key")), Value::Float(18.)),
237    ///     ]
238    /// );
239    /// assert_eq!(value.into_btree_string_map(), Ok(BTreeMap::from([(String::from("key"), Value::Float(18.))])));
240    ///
241    /// let value = Value::Bool(true);
242    /// assert_eq!(value.into_btree_string_map(), Err(Error::StructureError("value is not a map".to_string())))
243    /// ```
244    pub fn into_btree_string_map(self) -> Result<BTreeMap<String, Value>, Error> {
245        Self::map_into_btree_string_map(self.into_map()?)
246    }
247
248    /// If the `Value` is a `Map`, returns a the associated `BTreeMap<String, Value>` data as `Ok`.
249    /// Returns `Err(Error::Structure("reason"))` otherwise.
250    ///
251    /// ```
252    /// # use std::collections::BTreeMap;
253    /// # use platform_value::{Error, Value};
254    /// #
255    /// let mut value = Value::Map(
256    ///     vec![
257    ///         (Value::Text(String::from("key")), Value::Float(18.)),
258    ///     ]
259    /// );
260    /// assert_eq!(value.to_btree_ref_string_map(), Ok(BTreeMap::from([(String::from("key"), &Value::Float(18.))])));
261    ///
262    /// let value = Value::Bool(true);
263    /// assert_eq!(value.to_btree_ref_string_map(), Err(Error::StructureError("value is not a map".to_string())))
264    /// ```
265    pub fn to_btree_ref_string_map(&self) -> Result<BTreeMap<String, &Value>, Error> {
266        Self::map_ref_into_btree_string_map(self.to_map_ref()?)
267    }
268
269    /// If the `Value` is a `Map`, returns a the associated `BTreeMap<String, Value>` data as `Ok`.
270    /// Returns `Err(Error::Structure("reason"))` otherwise.
271    ///
272    /// ```
273    /// # use std::collections::BTreeMap;
274    /// # use platform_value::{Error, Value};
275    /// #
276    /// let mut value = Value::Map(
277    ///     vec![
278    ///         (Value::Text(String::from("key")), Value::Float(18.)),
279    ///     ]
280    /// );
281    /// assert_eq!(value.to_ref_string_map::<BTreeMap<_,_>>(), Ok(BTreeMap::from([(String::from("key"), &Value::Float(18.))])));
282    ///
283    /// assert_eq!(value.to_ref_string_map::<Vec<(_,_)>>(), Ok(vec![(String::from("key"), &Value::Float(18.))]));
284    ///
285    /// let value = Value::Bool(true);
286    /// assert_eq!(value.to_ref_string_map::<Vec<(_,_)>>(), Err(Error::StructureError("value is not a map".to_string())))
287    /// ```
288    pub fn to_ref_string_map<'a, I: FromIterator<(String, &'a Value)>>(
289        &'a self,
290    ) -> Result<I, Error> {
291        Self::map_ref_into_string_map(self.to_map_ref()?)
292    }
293
294    /// If the `Value` is a `Map`, returns a the associated `BTreeMap<String, Value>` data as `Ok`.
295    /// Returns `Err(Error::Structure("reason"))` otherwise.
296    ///
297    /// ```
298    /// # use std::collections::BTreeMap;
299    /// # use platform_value::{Error, Value};
300    /// #
301    /// let mut value = Value::Map(
302    ///     vec![
303    ///         (Value::Text(String::from("key")), Value::Float(18.)),
304    ///     ]
305    /// );
306    /// assert_eq!(value.to_ref_string_map_mut::<BTreeMap<_,_>>(), Ok(BTreeMap::from([(String::from("key"), &mut Value::Float(18.))])));
307    ///
308    /// assert_eq!(value.to_ref_string_map_mut::<Vec<(_,_)>>(), Ok(vec![(String::from("key"), &mut Value::Float(18.))]));
309    ///
310    /// let mut value = Value::Bool(true);
311    /// assert_eq!(value.to_ref_string_map_mut::<Vec<(_,_)>>(), Err(Error::StructureError("value is not a map".to_string())))
312    /// ```
313    pub fn to_ref_string_map_mut<'a, I: FromIterator<(String, &'a mut Value)>>(
314        &'a mut self,
315    ) -> Result<I, Error> {
316        Self::map_mut_ref_into_string_map(self.as_map_mut_ref()?)
317    }
318
319    /// Takes a ValueMap which is a `Vec<(Value, Value)>`
320    /// Returns a BTreeMap<String, Value> as long as each Key is a String
321    /// Returns `Err(Error::Structure("reason"))` otherwise.
322    pub fn map_into_btree_string_map(map: ValueMap) -> Result<BTreeMap<String, Value>, Error> {
323        map.into_iter()
324            .map(|(key, value)| {
325                let key = key
326                    .into_text()
327                    .map_err(|_| Error::StructureError("expected key to be string".to_string()))?;
328                Ok((key, value))
329            })
330            .collect::<Result<BTreeMap<String, Value>, Error>>()
331    }
332
333    /// Takes a ref to a ValueMap which is a `&Vec<(Value, Value)>`
334    /// Returns a BTreeMap<String, &Value> as long as each Key is a String
335    /// Returns `Err(Error::Structure("reason"))` otherwise.
336    pub fn map_ref_into_btree_string_map(
337        map: &ValueMap,
338    ) -> Result<BTreeMap<String, &Value>, Error> {
339        map.iter()
340            .map(|(key, value)| {
341                let key = key
342                    .to_text()
343                    .map_err(|_| Error::StructureError("expected key to be string".to_string()))?;
344                Ok((key, value))
345            })
346            .collect::<Result<BTreeMap<String, &Value>, Error>>()
347    }
348
349    /// Takes a ref to a ValueMap which is a `&Vec<(Value, Value)>`
350    /// Also takes a sort_key
351    /// Returns a IndexMap<String, &Value> as long as each Key is a String
352    /// The index map is in the order sorted by the sort key
353    /// The type T is the type of the value of the sort key
354    /// Returns `Err(Error::Structure("reason"))` otherwise.
355    pub fn map_ref_into_indexed_string_map<'a, T>(
356        map: &'a ValueMap,
357        sort_key: &str,
358    ) -> Result<IndexMap<String, &'a Value>, Error>
359    where
360        T: TryFrom<i128>
361            + TryFrom<u128>
362            + TryFrom<u64>
363            + TryFrom<i64>
364            + TryFrom<u32>
365            + TryFrom<i32>
366            + TryFrom<u16>
367            + TryFrom<i16>
368            + TryFrom<u8>
369            + TryFrom<i8>
370            + Ord,
371    {
372        // Check if the sort key exists in all values
373        for (_, value) in map.iter() {
374            value.get_integer::<T>(sort_key)?;
375        }
376
377        let mut sorted_map: Vec<_> = map.iter().collect();
378
379        sorted_map.sort_by(|(_, value_1), (_, value_2)| {
380            let pos_1: T = value_1.get_integer(sort_key).expect("expected sort key");
381            let pos_2: T = value_2.get_integer(sort_key).expect("expected sort key");
382            pos_1.cmp(&pos_2)
383        });
384
385        sorted_map
386            .into_iter()
387            .map(|(key, value)| {
388                let key = key
389                    .to_text()
390                    .map_err(|_| Error::StructureError("expected key to be string".to_string()))?;
391                Ok((key, value))
392            })
393            .collect::<Result<IndexMap<String, &Value>, Error>>()
394    }
395
396    /// Takes a ref to a ValueMap which is a `&Vec<(Value, Value)>`
397    /// Returns a BTreeMap<String, &Value> as long as each Key is a String
398    /// Returns `Err(Error::Structure("reason"))` otherwise.
399    pub fn map_ref_into_string_map<'a, I: FromIterator<(String, &'a Value)>>(
400        map: &'a ValueMap,
401    ) -> Result<I, Error> {
402        map.iter()
403            .map(|(key, value)| {
404                let key = key
405                    .to_text()
406                    .map_err(|_| Error::StructureError("expected key to be string".to_string()))?;
407                Ok((key, value))
408            })
409            .collect::<Result<I, Error>>()
410    }
411
412    /// Takes a ref to a ValueMap which is a `&Vec<(Value, Value)>`
413    /// Returns a BTreeMap<String, &Value> as long as each Key is a String
414    /// Returns `Err(Error::Structure("reason"))` otherwise.
415    pub fn map_mut_ref_into_string_map<'a, I: FromIterator<(String, &'a mut Value)>>(
416        map: &'a mut ValueMap,
417    ) -> Result<I, Error> {
418        map.iter_mut()
419            .map(|(key, value)| {
420                let key = key
421                    .to_text()
422                    .map_err(|_| Error::StructureError("expected key to be string".to_string()))?;
423                Ok((key, value))
424            })
425            .collect::<Result<I, Error>>()
426    }
427}