mini_template/template/
loops.rs1use crate::{renderer::RenderContext, variable_container::VariableContainer};
2
3#[cfg(feature = "condition")]
4use super::condition::{Condition, ConditionEval};
5use super::{Render, Statement};
6
7#[derive(PartialEq, Debug)]
8pub struct Loop {
9    condition: Condition,
10    template: Vec<Statement>,
11}
12
13impl Loop {
14    pub fn new(condition: Condition, template: Vec<Statement>) -> Self {
15        Self {
16            condition,
17            template,
18        }
19    }
20}
21
22impl Render for Loop {
23    fn render<VC: VariableContainer>(
24        &self,
25        context: &mut RenderContext<VC>,
26        buf: &mut String,
27    ) -> crate::error::Result<()> {
28        while self.condition.eval(context)? {
29            self.template.render(context, buf)?
30        }
31        Ok(())
32    }
33}
34
35#[cfg(test)]
36mod tests {
37    use std::collections::HashMap;
38
39    use crate::{
40        renderer::RenderContext,
41        template::{
42            condition::Condition, Assign, CalculatedValue, Render, Statement, StorageMethod,
43        },
44        value::Value,
45    };
46
47    use super::Loop;
48
49    #[test]
50    fn loop_single_iteration() {
51        let l = Loop::new(
52            Condition::CalculatedValue(CalculatedValue::new(
53                StorageMethod::Variable("var"),
54                vec![],
55            )),
56            vec![
57                Statement::Calculated(CalculatedValue::new(StorageMethod::Variable("var"), vec![])),
58                Statement::Assign(Assign::new(
59                    "var",
60                    CalculatedValue::new(
61                        StorageMethod::Variable("var"),
62                        vec![("sub", vec![StorageMethod::Const(Value::Number(1.))])],
63                    ),
64                )),
65            ],
66        );
67
68        let mut modifiers = HashMap::default();
69        let sub: &'static crate::modifier::Modifier = &crate::modifier::sub;
70        modifiers.insert("sub", sub);
71        let mut ctx = RenderContext::new(
72            &modifiers,
73            HashMap::from_iter([("var".to_owned(), Value::Number(1.))]),
74        );
75        let mut buffer = String::new();
76        assert!(l.render(&mut ctx, &mut buffer).is_ok());
77        assert_eq!(buffer.as_str(), "1")
78    }
79
80    #[test]
81    fn loop_multiple_iterations() {
82        let l = Loop::new(
83            Condition::CalculatedValue(CalculatedValue::new(
84                StorageMethod::Variable("var"),
85                vec![],
86            )),
87            vec![
88                Statement::Calculated(CalculatedValue::new(StorageMethod::Variable("var"), vec![])),
89                Statement::Assign(Assign::new(
90                    "var",
91                    CalculatedValue::new(
92                        StorageMethod::Variable("var"),
93                        vec![("sub", vec![StorageMethod::Const(Value::Number(1.))])],
94                    ),
95                )),
96            ],
97        );
98
99        let mut modifiers = HashMap::default();
100        let sub: &'static crate::modifier::Modifier = &crate::modifier::sub;
101        modifiers.insert("sub", sub);
102        let mut ctx = RenderContext::new(
103            &modifiers,
104            HashMap::from_iter([("var".to_owned(), Value::Number(5.))]),
105        );
106        let mut buffer = String::new();
107        assert!(l.render(&mut ctx, &mut buffer).is_ok());
108        assert_eq!(buffer.as_str(), "54321")
109    }
110
111    #[test]
112    fn loop_no_iterations() {
113        let l = Loop::new(
114            Condition::CalculatedValue(CalculatedValue::new(
115                StorageMethod::Const(Value::Bool(false)),
116                vec![],
117            )),
118            vec![Statement::Literal("TEST")],
119        );
120
121        let modifiers = HashMap::new();
122        let mut ctx = RenderContext::new(
123            &modifiers,
124            HashMap::from_iter([("var".to_owned(), Value::Number(5.))]),
125        );
126        let mut buffer = String::new();
127        assert!(l.render(&mut ctx, &mut buffer).is_ok());
128        assert!(buffer.is_empty())
129    }
130}