bracket/helper/
each.rs

1//! Block helper that iterates arrays and objects.
2use crate::{
3    //error::HelperError,
4    helper::{Helper, HelperValue},
5    parser::ast::Node,
6    render::{Context, Render, Scope},
7};
8
9use serde_json::{Number, Value};
10
11const FIRST: &str = "first";
12const LAST: &str = "last";
13const KEY: &str = "key";
14const INDEX: &str = "index";
15
16/// Iterate an array or object.
17///
18/// Accepts a single argument of the target to iterate, if the
19/// target is not an array or object this will return an error.
20///
21/// Each iteration sets a new scope with the local variables:
22///
23/// * `@first`: If this is the first iteration `true`.
24/// * `@last`: If this is the last iteration `true`.
25///
26/// Note that these variables are set even for objects where iteration order
27/// is not guaranteed which can be useful.
28///
29/// For objects the `@key` variable contains the name of the field; for
30/// arrays the `@index` variable contains the current zero-based index.
31///
32pub struct Each;
33
34impl Helper for Each {
35    fn call<'render, 'call>(
36        &self,
37        rc: &mut Render<'render>,
38        ctx: &Context<'call>,
39        template: Option<&'render Node<'render>>,
40    ) -> HelperValue {
41        ctx.arity(1..1)?;
42
43        if let Some(template) = template {
44            //let name = ctx.name();
45            let args = ctx.arguments();
46            let target = args.get(0).unwrap();
47
48            rc.push_scope(Scope::new());
49            match target {
50                Value::Object(t) => {
51                    let mut it = t.into_iter().enumerate();
52                    let mut next_value = it.next();
53                    while let Some((index, (key, value))) = next_value {
54                        next_value = it.next();
55                        if let Some(ref mut scope) = rc.scope_mut() {
56                            scope.set_local(FIRST, Value::Bool(index == 0));
57                            scope.set_local(
58                                LAST,
59                                Value::Bool(next_value.is_none()),
60                            );
61                            scope.set_local(
62                                INDEX,
63                                Value::Number(Number::from(index)),
64                            );
65                            scope.set_local(KEY, Value::String(key.to_owned()));
66                            scope.set_base_value(value.clone());
67                        }
68                        rc.template(template)?;
69                    }
70                }
71                Value::Array(t) => {
72                    let len = t.len();
73                    for (index, value) in t.into_iter().enumerate() {
74                        if let Some(ref mut scope) = rc.scope_mut() {
75                            scope.set_local(FIRST, Value::Bool(index == 0));
76                            scope
77                                .set_local(LAST, Value::Bool(index == len - 1));
78                            scope.set_local(
79                                INDEX,
80                                Value::Number(Number::from(index)),
81                            );
82                            scope.set_base_value(value.clone());
83                        }
84                        rc.template(template)?;
85                    }
86                }
87                _ => {
88                    //return Err(HelperError::IterableExpected(
89                    //name.to_string(),
90                    //0,
91                    //))
92                }
93            }
94            rc.pop_scope();
95        }
96
97        Ok(None)
98    }
99}