plist/
dictionary.rs

1//! A map of String to plist::Value.
2//!
3//! The map is currently backed by an [`IndexMap`]. This may be changed in a future minor release.
4//!
5//! [`IndexMap`]: https://docs.rs/indexmap/latest/indexmap/map/struct.IndexMap.html
6
7use indexmap::{map, IndexMap};
8use std::{
9    fmt::{self, Debug},
10    ops,
11};
12
13use crate::Value;
14
15/// Represents a plist dictionary type.
16#[derive(Clone, Default, PartialEq)]
17pub struct Dictionary {
18    map: IndexMap<String, Value>,
19}
20
21impl Dictionary {
22    /// Makes a new empty `Dictionary`.
23    #[inline]
24    pub fn new() -> Self {
25        Dictionary {
26            map: IndexMap::new(),
27        }
28    }
29
30    /// Clears the dictionary, removing all values.
31    #[inline]
32    pub fn clear(&mut self) {
33        self.map.clear()
34    }
35
36    /// Returns a reference to the value corresponding to the key.
37    #[inline]
38    pub fn get(&self, key: &str) -> Option<&Value> {
39        self.map.get(key)
40    }
41
42    /// Returns true if the dictionary contains a value for the specified key.
43    #[inline]
44    pub fn contains_key(&self, key: &str) -> bool {
45        self.map.contains_key(key)
46    }
47
48    /// Returns a mutable reference to the value corresponding to the key.
49    #[inline]
50    pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
51        self.map.get_mut(key)
52    }
53
54    /// Inserts a key-value pair into the dictionary.
55    ///
56    /// If the dictionary did not have this key present, `None` is returned.
57    ///
58    /// If the dictionary did have this key present, the value is updated, and the old value is
59    /// returned.
60    #[inline]
61    pub fn insert(&mut self, k: String, v: Value) -> Option<Value> {
62        self.map.insert(k, v)
63    }
64
65    /// Removes a key from the dictionary, returning the value at the key if the key was previously
66    /// in the dictionary.
67    #[inline]
68    pub fn remove(&mut self, key: &str) -> Option<Value> {
69        self.map.swap_remove(key)
70    }
71
72    /// Scan through each key-value pair in the map and keep those where the
73    /// closure `keep` returns `true`.
74    #[inline]
75    pub fn retain<F>(&mut self, keep: F)
76    where
77        F: FnMut(&String, &mut Value) -> bool,
78    {
79        self.map.retain(keep)
80    }
81
82    /// Sort the dictionary keys.
83    ///
84    /// This uses the default ordering defined on [`str`].
85    ///
86    /// This function is useful if you are serializing to XML, and wish to
87    /// ensure a consistent key order.
88    #[inline]
89    pub fn sort_keys(&mut self) {
90        self.map.sort_keys()
91    }
92
93    /// Gets the given key's corresponding entry in the dictionary for in-place manipulation.
94    // Entry functionality is unstable until I can figure out how to use either Cow<str> or
95    // T: AsRef<str> + Into<String>
96    #[cfg(any(
97        test,
98        feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"
99    ))]
100    pub fn entry<S>(&mut self, key: S) -> Entry
101    where
102        S: Into<String>,
103    {
104        match self.map.entry(key.into()) {
105            map::Entry::Vacant(vacant) => Entry::Vacant(VacantEntry { vacant }),
106            map::Entry::Occupied(occupied) => Entry::Occupied(OccupiedEntry { occupied }),
107        }
108    }
109
110    /// Returns the number of elements in the dictionary.
111    #[inline]
112    pub fn len(&self) -> usize {
113        self.map.len()
114    }
115
116    /// Returns true if the dictionary contains no elements.
117    #[inline]
118    pub fn is_empty(&self) -> bool {
119        self.map.is_empty()
120    }
121
122    /// Gets an iterator over the entries of the dictionary.
123    #[inline]
124    pub fn iter(&self) -> Iter {
125        Iter {
126            iter: self.map.iter(),
127        }
128    }
129
130    /// Gets a mutable iterator over the entries of the dictionary.
131    #[inline]
132    pub fn iter_mut(&mut self) -> IterMut {
133        IterMut {
134            iter: self.map.iter_mut(),
135        }
136    }
137
138    /// Gets an iterator over the keys of the dictionary.
139    #[inline]
140    pub fn keys(&self) -> Keys {
141        Keys {
142            iter: self.map.keys(),
143        }
144    }
145
146    /// Gets an iterator over the values of the dictionary.
147    #[inline]
148    pub fn values(&self) -> Values {
149        Values {
150            iter: self.map.values(),
151        }
152    }
153
154    /// Gets an iterator over mutable values of the dictionary.
155    #[inline]
156    pub fn values_mut(&mut self) -> ValuesMut {
157        ValuesMut {
158            iter: self.map.values_mut(),
159        }
160    }
161}
162
163/// Access an element of this dictionary. Panics if the given key is not present in the dictionary.
164///
165/// ```
166/// # use plist::Value;
167/// #
168/// # let val = &Value::String("".to_owned());
169/// # let _ =
170/// match *val {
171///     Value::Array(ref arr) => arr[0].as_string(),
172///     Value::Dictionary(ref dict) => dict["type"].as_string(),
173///     Value::String(ref s) => Some(s.as_str()),
174///     _ => None,
175/// }
176/// # ;
177/// ```
178impl<'a> ops::Index<&'a str> for Dictionary {
179    type Output = Value;
180
181    fn index(&self, index: &str) -> &Value {
182        self.map.index(index)
183    }
184}
185
186/// Mutably access an element of this dictionary. Panics if the given key is not present in the
187/// dictionary.
188///
189/// ```
190/// # let mut dict = plist::Dictionary::new();
191/// # dict.insert("key".to_owned(), plist::Value::Boolean(false));
192/// #
193/// dict["key"] = "value".into();
194/// ```
195impl<'a> ops::IndexMut<&'a str> for Dictionary {
196    fn index_mut(&mut self, index: &str) -> &mut Value {
197        self.map.get_mut(index).expect("no entry found for key")
198    }
199}
200
201impl Debug for Dictionary {
202    #[inline]
203    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
204        self.map.fmt(formatter)
205    }
206}
207
208impl<K: Into<String>, V: Into<Value>> FromIterator<(K, V)> for Dictionary {
209    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
210        Dictionary {
211            map: iter
212                .into_iter()
213                .map(|(k, v)| (k.into(), v.into()))
214                .collect(),
215        }
216    }
217}
218
219impl Extend<(String, Value)> for Dictionary {
220    fn extend<T>(&mut self, iter: T)
221    where
222        T: IntoIterator<Item = (String, Value)>,
223    {
224        self.map.extend(iter);
225    }
226}
227
228macro_rules! delegate_iterator {
229    (($name:ident $($generics:tt)*) => $item:ty) => {
230        impl $($generics)* Iterator for $name $($generics)* {
231            type Item = $item;
232            #[inline]
233            fn next(&mut self) -> Option<Self::Item> {
234                self.iter.next()
235            }
236            #[inline]
237            fn size_hint(&self) -> (usize, Option<usize>) {
238                self.iter.size_hint()
239            }
240        }
241
242        /*impl $($generics)* DoubleEndedIterator for $name $($generics)* {
243            #[inline]
244            fn next_back(&mut self) -> Option<Self::Item> {
245                self.iter.next_back()
246            }
247        }*/
248
249        impl $($generics)* ExactSizeIterator for $name $($generics)* {
250            #[inline]
251            fn len(&self) -> usize {
252                self.iter.len()
253            }
254        }
255    }
256}
257
258//////////////////////////////////////////////////////////////////////////////
259
260/// A view into a single entry in a dictionary, which may either be vacant or occupied.
261/// This enum is constructed from the [`entry`] method on [`Dictionary`].
262///
263/// [`entry`]: struct.Dictionary.html#method.entry
264/// [`Dictionary`]: struct.Dictionary.html
265#[cfg(any(
266    test,
267    feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"
268))]
269pub enum Entry<'a> {
270    /// A vacant Entry.
271    Vacant(VacantEntry<'a>),
272    /// An occupied Entry.
273    Occupied(OccupiedEntry<'a>),
274}
275
276/// A vacant Entry. It is part of the [`Entry`] enum.
277///
278/// [`Entry`]: enum.Entry.html
279#[cfg(any(
280    test,
281    feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"
282))]
283pub struct VacantEntry<'a> {
284    vacant: map::VacantEntry<'a, String, Value>,
285}
286
287/// An occupied Entry. It is part of the [`Entry`] enum.
288///
289/// [`Entry`]: enum.Entry.html
290#[cfg(any(
291    test,
292    feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"
293))]
294pub struct OccupiedEntry<'a> {
295    occupied: map::OccupiedEntry<'a, String, Value>,
296}
297
298#[cfg(any(
299    test,
300    feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"
301))]
302impl<'a> Entry<'a> {
303    /// Returns a reference to this entry's key.
304    ///
305    /// # Examples
306    ///
307    /// ```
308    /// let mut dict = plist::Dictionary::new();
309    /// assert_eq!(dict.entry("serde").key(), &"serde");
310    /// ```
311    pub fn key(&self) -> &String {
312        match *self {
313            Entry::Vacant(ref e) => e.key(),
314            Entry::Occupied(ref e) => e.key(),
315        }
316    }
317
318    /// Ensures a value is in the entry by inserting the default if empty, and returns a mutable
319    /// reference to the value in the entry.
320    ///
321    /// # Examples
322    ///
323    /// ```
324    /// let mut dict = plist::Dictionary::new();
325    /// dict.entry("serde").or_insert(12.into());
326    ///
327    /// assert_eq!(dict["serde"], 12.into());
328    /// ```
329    pub fn or_insert(self, default: Value) -> &'a mut Value {
330        match self {
331            Entry::Vacant(entry) => entry.insert(default),
332            Entry::Occupied(entry) => entry.into_mut(),
333        }
334    }
335
336    /// Ensures a value is in the entry by inserting the result of the default function if empty,
337    /// and returns a mutable reference to the value in the entry.
338    ///
339    /// # Examples
340    ///
341    /// ```
342    /// let mut dict = plist::Dictionary::new();
343    /// dict.entry("serde").or_insert_with(|| "hoho".into());
344    ///
345    /// assert_eq!(dict["serde"], "hoho".into());
346    /// ```
347    pub fn or_insert_with<F>(self, default: F) -> &'a mut Value
348    where
349        F: FnOnce() -> Value,
350    {
351        match self {
352            Entry::Vacant(entry) => entry.insert(default()),
353            Entry::Occupied(entry) => entry.into_mut(),
354        }
355    }
356}
357
358#[cfg(any(
359    test,
360    feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"
361))]
362impl<'a> VacantEntry<'a> {
363    /// Gets a reference to the key that would be used when inserting a value through the
364    /// VacantEntry.
365    ///
366    /// # Examples
367    ///
368    /// ```
369    /// use plist::dictionary::Entry;
370    ///
371    /// let mut dict = plist::Dictionary::new();
372    ///
373    /// match dict.entry("serde") {
374    ///     Entry::Vacant(vacant) => assert_eq!(vacant.key(), &"serde"),
375    ///     Entry::Occupied(_) => unimplemented!(),
376    /// }
377    /// ```
378    #[inline]
379    pub fn key(&self) -> &String {
380        self.vacant.key()
381    }
382
383    /// Sets the value of the entry with the VacantEntry's key, and returns a mutable reference
384    /// to it.
385    ///
386    /// # Examples
387    ///
388    /// ```
389    /// use plist::dictionary::Entry;
390    ///
391    /// let mut dict = plist::Dictionary::new();
392    ///
393    /// match dict.entry("serde") {
394    ///     Entry::Vacant(vacant) => vacant.insert("hoho".into()),
395    ///     Entry::Occupied(_) => unimplemented!(),
396    /// };
397    /// ```
398    #[inline]
399    pub fn insert(self, value: Value) -> &'a mut Value {
400        self.vacant.insert(value)
401    }
402}
403
404#[cfg(any(
405    test,
406    feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"
407))]
408impl<'a> OccupiedEntry<'a> {
409    /// Gets a reference to the key in the entry.
410    ///
411    /// # Examples
412    ///
413    /// ```
414    /// use plist::dictionary::Entry;
415    ///
416    /// let mut dict = plist::Dictionary::new();
417    /// dict.insert("serde".to_owned(), 12.into());
418    ///
419    /// match dict.entry("serde") {
420    ///     Entry::Occupied(occupied) => assert_eq!(occupied.key(), &"serde"),
421    ///     Entry::Vacant(_) => unimplemented!(),
422    /// }
423    /// ```
424    #[inline]
425    pub fn key(&self) -> &String {
426        self.occupied.key()
427    }
428
429    /// Gets a reference to the value in the entry.
430    ///
431    /// # Examples
432    ///
433    /// ```
434    /// use plist::Value;
435    /// use plist::dictionary::Entry;
436    ///
437    /// let mut dict = plist::Dictionary::new();
438    /// dict.insert("serde".to_owned(), 12.into());
439    ///
440    /// match dict.entry("serde") {
441    ///     Entry::Occupied(occupied) => assert_eq!(occupied.get(), &Value::from(12)),
442    ///     Entry::Vacant(_) => unimplemented!(),
443    /// }
444    /// ```
445    #[inline]
446    pub fn get(&self) -> &Value {
447        self.occupied.get()
448    }
449
450    /// Gets a mutable reference to the value in the entry.
451    ///
452    /// # Examples
453    ///
454    /// ```
455    /// use plist::Value;
456    /// use plist::dictionary::Entry;
457    ///
458    /// let mut dict = plist::Dictionary::new();
459    /// dict.insert("serde".to_owned(), Value::Array(vec![1.into(), 2.into(), 3.into()]));
460    ///
461    /// match dict.entry("serde") {
462    ///     Entry::Occupied(mut occupied) => {
463    ///         occupied.get_mut().as_array_mut().unwrap().push(4.into());
464    ///     }
465    ///     Entry::Vacant(_) => unimplemented!(),
466    /// }
467    ///
468    /// assert_eq!(dict["serde"].as_array().unwrap().len(), 4);
469    /// ```
470    #[inline]
471    pub fn get_mut(&mut self) -> &mut Value {
472        self.occupied.get_mut()
473    }
474
475    /// Converts the entry into a mutable reference to its value.
476    ///
477    /// # Examples
478    ///
479    /// ```
480    /// use plist::Value;
481    /// use plist::dictionary::Entry;
482    ///
483    /// let mut dict = plist::Dictionary::new();
484    /// dict.insert("serde".to_owned(), Value::Array(vec![1.into(), 2.into(), 3.into()]));
485    ///
486    /// match dict.entry("serde") {
487    ///     Entry::Occupied(mut occupied) => {
488    ///         occupied.into_mut().as_array_mut().unwrap().push(4.into());
489    ///     }
490    ///     Entry::Vacant(_) => unimplemented!(),
491    /// }
492    ///
493    /// assert_eq!(dict["serde"].as_array().unwrap().len(), 4);
494    /// ```
495    #[inline]
496    pub fn into_mut(self) -> &'a mut Value {
497        self.occupied.into_mut()
498    }
499
500    /// Sets the value of the entry with the `OccupiedEntry`'s key, and returns
501    /// the entry's old value.
502    ///
503    /// # Examples
504    ///
505    /// ```
506    /// use plist::Value;
507    /// use plist::dictionary::Entry;
508    ///
509    /// let mut dict = plist::Dictionary::new();
510    /// dict.insert("serde".to_owned(), 12.into());
511    ///
512    /// match dict.entry("serde") {
513    ///     Entry::Occupied(mut occupied) => {
514    ///         assert_eq!(occupied.insert(13.into()), 12.into());
515    ///         assert_eq!(occupied.get(), &Value::from(13));
516    ///     }
517    ///     Entry::Vacant(_) => unimplemented!(),
518    /// }
519    /// ```
520    #[inline]
521    pub fn insert(&mut self, value: Value) -> Value {
522        self.occupied.insert(value)
523    }
524
525    /// Takes the value of the entry out of the dictionary, and returns it.
526    ///
527    /// # Examples
528    ///
529    /// ```
530    /// use plist::dictionary::Entry;
531    ///
532    /// let mut dict = plist::Dictionary::new();
533    /// dict.insert("serde".to_owned(), 12.into());
534    ///
535    /// match dict.entry("serde") {
536    ///     Entry::Occupied(occupied) => assert_eq!(occupied.remove(), 12.into()),
537    ///     Entry::Vacant(_) => unimplemented!(),
538    /// }
539    /// ```
540    #[inline]
541    pub fn remove(self) -> Value {
542        self.occupied.swap_remove()
543    }
544}
545
546//////////////////////////////////////////////////////////////////////////////
547
548impl<'a> IntoIterator for &'a Dictionary {
549    type Item = (&'a String, &'a Value);
550    type IntoIter = Iter<'a>;
551    #[inline]
552    fn into_iter(self) -> Self::IntoIter {
553        Iter {
554            iter: self.map.iter(),
555        }
556    }
557}
558
559/// An iterator over a plist::Dictionary's entries.
560pub struct Iter<'a> {
561    iter: IterImpl<'a>,
562}
563
564type IterImpl<'a> = map::Iter<'a, String, Value>;
565
566delegate_iterator!((Iter<'a>) => (&'a String, &'a Value));
567
568//////////////////////////////////////////////////////////////////////////////
569
570impl<'a> IntoIterator for &'a mut Dictionary {
571    type Item = (&'a String, &'a mut Value);
572    type IntoIter = IterMut<'a>;
573    #[inline]
574    fn into_iter(self) -> Self::IntoIter {
575        IterMut {
576            iter: self.map.iter_mut(),
577        }
578    }
579}
580
581/// A mutable iterator over a plist::Dictionary's entries.
582pub struct IterMut<'a> {
583    iter: map::IterMut<'a, String, Value>,
584}
585
586delegate_iterator!((IterMut<'a>) => (&'a String, &'a mut Value));
587
588//////////////////////////////////////////////////////////////////////////////
589
590impl IntoIterator for Dictionary {
591    type Item = (String, Value);
592    type IntoIter = IntoIter;
593    #[inline]
594    fn into_iter(self) -> Self::IntoIter {
595        IntoIter {
596            iter: self.map.into_iter(),
597        }
598    }
599}
600
601/// An owning iterator over a plist::Dictionary's entries.
602pub struct IntoIter {
603    iter: map::IntoIter<String, Value>,
604}
605
606delegate_iterator!((IntoIter) => (String, Value));
607
608//////////////////////////////////////////////////////////////////////////////
609
610/// An iterator over a plist::Dictionary's keys.
611pub struct Keys<'a> {
612    iter: map::Keys<'a, String, Value>,
613}
614
615delegate_iterator!((Keys<'a>) => &'a String);
616
617//////////////////////////////////////////////////////////////////////////////
618
619/// An iterator over a plist::Dictionary's values.
620pub struct Values<'a> {
621    iter: map::Values<'a, String, Value>,
622}
623
624delegate_iterator!((Values<'a>) => &'a Value);
625
626//////////////////////////////////////////////////////////////////////////////
627
628/// A mutable iterator over a plist::Dictionary's values.
629pub struct ValuesMut<'a> {
630    iter: map::ValuesMut<'a, String, Value>,
631}
632
633delegate_iterator!((ValuesMut<'a>) => &'a mut Value);
634
635#[cfg(feature = "serde")]
636pub mod serde_impls {
637    use serde::{de, ser};
638    use std::fmt;
639
640    use crate::Dictionary;
641
642    impl ser::Serialize for Dictionary {
643        #[inline]
644        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
645        where
646            S: ser::Serializer,
647        {
648            use serde::ser::SerializeMap;
649            let mut map = serializer.serialize_map(Some(self.len()))?;
650            for (k, v) in self {
651                map.serialize_key(k)?;
652                map.serialize_value(v)?;
653            }
654            map.end()
655        }
656    }
657
658    impl<'de> de::Deserialize<'de> for Dictionary {
659        #[inline]
660        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
661        where
662            D: de::Deserializer<'de>,
663        {
664            struct Visitor;
665
666            impl<'de> de::Visitor<'de> for Visitor {
667                type Value = Dictionary;
668
669                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
670                    formatter.write_str("a map")
671                }
672
673                #[inline]
674                fn visit_unit<E>(self) -> Result<Self::Value, E>
675                where
676                    E: de::Error,
677                {
678                    Ok(Dictionary::new())
679                }
680
681                #[inline]
682                fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
683                where
684                    V: de::MapAccess<'de>,
685                {
686                    let mut values = Dictionary::new();
687
688                    while let Some((key, value)) = visitor.next_entry()? {
689                        values.insert(key, value);
690                    }
691
692                    Ok(values)
693                }
694            }
695
696            deserializer.deserialize_map(Visitor)
697        }
698    }
699}
700
701#[cfg(test)]
702mod tests {
703    use super::Dictionary;
704
705    #[test]
706    fn from_hash_map_to_dict() {
707        let dict: Dictionary = [
708            ("Doge", "Shiba Inu"),
709            ("Cheems", "Shiba Inu"),
710            ("Walter", "Bull Terrier"),
711            ("Perro", "Golden Retriever"),
712        ]
713        .into_iter()
714        .collect();
715
716        assert_eq!(
717            dict.get("Doge").and_then(|v| v.as_string()),
718            Some("Shiba Inu")
719        );
720        assert_eq!(
721            dict.get("Cheems").and_then(|v| v.as_string()),
722            Some("Shiba Inu")
723        );
724        assert_eq!(
725            dict.get("Walter").and_then(|v| v.as_string()),
726            Some("Bull Terrier")
727        );
728        assert_eq!(
729            dict.get("Perro").and_then(|v| v.as_string()),
730            Some("Golden Retriever")
731        );
732    }
733}