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}