brisk_it/
component.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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! Data structure created from parsing a declarative component.
use syn::{parse::Parse, Token};

/// Represents a property in a component.
///
/// ```
///   identifier: some+expression
/// ```
///
/// In which case, the `identifier` is stored in the `name` field, while `some+expression` is in `expr`.
#[derive(Debug)]
pub struct PropertyValue {
    /// name of the property
    pub name: syn::Ident,
    #[allow(missing_docs)]
    pub colon_token: Token![:],
    /// Expression of the property
    pub expr: syn::Expr,
}

/// Intermediary structure used for parsing
#[derive(Debug)]
enum ComponentContent {
    Id(syn::Ident),
    Property(PropertyValue),
    Child(ComponentInput),
}

/// Represents a component
/// ```
/// Identifier
/// {
///   id: some_name
///   prop1: value1
///   Child
///   {
///     prop2: value2
///   }
/// }
/// ```
///
/// `Identifier` is stored in the `name` field, while `prop1/value1` are in the list of `properties`.
/// And `Child` is in the list of `children`.
#[derive(Debug)]
pub struct ComponentInput {
    /// Name of the component
    pub name: syn::Ident,
    #[allow(missing_docs)]
    pub brace_token: syn::token::Brace,
    /// Identifier, used for storing in a variable
    pub id: Option<syn::Ident>,
    /// List of properties
    pub properties: Vec<PropertyValue>,
    /// List of children
    pub children: Vec<ComponentInput>,
}

impl Parse for ComponentContent {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        if input.peek2(Token![:]) {
            let lookahead1 = input.lookahead1();
            if lookahead1.peek(syn::Ident) {
                let name: syn::Ident = input.parse()?;
                if name == "id" {
                    let _: Token![:] = input.parse()?;
                    let id: syn::Ident = input.parse()?;
                    Ok(ComponentContent::Id(id))
                } else {
                    let colon_token: Token![:] = input.parse()?;
                    let expr: syn::Expr = input.parse()?;
                    Ok(ComponentContent::Property(PropertyValue {
                        name,
                        colon_token,
                        expr,
                    }))
                }
            } else {
                Err(lookahead1.error())
            }
        } else {
            Ok(Self::Child(ComponentInput::parse(input)?))
        }
    }
}

impl syn::parse::Parse for ComponentInput {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        let name = input.parse::<syn::Ident>()?;

        let unparsed_content;
        let brace_token = syn::braced!(unparsed_content in input);
        let content = unparsed_content.parse_terminated(ComponentContent::parse, Token![,])?;

        let mut id = Default::default();
        let mut properties: Vec<PropertyValue> = Default::default();
        let mut children: Vec<ComponentInput> = Default::default();

        for item in content {
            match item {
                ComponentContent::Id(idid) => id = Some(idid),
                ComponentContent::Property(prop) => {
                    properties.push(prop);
                }
                ComponentContent::Child(child) => {
                    children.push(child);
                }
            }
        }

        Ok(Self {
            name,
            brace_token,
            id,
            properties,
            children,
        })
    }
}