use std::borrow::Borrow; use std::collections::HashMap; use std::hash::Hash; /// A version of [`std::collections::HashMap`] with a built-in notion of scope. #[derive(Clone)] pub struct ScopedMap { scopes: Vec>, } impl Default for ScopedMap { fn default() -> Self { ScopedMap::new() } } impl ScopedMap { /// Generate a new scoped map. /// /// In addition to generate the map structure, this method also generates /// an initial scope for use by the caller. pub fn new() -> ScopedMap { ScopedMap { scopes: vec![HashMap::new()], } } /// Get a value from the scoped map. pub fn get(&self, k: &Q) -> Option<&V> where K: Borrow, Q: Hash + Eq + ?Sized, { for map in self.scopes.iter().rev() { match map.get(k) { None => continue, Some(v) => return Some(v), } } None } /// Returns true if the map contains the given key. pub fn contains_key(&self, k: &K) -> bool { self.scopes.iter().any(|x| x.contains_key(k)) } /// Insert a value into the current binding scope. /// /// If this variable is bound in the current scope, then its value will be /// overridden. If it's bound in a previous scope, however, that value will /// be shadowed, so that its value will preserved if/when the current scope /// is popped. pub fn insert(&mut self, k: K, v: V) { self.scopes .last_mut() .expect("tried to insert into ScopedMap with no scopes") .insert(k, v); } /// Create a new scope. /// /// Modifications to this scope will shadow all previous scopes without /// modifying them. Consider the following examples: /// /// ``` /// use ngr::util::scoped_map::ScopedMap; /// /// let mut example1 = ScopedMap::new(); /// example1.insert(1, true); /// example1.insert(1, false); /// assert_eq!(Some(&false), example1.get(&1)); /// let mut example2 = ScopedMap::new(); /// example2.insert(1, true); /// example2.new_scope(); /// example2.insert(1, false); /// assert_eq!(Some(&false), example2.get(&1)); /// example2.release_scope().expect("scope releases"); /// assert_eq!(Some(&true), example2.get(&1)); /// ``` pub fn new_scope(&mut self) { self.scopes.push(HashMap::new()); } /// Pop the current scope, returning to whatever was bound in the previous /// scope. If there is no prior scope, `None` will be returned. pub fn release_scope(&mut self) -> Option> { self.scopes.pop() } /// Create a new scoped set by mapping over the values of this one. pub fn map_values(self, f: F) -> ScopedMap where F: Fn(V) -> W, { let mut scopes = Vec::with_capacity(self.scopes.len()); for scope in self.scopes { let mut map = HashMap::with_capacity(scope.len()); for (k, v) in scope { map.insert(k, f(v)); } scopes.push(map); } ScopedMap { scopes } } /// Returns true if this map is completely empty, at every level of /// scope. pub fn is_empty(&self) -> bool { self.scopes.iter().all(|x| x.is_empty()) } } impl ScopedMap { /// Returns the set of all variables bound at this time, with shadowed /// variables hidden. pub fn bindings(&self) -> HashMap { let mut result = HashMap::new(); for scope in self.scopes.iter().rev() { for (key, value) in scope.iter() { if !result.contains_key(key) { result.insert(key.clone(), value.clone()); } } } result } }