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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
use quote::format_ident;
use syn::{bracketed, parenthesized, parse::{Parse, ParseStream}, Expr, Ident, LitStr, Token, Type};
use crate::form::{ParsedChild, ParsedInput, ParsedOnSubmit, SelectOptions};
macro_rules! parse_key_value {
($input:expr, $name:ident as $ty:ty) => {{
let key = $input.parse::<Ident>()?;
$input.parse::<Token![=]>()?;
let value = $input.parse::<$ty>()?;
if key != format_ident!(stringify!($name)) {
panic!("Expected key name to be {}, but found: {key}", stringify!($name));
}
if $input.peek(Token![,]) {
$input.parse::<Token![,]>()?;
}
value
}};
}
impl Parse for SelectOptions {
fn parse(input: ParseStream) -> syn::Result<Self> {
let content;
bracketed!(content in input);
let inner = content.parse_terminated(
|arg| {
let paren;
parenthesized!(paren in arg);
let lit = paren.parse::<LitStr>()?;
paren.parse::<Token![,]>()?;
let expr = paren.parse::<Expr>()?;
Ok((lit, expr))
},
Token![,],
)?;
Ok(Self(inner.into_iter().collect()))
}
}
impl Parse for ParsedInput {
fn parse(input: ParseStream) -> syn::Result<Self> {
let on_submit = input.parse::<syn::Ident>()?;
if on_submit != format_ident!("on_submit") {
panic!("Did not find correct `on_submit`: {on_submit}")
}
input.parse::<Token![=]>()?;
let on_submit = input.parse::<ParsedOnSubmit>()?;
let mut children = Vec::new();
while !input.is_empty() {
children.push(input.parse::<ParsedChild>()?);
}
Ok(Self {
on_submit,
children,
})
}
}
impl Parse for ParsedChild {
fn parse(input: ParseStream) -> syn::Result<Self> {
input.parse::<Token![<]>()?;
let variant = input.parse::<Ident>()?;
let output = match variant {
variant if variant == format_ident!("Input") => {
let name = parse_key_value!(input, name as Ident);
let rust_type = parse_key_value!(input, rust_type as Type);
let html_type = parse_key_value!(input, html_type as LitStr);
let label = parse_key_value!(input, label as LitStr);
ParsedChild::Input {
name,
rust_type,
html_type,
label,
}
}
variant if variant == format_ident!("Select") => {
let name = parse_key_value!(input, name as Ident);
let rust_type = parse_key_value!(input, rust_type as Type);
let label = parse_key_value!(input, label as LitStr);
let options = parse_key_value!(input, options as SelectOptions);
ParsedChild::Select {
name,
label,
options,
rust_type,
}
}
_ => panic!("Unkown form child variant: {variant}"),
};
input.parse::<Token![/]>()?;
input.parse::<Token![>]>()?;
Ok(output)
}
}
impl Parse for ParsedOnSubmit {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut inputs = Vec::new();
input.parse::<Token![|]>()?;
while !input.peek(Token![|]) {
inputs.push(input.parse::<Ident>()?);
if input.peek(Token![,]) {
input.parse::<Token![,]>()?;
}
}
input.parse::<Token![|]>()?;
let block = input.parse::<Expr>()?;
input.parse::<Token![;]>()?;
Ok(Self { inputs, block })
}
}
|