use core::{ cmp::{Eq, Ordering}, hash::{Hash, Hasher}, iter::FromIterator, ops::{Index, IndexMut}, }; use serde_derive::{Deserialize, Serialize}; use super::Value; /// A [`Value`] to [`Value`] map. /// /// This structure either uses a [`BTreeMap`](alloc::collections::BTreeMap) or the /// [`IndexMap`](indexmap::IndexMap) internally. /// The latter can be used by enabling the `indexmap` feature. This can be used /// to preserve the order of the parsed map. #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(transparent)] pub struct Map(pub(crate) MapInner); #[cfg(not(feature = "indexmap"))] type MapInner = alloc::collections::BTreeMap; #[cfg(feature = "indexmap")] type MapInner = indexmap::IndexMap; impl Map { /// Creates a new, empty [`Map`]. #[must_use] pub fn new() -> Self { Self::default() } /// Returns the number of elements in the map. #[must_use] pub fn len(&self) -> usize { self.0.len() } /// Returns `true` if `self.len() == 0`, `false` otherwise. #[must_use] pub fn is_empty(&self) -> bool { self.0.is_empty() } /// Immutably looks up an element by its `key`. #[must_use] pub fn get(&self, key: &Value) -> Option<&Value> { self.0.get(key) } /// Mutably looks up an element by its `key`. pub fn get_mut(&mut self, key: &Value) -> Option<&mut Value> { self.0.get_mut(key) } /// Inserts a new element, returning the previous element with this `key` if /// there was any. pub fn insert(&mut self, key: impl Into, value: impl Into) -> Option { self.0.insert(key.into(), value.into()) } /// Removes an element by its `key`. pub fn remove(&mut self, key: &Value) -> Option { #[cfg(feature = "indexmap")] { self.0.shift_remove(key) } #[cfg(not(feature = "indexmap"))] { self.0.remove(key) } } /// Iterate all key-value pairs. #[must_use] pub fn iter(&self) -> impl DoubleEndedIterator { self.0.iter() } /// Iterate all key-value pairs mutably. #[must_use] pub fn iter_mut(&mut self) -> impl DoubleEndedIterator { self.0.iter_mut() } /// Iterate all keys. #[must_use] pub fn keys(&self) -> impl DoubleEndedIterator { self.0.keys() } /// Iterate all values. #[must_use] pub fn values(&self) -> impl DoubleEndedIterator { self.0.values() } /// Iterate all values mutably. #[must_use] pub fn values_mut(&mut self) -> impl DoubleEndedIterator { self.0.values_mut() } /// Retains only the elements specified by the `keep` predicate. /// /// In other words, remove all pairs `(k, v)` for which `keep(&k, &mut v)` /// returns `false`. /// /// The elements are visited in iteration order. pub fn retain(&mut self, keep: F) where F: FnMut(&Value, &mut Value) -> bool, { self.0.retain(keep); } } impl Index<&Value> for Map { type Output = Value; #[allow(clippy::expect_used)] fn index(&self, index: &Value) -> &Self::Output { self.get(index).expect("no entry found for key") } } impl IndexMut<&Value> for Map { #[allow(clippy::expect_used)] fn index_mut(&mut self, index: &Value) -> &mut Self::Output { self.get_mut(index).expect("no entry found for key") } } impl IntoIterator for Map { type Item = (Value, Value); type IntoIter = ::IntoIter; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } impl, V: Into> FromIterator<(K, V)> for Map { fn from_iter>(iter: T) -> Self { Map(iter .into_iter() .map(|(key, value)| (key.into(), value.into())) .collect()) } } /// Note: equality is only given if both values and order of values match impl PartialEq for Map { fn eq(&self, other: &Map) -> bool { self.cmp(other).is_eq() } } /// Note: equality is only given if both values and order of values match impl Eq for Map {} impl PartialOrd for Map { fn partial_cmp(&self, other: &Map) -> Option { Some(self.cmp(other)) } } impl Ord for Map { fn cmp(&self, other: &Map) -> Ordering { self.iter().cmp(other.iter()) } } impl Hash for Map { fn hash(&self, state: &mut H) { self.iter().for_each(|x| x.hash(state)); } } #[cfg(test)] mod tests { use alloc::{vec, vec::Vec}; use super::{Map, Value}; #[test] fn map_usage() { let mut map = Map::new(); assert_eq!(map.len(), 0); assert!(map.is_empty()); map.insert("a", 42); assert_eq!(map.len(), 1); assert!(!map.is_empty()); assert_eq!(map.keys().collect::>(), vec![&Value::from("a")]); assert_eq!(map.values().collect::>(), vec![&Value::from(42)]); assert_eq!( map.iter().collect::>(), vec![(&Value::from("a"), &Value::from(42))] ); assert_eq!(map.get(&Value::from("a")), Some(&Value::from(42))); assert_eq!(map.get(&Value::from("b")), None); assert_eq!(map.get_mut(&Value::from("a")), Some(&mut Value::from(42))); assert_eq!(map.get_mut(&Value::from("b")), None); map[&Value::from("a")] = Value::from(24); assert_eq!(&map[&Value::from("a")], &Value::from(24)); for (key, value) in map.iter_mut() { if key == &Value::from("a") { *value = Value::from(42); } } assert_eq!(&map[&Value::from("a")], &Value::from(42)); map.values_mut().for_each(|value| *value = Value::from(24)); assert_eq!(&map[&Value::from("a")], &Value::from(24)); map.insert("b", 42); assert_eq!(map.len(), 2); assert!(!map.is_empty()); assert_eq!(map.get(&Value::from("a")), Some(&Value::from(24))); assert_eq!(map.get(&Value::from("b")), Some(&Value::from(42))); map.retain(|key, value| { if key == &Value::from("a") { *value = Value::from(42); true } else { false } }); assert_eq!(map.len(), 1); assert_eq!(map.get(&Value::from("a")), Some(&Value::from(42))); assert_eq!(map.get(&Value::from("b")), None); assert_eq!(map.remove(&Value::from("b")), None); assert_eq!(map.remove(&Value::from("a")), Some(Value::from(42))); assert_eq!(map.remove(&Value::from("a")), None); } #[cfg(feature = "std")] #[test] fn map_hash() { assert_same_hash(&Map::new(), &Map::new()); assert_same_hash( &[("a", 42)].into_iter().collect(), &[("a", 42)].into_iter().collect(), ); assert_same_hash( &[("b", 24), ("c", 42)].into_iter().collect(), &[("b", 24), ("c", 42)].into_iter().collect(), ); } #[cfg(feature = "std")] fn assert_same_hash(a: &Map, b: &Map) { use core::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; assert_eq!(a, b); assert!(a.cmp(b).is_eq()); assert_eq!(a.partial_cmp(b), Some(core::cmp::Ordering::Equal)); let mut hasher = DefaultHasher::new(); a.hash(&mut hasher); let h1 = hasher.finish(); let mut hasher = DefaultHasher::new(); b.hash(&mut hasher); let h2 = hasher.finish(); assert_eq!(h1, h2); } #[test] #[should_panic(expected = "no entry found for key")] fn map_index_panic() { let _ = &Map::new()[&Value::Unit]; } #[test] #[should_panic(expected = "no entry found for key")] fn map_index_mut_panic() { let _ = &mut Map::new()[&Value::Unit]; } }