templar 0.5.0

Lightweight, fast, and powerful templating engine
Documentation
use super::*;

#[derive(Clone, Debug, Default)]
pub struct ContextMap {
    root: BTreeMap<InnerData, ContextMapValue>,
}

impl ContextMap {
    pub fn new<T: Into<ContextMapValue>>(doc: T) -> Self {
        let mut result = ContextMap::default();
        result.set(doc, &[]).unwrap_or_default();
        result
    }

    pub fn set<T: Into<ContextMapValue>>(&mut self, value: T, path: &[&InnerData]) -> Result<()> {
        if path.is_empty() {
            let val: ContextMapValue = value.into();
            println!("{:?}", val);
            if let ContextMapValue::Map(map) = val {
                for (k, v) in map.into_iter() {
                    self.root.insert(k, v);
                }
            }
            return Ok(());
        }
        if path.len() == 1 {
            self.root.insert(path[0].clone(), value.into());
            return Ok(());
        }
        let mut target: &mut ContextMapValue = self
            .root
            .entry(path[0].clone())
            .or_insert_with(ContextMapValue::new_map);
        for p in path.iter().skip(1).take(path.len() - 1) {
            target = target.get_or_add_key(*p);
        }
        target.set(value.into());
        Ok(())
    }

    pub fn exec(&self, ctx: &impl Context, path: &[&InnerData]) -> Data {
        if path.is_empty() {
            let copy = ContextMapValue::Map(self.root.clone());
            return copy.exec(ctx);
        }
        let walker = ContextWalk::from(self.root.get(&path[0]));
        for p in path.iter().skip(1) {
            walker.walk(ctx, p);
        }
        walker.exec(ctx)
    }
}

impl From<TemplateTree> for ContextMapValue {
    fn from(val: TemplateTree) -> Self {
        match val {
            TemplateTree::Template(t) => t.into(),
            TemplateTree::Sequence(s) => {
                let result: Vec<ContextMapValue> = s.iter().map(|t| t.clone().into()).collect();
                ContextMapValue::Seq(result)
            }
            TemplateTree::Mapping(m) => {
                let result: BTreeMap<InnerData, ContextMapValue> = m
                    .iter()
                    .map(|(k, v)| (k.clone(), v.clone().into()))
                    .collect();
                ContextMapValue::Map(result)
            }
        }
    }
}

impl ContextMapValue {
    #[inline]
    fn new_map() -> Self {
        ContextMapValue::Map(BTreeMap::new())
    }

    fn set<T: Into<ContextMapValue>>(&mut self, val: T) {
        drop(replace(self, val.into()));
    }

    fn get_or_add_key(&mut self, key: &InnerData) -> &mut ContextMapValue {
        match self {
            ContextMapValue::Map(ref mut map) => map
                .entry(key.clone())
                .or_insert_with(ContextMapValue::new_map),
            _ => {
                let new_val = ContextMapValue::new_map();
                drop(replace(self, new_val));
                self.get_or_add_key(key)
            }
        }
    }

    pub fn exec(&self, ctx: &impl Context) -> Data {
        match self {
            ContextMapValue::Node(node) => node.exec(ctx),
            ContextMapValue::Map(map) => {
                let mut result: BTreeMap<InnerData, InnerData> = BTreeMap::new();
                for (k, v) in map.iter() {
                    match v.exec(ctx).into_result() {
                        Ok(d) => result.insert(k.clone(), d.into_inner()),
                        Err(e) => return e.into(),
                    };
                }
                result.into()
            }
            ContextMapValue::Seq(s) => {
                let result: Result<Vec<InnerData>> = s
                    .iter()
                    .map(|v| Ok(v.exec(ctx).into_result()?.into_inner()))
                    .collect();
                match result {
                    Ok(s) => Data::new(s),
                    Err(e) => e.into(),
                }
            }
            _ => Data::empty(),
        }
    }
}

#[derive(Clone, Debug)]
pub enum ContextMapValue {
    Seq(Vec<ContextMapValue>),
    Map(BTreeMap<InnerData, ContextMapValue>),
    Node(Arc<Node>),
    Empty,
}

impl Default for ContextMapValue {
    fn default() -> Self {
        ContextMapValue::Empty
    }
}

impl<T: Into<InnerData>> From<T> for ContextMapValue {
    fn from(val: T) -> Self {
        match val.into() {
            InnerData::Map(m) => {
                let mut new_val = BTreeMap::new();
                for (k, v) in m.into_iter() {
                    new_val.insert(k, v.into());
                }
                ContextMapValue::Map(new_val)
            }
            InnerData::Seq(s) => {
                let new_val: Vec<ContextMapValue> = s.into_iter().map(|i| i.into()).collect();
                ContextMapValue::Seq(new_val)
            }
            InnerData::Newtype(mut d) => d.take().into(),
            other => ContextMapValue::Node(Arc::new(Data::from(other).into())),
        }
    }
}

impl From<Node> for ContextMapValue {
    fn from(val: Node) -> Self {
        ContextMapValue::Node(Arc::new(val))
    }
}

impl From<Template> for ContextMapValue {
    fn from(val: Template) -> Self {
        ContextMapValue::Node(val.root_node())
    }
}

impl From<Data> for ContextMapValue {
    fn from(val: Data) -> Self {
        val.into_inner().into()
    }
}