//! A key-value map that can also model array-like structures. use std::collections::BTreeMap; use std::fmt::{self, Debug, Display, Formatter}; use std::iter::{Extend, FromIterator}; use std::ops::Index; use crate::syntax::{Span, Spanned}; /// A dictionary data structure, which maps from integers and strings to a /// generic value type. /// /// The dictionary can be used to model arrays by assigning values to successive /// indices from `0..n`. The `push` method offers special support for this /// pattern. #[derive(Clone)] pub struct Dict { nums: BTreeMap, strs: BTreeMap, lowest_free: u64, } impl Dict { /// Create a new empty dictionary. pub fn new() -> Self { Self { nums: BTreeMap::new(), strs: BTreeMap::new(), lowest_free: 0, } } /// The total number of entries in the dictionary. pub fn len(&self) -> usize { self.nums.len() + self.strs.len() } /// Whether the dictionary contains no entries. pub fn is_empty(&self) -> bool { self.len() == 0 } /// The first number key-value pair (with lowest number). pub fn first(&self) -> Option<(u64, &V)> { self.nums.iter().next().map(|(&k, v)| (k, v)) } /// The last number key-value pair (with highest number). pub fn last(&self) -> Option<(u64, &V)> { self.nums.iter().next_back().map(|(&k, v)| (k, v)) } /// Get a reference to the value with the given key. pub fn get<'a, K>(&self, key: K) -> Option<&V> where K: Into>, { match key.into() { RefKey::Num(num) => self.nums.get(&num), RefKey::Str(string) => self.strs.get(string), } } /// Borrow the value with the given key mutably. pub fn get_mut<'a, K>(&mut self, key: K) -> Option<&mut V> where K: Into>, { match key.into() { RefKey::Num(num) => self.nums.get_mut(&num), RefKey::Str(string) => self.strs.get_mut(string), } } /// Insert a value into the dictionary. pub fn insert(&mut self, key: K, value: V) where K: Into, { match key.into() { DictKey::Num(num) => { self.nums.insert(num, value); if self.lowest_free == num { self.lowest_free += 1; } } DictKey::Str(string) => { self.strs.insert(string, value); } } } /// Remove the value with the given key from the dictionary. pub fn remove<'a, K>(&mut self, key: K) -> Option where K: Into>, { match key.into() { RefKey::Num(num) => { self.lowest_free = self.lowest_free.min(num); self.nums.remove(&num) } RefKey::Str(string) => self.strs.remove(string), } } /// Append a value to the dictionary. /// /// This will associate the `value` with the lowest free number key (zero if /// there is no number key so far). pub fn push(&mut self, value: V) { while self.nums.contains_key(&self.lowest_free) { self.lowest_free += 1; } self.nums.insert(self.lowest_free, value); self.lowest_free += 1; } } impl<'a, K, V> Index for Dict where K: Into>, { type Output = V; fn index(&self, index: K) -> &Self::Output { self.get(index).expect("key not in dict") } } impl Eq for Dict {} impl PartialEq for Dict { fn eq(&self, other: &Self) -> bool { self.iter().eq(other.iter()) } } impl Default for Dict { fn default() -> Self { Self::new() } } impl Debug for Dict { fn fmt(&self, f: &mut Formatter) -> fmt::Result { if self.is_empty() { return f.write_str("()"); } let mut builder = f.debug_tuple(""); struct Entry<'a>(bool, &'a dyn Display, &'a dyn Debug); impl<'a> Debug for Entry<'a> { fn fmt(&self, f: &mut Formatter) -> fmt::Result { if self.0 { f.write_str("\"")?; } self.1.fmt(f)?; if self.0 { f.write_str("\"")?; } if f.alternate() { f.write_str(" = ")?; } else { f.write_str("=")?; } self.2.fmt(f) } } for (key, value) in self.nums() { builder.field(&Entry(false, &key, &value)); } for (key, value) in self.strs() { builder.field(&Entry(key.contains(' '), &key, &value)); } builder.finish() } } /// Iteration. impl Dict { /// Iterator over all borrowed keys and values. pub fn iter(&self) -> impl Iterator { self.into_iter() } /// Iterator over all borrowed keys and values. pub fn iter_mut(&mut self) -> impl Iterator { self.into_iter() } /// Iterate over all values in the dictionary. pub fn values(&self) -> impl Iterator { self.nums().map(|(_, v)| v).chain(self.strs().map(|(_, v)| v)) } /// Iterate over all values in the dictionary. pub fn values_mut(&mut self) -> impl Iterator { self.nums .iter_mut() .map(|(_, v)| v) .chain(self.strs.iter_mut().map(|(_, v)| v)) } /// Move into an owned iterator over all values in the dictionary. pub fn into_values(self) -> impl Iterator { self.nums .into_iter() .map(|(_, v)| v) .chain(self.strs.into_iter().map(|(_, v)| v)) } /// Iterate over the number key-value pairs. pub fn nums(&self) -> std::collections::btree_map::Iter { self.nums.iter() } /// Iterate mutably over the number key-value pairs. pub fn nums_mut(&mut self) -> std::collections::btree_map::IterMut { self.nums.iter_mut() } /// Iterate over the number key-value pairs. pub fn into_nums(self) -> std::collections::btree_map::IntoIter { self.nums.into_iter() } /// Iterate over the string key-value pairs. pub fn strs(&self) -> std::collections::btree_map::Iter { self.strs.iter() } /// Iterate mutably over the string key-value pairs. pub fn strs_mut(&mut self) -> std::collections::btree_map::IterMut { self.strs.iter_mut() } /// Iterate over the string key-value pairs. pub fn into_strs(self) -> std::collections::btree_map::IntoIter { self.strs.into_iter() } } impl Extend<(DictKey, V)> for Dict { fn extend>(&mut self, iter: T) { for (key, value) in iter.into_iter() { self.insert(key, value); } } } impl FromIterator<(DictKey, V)> for Dict { fn from_iter>(iter: T) -> Self { let mut v = Self::new(); v.extend(iter); v } } impl IntoIterator for Dict { type Item = (DictKey, V); type IntoIter = std::iter::Chain< std::iter::Map< std::collections::btree_map::IntoIter, fn((u64, V)) -> (DictKey, V), >, std::iter::Map< std::collections::btree_map::IntoIter, fn((String, V)) -> (DictKey, V), >, >; fn into_iter(self) -> Self::IntoIter { let nums = self.nums.into_iter().map((|(k, v)| (DictKey::Num(k), v)) as _); let strs = self.strs.into_iter().map((|(k, v)| (DictKey::Str(k), v)) as _); nums.chain(strs) } } impl<'a, V> IntoIterator for &'a Dict { type Item = (RefKey<'a>, &'a V); type IntoIter = std::iter::Chain< std::iter::Map< std::collections::btree_map::Iter<'a, u64, V>, fn((&'a u64, &'a V)) -> (RefKey<'a>, &'a V), >, std::iter::Map< std::collections::btree_map::Iter<'a, String, V>, fn((&'a String, &'a V)) -> (RefKey<'a>, &'a V), >, >; fn into_iter(self) -> Self::IntoIter { let nums = self.nums().map((|(k, v): (&u64, _)| (RefKey::Num(*k), v)) as _); let strs = self.strs().map((|(k, v): (&'a String, _)| (RefKey::Str(k), v)) as _); nums.chain(strs) } } impl<'a, V> IntoIterator for &'a mut Dict { type Item = (RefKey<'a>, &'a mut V); type IntoIter = std::iter::Chain< std::iter::Map< std::collections::btree_map::IterMut<'a, u64, V>, fn((&'a u64, &'a mut V)) -> (RefKey<'a>, &'a mut V), >, std::iter::Map< std::collections::btree_map::IterMut<'a, String, V>, fn((&'a String, &'a mut V)) -> (RefKey<'a>, &'a mut V), >, >; fn into_iter(self) -> Self::IntoIter { let nums = self .nums .iter_mut() .map((|(k, v): (&u64, _)| (RefKey::Num(*k), v)) as _); let strs = self .strs .iter_mut() .map((|(k, v): (&'a String, _)| (RefKey::Str(k), v)) as _); nums.chain(strs) } } /// The owned variant of a dictionary key. #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] pub enum DictKey { Num(u64), Str(String), } impl From<&Self> for DictKey { fn from(key: &Self) -> Self { key.clone() } } impl From> for DictKey { fn from(key: RefKey<'_>) -> Self { match key { RefKey::Num(num) => Self::Num(num), RefKey::Str(string) => Self::Str(string.to_string()), } } } impl From for DictKey { fn from(num: u64) -> Self { Self::Num(num) } } impl From for DictKey { fn from(string: String) -> Self { Self::Str(string) } } impl From<&'static str> for DictKey { fn from(string: &'static str) -> Self { Self::Str(string.to_string()) } } /// The borrowed variant of a dictionary key. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] pub enum RefKey<'a> { Num(u64), Str(&'a str), } impl From for RefKey<'static> { fn from(num: u64) -> Self { Self::Num(num) } } impl<'a> From<&'a String> for RefKey<'a> { fn from(string: &'a String) -> Self { Self::Str(&string) } } impl<'a> From<&'a str> for RefKey<'a> { fn from(string: &'a str) -> Self { Self::Str(string) } } /// A dictionary entry which combines key span and value. /// /// This exists because a key in a directory can't track its span by itself. #[derive(Clone, PartialEq)] pub struct SpannedEntry { pub key_span: Span, pub value: Spanned, } impl SpannedEntry { /// Create a new entry. pub fn new(key: Span, val: Spanned) -> Self { Self { key_span: key, value: val } } /// Create an entry with the same span for key and value. pub fn value(val: Spanned) -> Self { Self { key_span: val.span, value: val } } /// Convert from `&SpannedEntry` to `SpannedEntry<&T>` pub fn as_ref(&self) -> SpannedEntry<&V> { SpannedEntry { key_span: self.key_span, value: self.value.as_ref(), } } /// Map the entry to a different value type. pub fn map(self, f: impl FnOnce(V) -> U) -> SpannedEntry { SpannedEntry { key_span: self.key_span, value: self.value.map(f), } } } impl Debug for SpannedEntry { fn fmt(&self, f: &mut Formatter) -> fmt::Result { if f.alternate() { f.write_str("key")?; self.key_span.fmt(f)?; f.write_str(" ")?; } self.value.fmt(f) } } #[cfg(test)] mod tests { use super::Dict; #[test] fn test_dict_different_key_types_dont_interfere() { let mut dict = Dict::new(); dict.insert(10, "hello"); dict.insert("twenty", "there"); assert_eq!(dict.len(), 2); assert_eq!(dict[10], "hello"); assert_eq!(dict["twenty"], "there"); } #[test] fn test_dict_push_skips_already_inserted_keys() { let mut dict = Dict::new(); dict.insert(2, "2"); dict.push("0"); dict.insert(3, "3"); dict.push("1"); dict.push("4"); assert_eq!(dict.len(), 5); assert_eq!(dict[0], "0"); assert_eq!(dict[1], "1"); assert_eq!(dict[2], "2"); assert_eq!(dict[3], "3"); assert_eq!(dict[4], "4"); } #[test] fn test_dict_push_remove_push_reuses_index() { let mut dict = Dict::new(); dict.push("0"); dict.push("1"); dict.push("2"); dict.remove(1); dict.push("a"); dict.push("3"); assert_eq!(dict.len(), 4); assert_eq!(dict[0], "0"); assert_eq!(dict[1], "a"); assert_eq!(dict[2], "2"); assert_eq!(dict[3], "3"); } #[test] fn test_dict_first_and_last_are_correct() { let mut dict = Dict::new(); assert_eq!(dict.first(), None); assert_eq!(dict.last(), None); dict.insert(4, "hi"); dict.insert("string", "hi"); assert_eq!(dict.first(), Some((4, &"hi"))); assert_eq!(dict.last(), Some((4, &"hi"))); dict.insert(2, "bye"); assert_eq!(dict.first(), Some((2, &"bye"))); assert_eq!(dict.last(), Some((4, &"hi"))); } #[test] fn test_dict_format_debug() { let mut dict = Dict::new(); assert_eq!(format!("{:?}", dict), "()"); assert_eq!(format!("{:#?}", dict), "()"); dict.insert(10, "hello"); dict.insert("twenty", "there"); dict.insert("sp ace", "quotes"); assert_eq!( format!("{:?}", dict), r#"(10="hello", "sp ace"="quotes", twenty="there")"#, ); assert_eq!(format!("{:#?}", dict).lines().collect::>(), [ "(", r#" 10 = "hello","#, r#" "sp ace" = "quotes","#, r#" twenty = "there","#, ")", ]); } }