pub trait StackMap<'a, V>
where
V: Default + Copy,
{
fn lookup(
&self,
key: &'a str,
) -> Option<V>;
fn export_key_values<const K: usize>(
&self,
keys: &'a [&str; K],
) -> [V; K] {
let mut values: [V; K] = [Default::default(); K];
for i in 0..K {
let key = keys[i];
values[i] = match self.lookup(key) {
Some(v) => v,
None => panic!("No value for key \"{}\"", key),
};
}
values
}
}
pub type StackEnvironment<'a> = &'a [(&'a str, usize)];
impl<'a> StackMap<'a, usize> for StackEnvironment<'a> {
fn lookup(
&self,
key: &'a str,
) -> Option<usize> {
self.iter()
.find_map(|(k, v)| if k == &key { Some(*v) } else { None })
}
}
pub trait MutableStackMap<'a, V>: StackMap<'a, V>
where
V: Default + Copy,
{
fn bind(
&mut self,
key: &'a str,
value: V,
);
}
pub struct MutableStackEnvironment<'a> {
pub backing: StackEnvironment<'a>,
pub updates: Vec<(&'a str, usize)>,
}
impl<'a> StackMap<'a, usize> for MutableStackEnvironment<'a> {
fn lookup(
&self,
key: &str,
) -> Option<usize> {
(&self.updates.as_slice()).lookup(key).or_else(|| {
self.backing.lookup(key)
})
}
}
impl<'a> MutableStackMap<'a, usize> for MutableStackEnvironment<'a> {
fn bind(
&mut self,
key: &'a str,
value: usize,
) {
self.updates.push((key, value))
}
}
impl<'a> MutableStackEnvironment<'a> {
pub fn new(bindings: StackEnvironment<'a>) -> Self {
MutableStackEnvironment {
backing: bindings,
updates: Vec::new(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_stack_bindings() {
{
let env: StackEnvironment = &[("a", 1), ("b", 2)];
assert_eq!(env.lookup("a"), Some(1));
assert_eq!(env.lookup("b"), Some(2));
assert_eq!(env.lookup("c"), None);
}
{
static ENV: StackEnvironment = &[("a", 1), ("b", 2)];
assert_eq!(ENV.lookup("a"), Some(1));
assert_eq!(ENV.lookup("b"), Some(2));
assert_eq!(ENV.lookup("c"), None);
}
}
#[test]
fn test_mutable_stack_bindings() {
let mut env = MutableStackEnvironment::new(&[("a", 1), ("b", 2)]);
assert_eq!(env.lookup("a"), Some(1));
assert_eq!(env.lookup("b"), Some(2));
assert_eq!(env.lookup("c"), None);
env.bind("c", 3);
assert_eq!(env.lookup("c"), Some(3));
let keys = ["a", "b", "c"];
let values = env.export_key_values(&keys);
assert_eq!(values, [1, 2, 3]);
}
#[should_panic(expected = "No value for key \"d\"")]
#[test]
fn test_export_key_values_panic() {
let env = MutableStackEnvironment::new(&[("a", 1), ("b", 2)]);
let keys = ["a", "b", "d"]; env.export_key_values(&keys); }
}