jmap_tools/json/
object_vec.rs

1/*
2 * SPDX-FileCopyrightText: 2021 Pascal Seitz <pascal.seitz@gmail.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0 OR MIT
5 */
6
7#![allow(clippy::useless_conversion)]
8#![allow(clippy::useless_asref)]
9
10use crate::{
11    Value,
12    json::key::Key,
13    json::value::{Element, Property},
14};
15
16/// Represents a JSON key/value type.
17///
18/// For performance reasons we use a Vec instead of a Hashmap.
19/// This comes with a tradeoff of slower key accesses as we need to iterate and compare.
20///
21/// The ObjectAsVec struct is a wrapper around a Vec of (&str, Value) pairs.
22/// It provides methods to make it easy to migrate from serde_json::Value::Object or
23/// serde_json::Map.
24#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
25pub struct ObjectAsVec<'ctx, P: Property, E: Element>(
26    pub(crate) Vec<(Key<'ctx, P>, Value<'ctx, P, E>)>,
27);
28
29impl<'ctx, P: Property, E: Element> From<Vec<(Key<'ctx, P>, Value<'ctx, P, E>)>>
30    for ObjectAsVec<'ctx, P, E>
31{
32    fn from(vec: Vec<(Key<'ctx, P>, Value<'ctx, P, E>)>) -> Self {
33        ObjectAsVec(vec)
34    }
35}
36
37impl<'ctx, P: Property, E: Element> FromIterator<(Key<'ctx, P>, Value<'ctx, P, E>)>
38    for ObjectAsVec<'ctx, P, E>
39{
40    fn from_iter<T: IntoIterator<Item = (Key<'ctx, P>, Value<'ctx, P, E>)>>(iter: T) -> Self {
41        Self(iter.into_iter().collect())
42    }
43}
44
45impl<'ctx, P: Property, E: Element> ObjectAsVec<'ctx, P, E> {
46    /// Access to the underlying Vec.
47    ///
48    /// # Note
49    /// Since KeyStrType can be changed via a feature flag avoid using `as_vec` and use other
50    /// methods instead. This could be a problem with feature unification, when one crate uses it
51    /// as `&str` and another uses it as `Cow<str>`, both will get `Cow<str>`
52    #[inline]
53    pub fn as_vec(&self) -> &Vec<(Key<'ctx, P>, Value<'ctx, P, E>)> {
54        &self.0
55    }
56
57    #[inline]
58    pub fn as_mut_vec(&mut self) -> &mut Vec<(Key<'ctx, P>, Value<'ctx, P, E>)> {
59        &mut self.0
60    }
61
62    /// Access to the underlying Vec. Keys are normalized to Cow.
63    #[inline]
64    pub fn into_vec(self) -> Vec<(Key<'ctx, P>, Value<'ctx, P, E>)> {
65        self.0
66    }
67
68    /// Returns a reference to the value corresponding to the key.
69    ///
70    /// ## Performance
71    /// As this is backed by a Vec, this searches linearly through the Vec as may be much more
72    /// expensive than a `Hashmap` for larger Objects.
73    #[inline]
74    pub fn get(&self, key: &Key<'_, P>) -> Option<&Value<'ctx, P, E>> {
75        self.0
76            .iter()
77            .find_map(|(k, v)| if k == key { Some(v) } else { None })
78    }
79
80    #[inline]
81    pub fn get_ignore_case(&self, key: &str) -> Option<&Value<'ctx, P, E>> {
82        self.0.iter().find_map(|(k, v)| {
83            if k.to_string().eq_ignore_ascii_case(key) {
84                Some(v)
85            } else {
86                None
87            }
88        })
89    }
90
91    /// Returns a mutable reference to the value corresponding to the key, if it exists.
92    ///
93    /// ## Performance
94    /// As this is backed by a Vec, this searches linearly through the Vec as may be much more
95    /// expensive than a `Hashmap` for larger Objects.
96    #[inline]
97    pub fn get_mut(&mut self, key: &Key<'ctx, P>) -> Option<&mut Value<'ctx, P, E>> {
98        self.0
99            .iter_mut()
100            .find_map(move |(k, v)| if k == key { Some(v) } else { None })
101    }
102
103    /// Returns the key-value pair corresponding to the supplied key.
104    ///
105    /// ## Performance
106    /// As this is backed by a Vec, this searches linearly through the Vec as may be much more
107    /// expensive than a `Hashmap` for larger Objects.
108    #[inline]
109    pub fn get_key_value(&self, key: &Key<'_, P>) -> Option<(&Key<'_, P>, &Value<'ctx, P, E>)> {
110        self.0
111            .iter()
112            .find_map(|(k, v)| if k == key { Some((k, v)) } else { None })
113    }
114
115    /// An iterator visiting all key-value pairs
116    #[inline]
117    pub fn iter(&self) -> impl Iterator<Item = (&Key<'ctx, P>, &Value<'ctx, P, E>)> {
118        self.0.iter().map(|(k, v)| (k, v))
119    }
120
121    #[inline]
122    pub fn iter_mut(
123        &mut self,
124    ) -> impl Iterator<Item = (&mut Key<'ctx, P>, &mut Value<'ctx, P, E>)> {
125        self.0.iter_mut().map(|(k, v)| (k, v))
126    }
127
128    /// Returns the number of elements in the object
129    #[inline]
130    pub fn len(&self) -> usize {
131        self.0.len()
132    }
133
134    /// Returns true if the object contains no elements
135    #[inline]
136    pub fn is_empty(&self) -> bool {
137        self.0.is_empty()
138    }
139
140    /// An iterator visiting all keys
141    #[inline]
142    pub fn keys(&self) -> impl Iterator<Item = &Key<'ctx, P>> {
143        self.0.iter().map(|(k, _)| k)
144    }
145
146    /// An iterator visiting all values
147    #[inline]
148    pub fn values(&self) -> impl Iterator<Item = &Value<'ctx, P, E>> {
149        self.0.iter().map(|(_, v)| v)
150    }
151
152    /// Returns true if the object contains a value for the specified key.
153    ///
154    /// ## Performance
155    /// As this is backed by a Vec, this searches linearly through the Vec as may be much more
156    /// expensive than a `Hashmap` for larger Objects.
157    #[inline]
158    pub fn contains_key(&self, key: &Key<'ctx, P>) -> bool {
159        self.0.iter().any(|(k, _)| k == key)
160    }
161
162    #[inline]
163    pub fn contains_key_value(&self, key: &Key<'ctx, P>, value: &Value<'ctx, P, E>) -> bool {
164        self.0.iter().any(|(k, v)| k == key && v == value)
165    }
166
167    #[inline]
168    pub fn contains_any_key(&self, keys: &[Key<'ctx, P>]) -> bool {
169        self.0.iter().any(|(k, _)| keys.contains(k))
170    }
171
172    /// Inserts a key-value pair into the object.
173    /// If the object did not have this key present, `None` is returned.
174    /// If the object did have this key present, the value is updated, and the old value is
175    /// returned.
176    ///
177    /// ## Performance
178    /// This operation is linear in the size of the Vec because it potentially requires iterating
179    /// through all elements to find a matching key.
180    #[inline]
181    pub fn insert(
182        &mut self,
183        key: impl Into<Key<'ctx, P>>,
184        value: Value<'ctx, P, E>,
185    ) -> Option<Value<'ctx, P, E>> {
186        let key = key.into();
187        for (k, v) in &mut self.0 {
188            if k == &key {
189                return Some(std::mem::replace(v, value));
190            }
191        }
192        // If the key is not found, push the new key-value pair to the end of the Vec
193        self.0.push((key.into(), value));
194        None
195    }
196
197    /// Inserts a key-value pair into the object if the key does not yet exist, otherwise returns a
198    /// mutable reference to the existing value.
199    ///
200    /// ## Performance
201    /// This operation might be linear in the size of the Vec because it requires iterating through
202    /// all elements to find a matching key, and might add to the end if not found.
203    #[inline]
204    pub fn insert_or_get_mut(
205        &mut self,
206        key: impl Into<Key<'ctx, P>>,
207        value: Value<'ctx, P, E>,
208    ) -> &mut Value<'ctx, P, E> {
209        let key = key.into();
210        // get position to circumvent lifetime issue
211        if let Some(pos) = self.0.iter_mut().position(|(k, _)| *k == key) {
212            &mut self.0[pos].1
213        } else {
214            self.0.push((key, value));
215            &mut self.0.last_mut().unwrap().1
216        }
217    }
218
219    #[inline]
220    pub fn insert_unchecked(&mut self, key: impl Into<Key<'ctx, P>>, value: Value<'ctx, P, E>) {
221        let key = key.into();
222        self.0.push((key, value));
223    }
224
225    pub fn insert_named(&mut self, key: Option<String>, value: Value<'ctx, P, E>) -> String {
226        let len = self.0.len();
227        let mut key = key.unwrap_or_else(|| format!("k{}", len + 1));
228
229        if self.contains_key(&Key::Borrowed(key.as_str())) {
230            key = format!("{}-{}", key, len + 1);
231        }
232
233        self.0.push((Key::Owned(key.clone()), value));
234        key
235    }
236
237    pub fn extend<I>(&mut self, iter: I)
238    where
239        I: IntoIterator<Item = (Key<'ctx, P>, Value<'ctx, P, E>)>,
240    {
241        self.0.extend(iter);
242    }
243
244    /// Inserts a key-value pair into the object and returns the mutable reference of the inserted
245    /// value.
246    ///
247    /// ## Note
248    /// The key must not exist in the object. If the key already exists, the object will contain
249    /// multiple keys afterwards.
250    ///
251    /// ## Performance
252    /// This operation is amortized constant time, worst case linear time in the size of the Vec
253    /// because it potentially requires a reallocation to grow the Vec.
254    #[inline]
255    pub fn insert_unchecked_and_get_mut(
256        &mut self,
257        key: impl Into<Key<'ctx, P>>,
258        value: Value<'ctx, P, E>,
259    ) -> &mut Value<'ctx, P, E> {
260        let key = key.into();
261        self.0.push((key, value));
262        let idx = self.0.len() - 1;
263        &mut self.0[idx].1
264    }
265}
266
267impl<'ctx, P: Property, E: Element> From<ObjectAsVec<'ctx, P, E>>
268    for serde_json::Map<String, serde_json::Value>
269{
270    fn from(val: ObjectAsVec<'ctx, P, E>) -> Self {
271        val.iter()
272            .map(|(key, val)| (key.to_string().into_owned(), val.into()))
273            .collect()
274    }
275}
276impl<'ctx, P: Property, E: Element> From<&ObjectAsVec<'ctx, P, E>>
277    for serde_json::Map<String, serde_json::Value>
278{
279    fn from(val: &ObjectAsVec<'ctx, P, E>) -> Self {
280        val.iter()
281            .map(|(key, val)| (key.to_string().into_owned(), val.into()))
282            .collect()
283    }
284}