dioxus_rsx/
forloop.rs

1use super::*;
2use location::DynIdx;
3use proc_macro2::TokenStream as TokenStream2;
4use syn::{braced, token::Brace, Expr, Pat};
5
6#[non_exhaustive]
7#[derive(PartialEq, Eq, Clone, Debug)]
8pub struct ForLoop {
9    pub for_token: Token![for],
10    pub pat: Pat,
11    pub in_token: Token![in],
12    pub expr: Box<Expr>,
13    pub brace: Brace,
14    pub body: TemplateBody,
15    pub dyn_idx: DynIdx,
16}
17
18impl Parse for ForLoop {
19    fn parse(input: ParseStream) -> Result<Self> {
20        // todo: better partial parsing
21        // A bit stolen from `ExprForLoop` in the `syn` crate
22        let for_token = input.parse()?;
23        let pat = input.call(Pat::parse_single)?;
24        let in_token = input.parse()?;
25        let expr = input.call(Expr::parse_without_eager_brace)?;
26
27        let content;
28        let brace = braced!(content in input);
29        let body = content.parse()?;
30
31        Ok(Self {
32            for_token,
33            pat,
34            in_token,
35            brace,
36            expr: Box::new(expr),
37            body,
38            dyn_idx: DynIdx::default(),
39        })
40    }
41}
42
43impl ToTokens for ForLoop {
44    fn to_tokens(&self, tokens: &mut TokenStream2) {
45        let ForLoop {
46            pat, expr, body, ..
47        } = self;
48
49        // the temporary is important so we create a lifetime binding
50        tokens.append_all(quote! {
51            {
52                let ___nodes = (#expr).into_iter().map(|#pat| { #body }).into_dyn_node();
53                ___nodes
54            }
55        });
56    }
57}
58
59#[test]
60fn parses_for_loop() {
61    let toks = quote! {
62        for item in 0..10 {
63            div { "cool-{item}" }
64            div { "cool-{item}" }
65            div { "cool-{item}" }
66        }
67    };
68
69    let for_loop: ForLoop = syn::parse2(toks).unwrap();
70    assert!(for_loop.body.roots.len() == 3);
71}