use crate::{input::TemplateInput, value::Value};
#[derive(Debug, Clone)]
struct Binding {
depth: u32,
name: String,
value: Value,
}
#[derive(Debug, Clone)]
pub struct TemplateEnv<'i, I: TemplateInput> {
inputs: &'i I,
bindings: Vec<Binding>,
depth: u32,
}
impl<'i, I: TemplateInput> TemplateEnv<'i, I> {
pub fn new(inputs: &'i I) -> Self {
TemplateEnv {
inputs,
bindings: Vec::new(),
depth: 0,
}
}
pub fn pop(&mut self) {
self.depth -= 1;
self.bindings.retain(|b| b.depth <= self.depth);
}
pub fn push(&mut self) {
self.depth += 1;
}
pub fn set(&mut self, name: impl Into<String>, value: impl Into<Value>) {
let name = name.into();
let value = value.into();
if let Some(binding) = self
.bindings
.iter_mut()
.rev()
.find(|b| b.name == name && b.depth == self.depth)
{
binding.value = value;
} else {
self.bindings.push(Binding {
depth: self.depth,
name,
value,
});
}
}
pub fn get(&self, name: &str) -> Option<Value> {
self.bindings
.iter()
.rev()
.find(|b| b.name == name)
.map(|b| b.value.clone())
.or_else(|| self.inputs.get(name))
}
}
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
use super::*;
#[test]
fn template_env_works() {
let mut inputs = BTreeMap::new();
inputs.insert("meow", Value::String(":3".to_owned()));
let mut env = TemplateEnv::new(&inputs);
assert_eq!(env.get("meow"), Some(Value::String(":3".to_owned())));
assert_eq!(env.get("waf"), None);
env.push();
assert_eq!(env.get("meow"), Some(Value::String(":3".to_owned())));
assert_eq!(env.get("waf"), None);
env.set("meow", Value::String(":3c".to_owned()));
assert_eq!(env.get("meow"), Some(Value::String(":3c".to_owned())));
assert_eq!(env.get("waf"), None);
env.set("waf", Value::String("fops!".to_owned()));
assert_eq!(env.get("meow"), Some(Value::String(":3c".to_owned())));
assert_eq!(env.get("waf"), Some(Value::String("fops!".to_owned())));
env.push();
env.set("waf", Value::String("fops!!!".to_owned()));
assert_eq!(env.get("meow"), Some(Value::String(":3c".to_owned())));
assert_eq!(env.get("waf"), Some(Value::String("fops!!!".to_owned())));
env.pop();
assert_eq!(env.get("meow"), Some(Value::String(":3c".to_owned())));
assert_eq!(env.get("waf"), Some(Value::String("fops!".to_owned())));
env.pop();
assert_eq!(env.get("meow"), Some(Value::String(":3".to_owned())));
assert_eq!(env.get("waf"), None);
}
}