1use quote::ToTokens;
2
3#[proc_macro]
4pub fn callback(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
5 let clone = syn::parse_macro_input!(input as Callback);
6 clone.into_token_stream().into()
7}
8
9struct Callback {
10 captures: Vec<Capture>,
11 body: Closure,
12}
13
14impl syn::parse::Parse for Callback {
15 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
16 let mut captures = Vec::new();
17
18 while let Ok(capture) = Capture::parse(input) {
19 captures.push(capture);
20
21 if input.peek(syn::Token![,]) {
22 input.parse::<syn::Token![,]>()?;
23 }
24 }
25
26 let body = input.parse::<Closure>()?;
27
28 if input.peek(syn::Token![,]) {
29 input.parse::<syn::Token![,]>()?;
30 }
31
32 Ok(Self { captures, body })
33 }
34}
35
36impl ToTokens for Callback {
37 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
38 let captures = &self.captures;
39 let cb = &self.body;
40
41 tokens.extend(quote::quote! {{
42 #( #captures )*
43 yew::Callback::from(#cb)
44 }});
45 }
46}
47
48struct Capture {
49 pub alias: Option<syn::Ident>,
50 pub name: syn::Expr,
51}
52
53impl syn::parse::Parse for Capture {
54 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
55 let name = input.parse::<syn::Ident>()?;
56
57 let (alias, name) = if input.peek(syn::Token![=]) {
58 input.parse::<syn::Token![=]>()?;
59 let expr = input.parse::<syn::Expr>()?;
60 (Some(name), expr)
61 } else {
62 let mut segments = syn::punctuated::Punctuated::new();
63 segments.push_value(name.into());
64
65 let path = syn::Path {
66 leading_colon: None,
67 segments,
68 };
69 let exprpath = syn::ExprPath {
70 attrs: Vec::new(),
71 qself: None,
72 path,
73 };
74
75 (None, syn::Expr::Path(exprpath))
76 };
77
78 Ok(Self { alias, name })
79 }
80}
81
82impl ToTokens for Capture {
83 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
84 let name = &self.name;
85
86 let token = if let Some(alias) = &self.alias {
87 quote::quote! { let #alias = #name.clone(); }
88 } else {
89 quote::quote! { let #name = #name.clone(); }
90 };
91
92 tokens.extend(token);
93 }
94}
95
96struct Closure {
97 cb: syn::ExprClosure,
98}
99
100impl syn::parse::Parse for Closure {
101 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
102 Ok(Self { cb: input.parse()? })
103 }
104}
105
106impl ToTokens for Closure {
107 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
108 self.cb.to_tokens(tokens);
109 }
110}