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}