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    pub fn new() -> Self {
47        Self(Vec::new())
48    }
49
50    pub fn with_capacity(capacity: usize) -> Self {
51        Self(Vec::with_capacity(capacity))
52    }
53
54    /// Access to the underlying Vec.
55    ///
56    /// # Note
57    /// Since KeyStrType can be changed via a feature flag avoid using `as_vec` and use other
58    /// methods instead. This could be a problem with feature unification, when one crate uses it
59    /// as `&str` and another uses it as `Cow<str>`, both will get `Cow<str>`
60    #[inline]
61    pub fn as_vec(&self) -> &Vec<(Key<'ctx, P>, Value<'ctx, P, E>)> {
62        &self.0
63    }
64
65    #[inline]
66    pub fn as_mut_vec(&mut self) -> &mut Vec<(Key<'ctx, P>, Value<'ctx, P, E>)> {
67        &mut self.0
68    }
69
70    /// Access to the underlying Vec. Keys are normalized to Cow.
71    #[inline]
72    pub fn into_vec(self) -> Vec<(Key<'ctx, P>, Value<'ctx, P, E>)> {
73        self.0
74    }
75
76    /// Returns a reference to the value corresponding to the key.
77    ///
78    /// ## Performance
79    /// As this is backed by a Vec, this searches linearly through the Vec as may be much more
80    /// expensive than a `Hashmap` for larger Objects.
81    #[inline]
82    pub fn get(&self, key: &Key<'_, P>) -> Option<&Value<'ctx, P, E>> {
83        self.0
84            .iter()
85            .find_map(|(k, v)| if k == key { Some(v) } else { None })
86    }
87
88    #[inline]
89    pub fn get_ignore_case(&self, key: &str) -> Option<&Value<'ctx, P, E>> {
90        self.0.iter().find_map(|(k, v)| {
91            if k.to_string().eq_ignore_ascii_case(key) {
92                Some(v)
93            } else {
94                None
95            }
96        })
97    }
98
99    /// Returns a mutable reference to the value corresponding to the key, if it exists.
100    ///
101    /// ## Performance
102    /// As this is backed by a Vec, this searches linearly through the Vec as may be much more
103    /// expensive than a `Hashmap` for larger Objects.
104    #[inline]
105    pub fn get_mut(&mut self, key: &Key<'ctx, P>) -> Option<&mut Value<'ctx, P, E>> {
106        self.0
107            .iter_mut()
108            .find_map(move |(k, v)| if k == key { Some(v) } else { None })
109    }
110
111    /// Returns the key-value pair corresponding to the supplied key.
112    ///
113    /// ## Performance
114    /// As this is backed by a Vec, this searches linearly through the Vec as may be much more
115    /// expensive than a `Hashmap` for larger Objects.
116    #[inline]
117    pub fn get_key_value(&self, key: &Key<'_, P>) -> Option<(&Key<'_, P>, &Value<'ctx, P, E>)> {
118        self.0
119            .iter()
120            .find_map(|(k, v)| if k == key { Some((k, v)) } else { None })
121    }
122
123    /// An iterator visiting all key-value pairs
124    #[inline]
125    pub fn iter(&self) -> impl Iterator<Item = (&Key<'ctx, P>, &Value<'ctx, P, E>)> {
126        self.0.iter().map(|(k, v)| (k, v))
127    }
128
129    #[inline]
130    pub fn iter_mut(
131        &mut self,
132    ) -> impl Iterator<Item = (&mut Key<'ctx, P>, &mut Value<'ctx, P, E>)> {
133        self.0.iter_mut().map(|(k, v)| (k, v))
134    }
135
136    /// Returns the number of elements in the object
137    #[inline]
138    pub fn len(&self) -> usize {
139        self.0.len()
140    }
141
142    /// Returns true if the object contains no elements
143    #[inline]
144    pub fn is_empty(&self) -> bool {
145        self.0.is_empty()
146    }
147
148    /// An iterator visiting all keys
149    #[inline]
150    pub fn keys(&self) -> impl Iterator<Item = &Key<'ctx, P>> {
151        self.0.iter().map(|(k, _)| k)
152    }
153
154    /// An iterator visiting all values
155    #[inline]
156    pub fn values(&self) -> impl Iterator<Item = &Value<'ctx, P, E>> {
157        self.0.iter().map(|(_, v)| v)
158    }
159
160    /// Returns true if the object contains a value for the specified key.
161    ///
162    /// ## Performance
163    /// As this is backed by a Vec, this searches linearly through the Vec as may be much more
164    /// expensive than a `Hashmap` for larger Objects.
165    #[inline]
166    pub fn contains_key(&self, key: &Key<'ctx, P>) -> bool {
167        self.0.iter().any(|(k, _)| k == key)
168    }
169
170    #[inline]
171    pub fn contains_key_value(&self, key: &Key<'ctx, P>, value: &Value<'ctx, P, E>) -> bool {
172        self.0.iter().any(|(k, v)| k == key && v == value)
173    }
174
175    #[inline]
176    pub fn contains_any_key(&self, keys: &[Key<'ctx, P>]) -> bool {
177        self.0.iter().any(|(k, _)| keys.contains(k))
178    }
179
180    pub fn remove(&mut self, key: &Key<'ctx, P>) -> Option<Value<'ctx, P, E>> {
181        if let Some(pos) = self.0.iter().position(|(k, _)| k == key) {
182            Some(self.0.swap_remove(pos).1)
183        } else {
184            None
185        }
186    }
187
188    /// Inserts a key-value pair into the object.
189    /// If the object did not have this key present, `None` is returned.
190    /// If the object did have this key present, the value is updated, and the old value is
191    /// returned.
192    ///
193    /// ## Performance
194    /// This operation is linear in the size of the Vec because it potentially requires iterating
195    /// through all elements to find a matching key.
196    #[inline]
197    pub fn insert(
198        &mut self,
199        key: impl Into<Key<'ctx, P>>,
200        value: impl Into<Value<'ctx, P, E>>,
201    ) -> Option<Value<'ctx, P, E>> {
202        let key = key.into();
203        for (k, v) in &mut self.0 {
204            if k == &key {
205                return Some(std::mem::replace(v, value.into()));
206            }
207        }
208        // If the key is not found, push the new key-value pair to the end of the Vec
209        self.0.push((key.into(), value.into()));
210        None
211    }
212
213    /// Inserts a key-value pair into the object if the key does not yet exist, otherwise returns a
214    /// mutable reference to the existing value.
215    ///
216    /// ## Performance
217    /// This operation might be linear in the size of the Vec because it requires iterating through
218    /// all elements to find a matching key, and might add to the end if not found.
219    #[inline]
220    pub fn insert_or_get_mut(
221        &mut self,
222        key: impl Into<Key<'ctx, P>>,
223        value: impl Into<Value<'ctx, P, E>>,
224    ) -> &mut Value<'ctx, P, E> {
225        let key = key.into();
226        // get position to circumvent lifetime issue
227        if let Some(pos) = self.0.iter_mut().position(|(k, _)| *k == key) {
228            &mut self.0[pos].1
229        } else {
230            self.0.push((key, value.into()));
231            &mut self.0.last_mut().unwrap().1
232        }
233    }
234
235    #[inline]
236    pub fn insert_unchecked(
237        &mut self,
238        key: impl Into<Key<'ctx, P>>,
239        value: impl Into<Value<'ctx, P, E>>,
240    ) {
241        self.0.push((key.into(), value.into()));
242    }
243
244    #[inline]
245    pub fn with_key_value(
246        mut self,
247        key: impl Into<Key<'ctx, P>>,
248        value: impl Into<Value<'ctx, P, E>>,
249    ) -> Self {
250        self.insert_unchecked(key, value);
251        self
252    }
253
254    pub fn insert_named(&mut self, key: Option<String>, value: Value<'ctx, P, E>) -> String {
255        let len = self.0.len();
256        let mut key = key.unwrap_or_else(|| format!("k{}", len + 1));
257
258        if self.contains_key(&Key::Borrowed(key.as_str())) {
259            key = format!("{}-{}", key, len + 1);
260        }
261
262        self.0.push((Key::Owned(key.clone()), value));
263        key
264    }
265
266    #[inline]
267    pub fn extend<I>(&mut self, iter: I)
268    where
269        I: IntoIterator<Item = (Key<'ctx, P>, Value<'ctx, P, E>)>,
270    {
271        self.0.extend(iter);
272    }
273
274    /// Inserts a key-value pair into the object and returns the mutable reference of the inserted
275    /// value.
276    ///
277    /// ## Note
278    /// The key must not exist in the object. If the key already exists, the object will contain
279    /// multiple keys afterwards.
280    ///
281    /// ## Performance
282    /// This operation is amortized constant time, worst case linear time in the size of the Vec
283    /// because it potentially requires a reallocation to grow the Vec.
284    #[inline]
285    pub fn insert_unchecked_and_get_mut(
286        &mut self,
287        key: impl Into<Key<'ctx, P>>,
288        value: impl Into<Value<'ctx, P, E>>,
289    ) -> &mut Value<'ctx, P, E> {
290        let key = key.into();
291        self.0.push((key, value.into()));
292        let idx = self.0.len() - 1;
293        &mut self.0[idx].1
294    }
295}
296
297impl<'ctx, P: Property, E: Element<Property = P>> ObjectAsVec<'ctx, P, E> {
298    pub fn into_expanded_boolean_set(self) -> impl Iterator<Item = Key<'ctx, P>> {
299        self.into_vec()
300            .into_iter()
301            .filter_map(|(key, value)| value.as_bool().filter(|&b| b).map(|_| key))
302    }
303}
304
305impl<'ctx, P: Property, E: Element> From<ObjectAsVec<'ctx, P, E>>
306    for serde_json::Map<String, serde_json::Value>
307{
308    fn from(val: ObjectAsVec<'ctx, P, E>) -> Self {
309        val.iter()
310            .map(|(key, val)| (key.to_string().into_owned(), val.into()))
311            .collect()
312    }
313}
314impl<'ctx, P: Property, E: Element> From<&ObjectAsVec<'ctx, P, E>>
315    for serde_json::Map<String, serde_json::Value>
316{
317    fn from(val: &ObjectAsVec<'ctx, P, E>) -> Self {
318        val.iter()
319            .map(|(key, val)| (key.to_string().into_owned(), val.into()))
320            .collect()
321    }
322}