use std::borrow::Borrow;
use std::collections::{HashMap, hash_map};
use std::fmt::Debug;
use std::hash::Hash;
#[derive(Clone, Debug, PartialEq)]
enum EnvOpr<K, V> {
Update(K, V),
Insert(K),
Delete(K, V),
Nothing,
}
#[derive(Clone, Debug)]
pub struct EnvMap<K, V> {
base_map: HashMap<K, V>,
history: Vec<EnvOpr<K, V>>,
scopes: Vec<usize>,
}
impl<K, V> Default for EnvMap<K, V>
where
K: Eq + Hash + Clone,
{
fn default() -> Self {
Self::new()
}
}
impl<K, V> EnvMap<K, V>
where
K: Eq + Hash + Clone,
{
pub fn new() -> EnvMap<K, V> {
EnvMap {
base_map: HashMap::new(),
history: Vec::new(),
scopes: Vec::new(),
}
}
pub fn with_capacity(capacity: usize) -> EnvMap<K, V> {
EnvMap {
base_map: HashMap::with_capacity(capacity),
history: Vec::new(),
scopes: Vec::new(),
}
}
pub fn capacity(&self) -> usize {
self.base_map.capacity()
}
pub fn keys(&self) -> hash_map::Keys<'_, K, V> {
self.base_map.keys()
}
pub fn values(&self) -> hash_map::Values<'_, K, V> {
self.base_map.values()
}
pub fn iter(&self) -> hash_map::Iter<'_, K, V> {
self.base_map.iter()
}
pub fn is_empty(&self) -> bool {
self.base_map.is_empty()
}
pub fn is_scope_empty(&self) -> bool {
self.scopes.is_empty()
}
pub fn clear(&mut self) {
self.base_map.clear();
self.history.clear();
self.scopes.clear();
}
pub fn get<Q>(&self, k: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.base_map.get(k)
}
pub fn get_key_value<Q>(&self, k: &Q) -> Option<(&K, &V)>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.base_map.get_key_value(k)
}
pub fn contains_key<Q>(&self, k: &Q) -> bool
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.base_map.contains_key(k)
}
pub fn insert(&mut self, k: K, v: V) -> bool {
if let Some(old) = self.base_map.insert(k.clone(), v) {
self.history.push(EnvOpr::Update(k, old));
true
} else {
self.history.push(EnvOpr::Insert(k));
false
}
}
pub fn remove(&mut self, k: &K) -> bool {
if let Some(old) = self.base_map.remove(k) {
self.history.push(EnvOpr::Delete(k.clone(), old));
true
} else {
self.history.push(EnvOpr::Nothing);
false
}
}
pub fn enter_scope(&mut self) {
self.scopes.push(self.history.len());
}
pub fn leave_scope(&mut self) {
let n = self.scopes.pop().unwrap();
for _ in n..self.history.len() {
match self.history.pop().unwrap() {
EnvOpr::Update(k, v) => {
let r = self.base_map.insert(k, v);
assert!(r.is_some());
}
EnvOpr::Insert(k) => {
let r = self.base_map.remove(&k);
assert!(r.is_some());
}
EnvOpr::Delete(k, v) => {
let r = self.base_map.insert(k, v);
assert!(r.is_none());
}
EnvOpr::Nothing => {
}
}
}
}
}
impl<K, V> std::ops::Index<&K> for EnvMap<K, V>
where
K: Hash + Eq,
{
type Output = V;
fn index(&self, index: &K) -> &Self::Output {
&self.base_map[index]
}
}
#[test]
fn env_map_test() {
let mut env = EnvMap::new();
env.insert(&1, 'a');
env.enter_scope();
env.insert(&1, 'd');
env.insert(&2, 'b');
env.insert(&3, 'c');
assert_eq!(env.get(&1), Some(&'d'));
assert_eq!(env.get(&2), Some(&'b'));
assert_eq!(env.get(&3), Some(&'c'));
env.leave_scope();
assert_eq!(env.get(&1), Some(&'a'));
assert_eq!(env.get(&2), None);
assert_eq!(env.get(&3), None);
}