mini_template 0.1.1

Small template engine with smarty like syntax
Documentation
use crate::{renderer::RenderContext, variable_container::VariableContainer};

use super::CalculatedValue;

#[derive(Debug, PartialEq)]
pub enum Condition {
    Or(OrCondition),
    And(AndCondition),
    CalculatedValue(CalculatedValue),
    Compare(CompareCondition),
}

#[cfg(test)]
impl Condition {
    pub fn and(and: Vec<Condition>) -> Condition {
        Condition::And(AndCondition::new(and))
    }

    pub fn or(and: Vec<Condition>) -> Condition {
        Condition::Or(OrCondition::new(and))
    }
}

impl ConditionEval for Condition {
    fn eval<VC: VariableContainer>(
        &self,
        context: &RenderContext<VC>,
    ) -> crate::error::Result<bool> {
        match self {
            Self::Or(c) => c.eval(context),
            Self::And(c) => c.eval(context),
            Self::Compare(c) => c.eval(context),
            Self::CalculatedValue(c) => Ok(c.calc(context)?.as_bool()),
        }
    }
}

pub trait ConditionEval {
    fn eval<VC: VariableContainer>(
        &self,
        context: &RenderContext<VC>,
    ) -> crate::error::Result<bool>;
}

#[derive(Debug, PartialEq)]
pub struct OrCondition {
    conditions: Vec<Condition>,
}

impl OrCondition {
    pub fn new(conditions: Vec<Condition>) -> Self {
        Self { conditions }
    }
}

impl ConditionEval for OrCondition {
    fn eval<VC: VariableContainer>(
        &self,
        context: &RenderContext<VC>,
    ) -> crate::error::Result<bool> {
        for condition in &self.conditions {
            if condition.eval(context)? {
                return Ok(true);
            }
        }
        Ok(false)
    }
}

#[derive(Debug, PartialEq)]
pub struct AndCondition {
    conditions: Vec<Condition>,
}

impl AndCondition {
    pub fn new(conditions: Vec<Condition>) -> Self {
        Self { conditions }
    }
}

impl ConditionEval for AndCondition {
    fn eval<VC: VariableContainer>(
        &self,
        context: &RenderContext<VC>,
    ) -> crate::error::Result<bool> {
        for condition in &self.conditions {
            if !condition.eval(context)? {
                return Ok(false);
            }
        }
        Ok(true)
    }
}

#[derive(Debug, PartialEq)]
pub struct CompareCondition {
    pub(crate) left: CalculatedValue,
    pub(crate) operator: CompareOperator,
    pub(crate) right: CalculatedValue,
}

impl ConditionEval for CompareCondition {
    fn eval<VC: VariableContainer>(
        &self,
        context: &RenderContext<VC>,
    ) -> crate::error::Result<bool> {
        let left = self.left.calc(context)?;
        let right = self.right.calc(context)?;
        let r = match self.operator {
            CompareOperator::EQ => left == right,
            CompareOperator::NE => left != right,
            CompareOperator::LT => left < right,
            CompareOperator::LE => left <= right,
            CompareOperator::GT => left > right,
            CompareOperator::GE => left >= right,
        };
        Ok(r)
    }
}

#[derive(Debug, PartialEq)]
pub enum CompareOperator {
    EQ,
    NE,
    LT,
    LE,
    GT,
    GE,
}