templar 0.5.0

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

#[derive(Clone)]
pub enum Node {
    Expr(Vec<Node>),
    Data(Data),
    Scope(Box<Node>),
    Value(Vec<InnerData>),
    Operation(Arc<Operation>),
    Array(Vec<Node>),
    Map(BTreeMap<InnerData, Node>),
}

impl fmt::Debug for Node {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Node::Expr(inner) => write!(f, "Node::Expr({:?})", inner),
            Node::Operation(inner) => write!(f, "Node::Operation({:?})", inner),
            Node::Data(inner) => write!(f, "Node::Data({:?})", inner),
            Node::Value(inner) => write!(f, "Node::Value({:?})", inner),
            Node::Array(inner) => write!(f, "Node::Array({:?})", inner),
            Node::Map(inner) => write!(f, "Node::Map({:?})", inner),
            Node::Scope(inner) => write!(f, "Node::Scope({:?})", inner),
        }
    }
}

impl Default for Node {
    fn default() -> Self {
        Data::empty().into()
    }
}

impl Node {
    pub(crate) fn exec(&self, ctx: &impl Context) -> Data {
        match self {
            Self::Data(d) => d.clone(),
            Self::Operation(op) => op.exec(ctx),
            Self::Value(a) => {
                let docs = a.iter().collect::<Vec<&InnerData>>();
                ctx.get_path(&docs)
            }
            Self::Scope(i) => {
                let local_context = ctx.create_scope();
                i.exec(&local_context)
            }
            Self::Array(s) => Data::from_vec(s.iter().map(|n| n.exec(ctx)).collect()),
            Self::Map(m) => {
                let mut map: BTreeMap<InnerData, InnerData> = BTreeMap::new();
                for (key, node) in m.iter() {
                    match node.exec(ctx).into_inner() {
                        InnerData::Err(e) => return e.into(),
                        d => map.insert(key.clone(), d),
                    };
                }
                map.into()
            }
            Self::Expr(a) => {
                let mut res: Vec<Data> = a.iter().map(|n| n.exec(ctx)).collect();
                if res.is_empty() {
                    Data::empty()
                } else if res.len() == 1 {
                    res.remove(0).unwrap()
                } else {
                    Data::from_vec(res)
                }
            }
        }
    }

    pub(crate) fn set_operation(self, op: Operations) -> Node {
        match self {
            Node::Expr(nodes) => Node::Operation(Arc::new(op.build(nodes))),
            _ => self,
        }
    }

    pub(crate) fn into_scope(self) -> Node {
        Node::Scope(Box::new(self))
    }

    pub(crate) fn into_document(self) -> Result<Data> {
        match self {
            Self::Data(d) => Ok(d.into_result()?),
            _ => Err(TemplarError::RenderFailure(
                "Attempted document conversion on unprocessed node".into(),
            )),
        }
    }

    pub fn render(&self, ctx: &impl Context) -> Result<String> {
        self.exec(ctx).render()
    }
}

impl From<Vec<Node>> for Node {
    fn from(mut n: Vec<Node>) -> Node {
        match n.len() {
            1 => n.pop().unwrap(),
            0 => Data::empty().into(),
            _ => Node::Expr(n),
        }
    }
}

impl From<Data> for Node {
    fn from(d: Data) -> Self {
        Self::Data(d)
    }
}