#![allow(unused_variables)]
#![allow(dead_code)]
use crate::render::is_identifier;
use crate::value::Value;
use anyhow::{anyhow, Result};
use serde_json::Value as SerdeValue;
use std::collections::HashMap;
pub(crate) struct Context<'a> {
content: HashMap<String, Value>,
parent: Option<&'a Context<'a>>,
}
impl<'a> Context<'a> {
pub(crate) fn new() -> Context<'a> {
Context {
content: HashMap::new(),
parent: None,
}
}
pub(crate) fn child(&'a self) -> Context<'a> {
Context {
content: HashMap::new(),
parent: Some(self),
}
}
pub(crate) fn from_serde_value(
value: &'_ SerdeValue,
parent: Option<&'a Context>,
) -> Result<Context<'a>> {
let value: Value = value.into();
Context::from_value(&value, parent)
}
pub(crate) fn from_value(value: &'_ Value, parent: Option<&'a Context>) -> Result<Context<'a>> {
let mut c = Context {
content: HashMap::new(),
parent,
};
if let Value::Object(o) = value {
if o.keys().any(|k| !is_identifier(k)) {
return Err(template_error!(
"top level keys of context must follow /[a-zA-Z_][a-zA-Z0-9_]"
));
}
for (k, v) in o.iter() {
c.insert(k, v.clone());
}
} else {
return Err(anyhow!("Context is not an Object"));
}
Ok(c)
}
pub(crate) fn insert<K: Into<String>>(&mut self, k: K, v: Value) {
self.content.insert(k.into(), v);
}
pub(crate) fn get<'b>(&'b self, k: &'_ str) -> Option<&'b Value> {
match self.content.get(k) {
Some(v) => Some(v),
None => match self.parent {
Some(p) => p.get(k),
None => None,
},
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_get_not_found() {
let c = Context::new();
assert_eq!(c.get("xyz"), None);
}
#[test]
fn test_get_found() {
let mut c = Context::new();
c.insert("abc", Value::Null);
assert_eq!(c.get("abc"), Some(&Value::Null))
}
#[test]
fn test_get_parent() {
let mut c1 = Context::new();
c1.insert("abc", Value::Null);
c1.insert("def", Value::Bool(true));
let mut c2 = c1.child();
c2.insert("def", Value::Bool(false));
c2.insert("ghi", Value::String("hi".into()));
assert_eq!(c2.get("abc"), Some(&Value::Null));
assert_eq!(c2.get("def"), Some(&Value::Bool(false)));
assert_eq!(c2.get("ghi"), Some(&Value::String("hi".into())));
}
}