dioxus_rsx/
forloop.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use super::*;
use location::DynIdx;
use proc_macro2::TokenStream as TokenStream2;
use syn::{braced, token::Brace, Expr, Pat};

#[non_exhaustive]
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ForLoop {
    pub for_token: Token![for],
    pub pat: Pat,
    pub in_token: Token![in],
    pub expr: Box<Expr>,
    pub brace: Brace,
    pub body: TemplateBody,
    pub dyn_idx: DynIdx,
}

impl Parse for ForLoop {
    fn parse(input: ParseStream) -> Result<Self> {
        // todo: better partial parsing
        // A bit stolen from `ExprForLoop` in the `syn` crate
        let for_token = input.parse()?;
        let pat = input.call(Pat::parse_single)?;
        let in_token = input.parse()?;
        let expr = input.call(Expr::parse_without_eager_brace)?;

        let content;
        let brace = braced!(content in input);
        let body = content.parse()?;

        Ok(Self {
            for_token,
            pat,
            in_token,
            brace,
            expr: Box::new(expr),
            body,
            dyn_idx: DynIdx::default(),
        })
    }
}

impl ToTokens for ForLoop {
    fn to_tokens(&self, tokens: &mut TokenStream2) {
        let ForLoop {
            pat, expr, body, ..
        } = self;

        // the temporary is important so we create a lifetime binding
        tokens.append_all(quote! {
            {
                let ___nodes = (#expr).into_iter().map(|#pat| { #body }).into_dyn_node();
                ___nodes
            }
        });
    }
}

#[test]
fn parses_for_loop() {
    let toks = quote! {
        for item in 0..10 {
            div { "cool-{item}" }
            div { "cool-{item}" }
            div { "cool-{item}" }
        }
    };

    let for_loop: ForLoop = syn::parse2(toks).unwrap();
    assert!(for_loop.body.roots.len() == 3);
}