yew_macro/
use_prepared_state.rs1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::parse::{Parse, ParseStream};
4use syn::{Expr, ExprClosure, ReturnType, Token, Type};
5
6#[derive(Debug)]
7pub struct PreparedState {
8 closure: ExprClosure,
9 return_type: Type,
10 deps: Expr,
11}
12
13impl Parse for PreparedState {
14 fn parse(input: ParseStream) -> syn::Result<Self> {
15 let deps = input.parse()?;
17
18 input.parse::<Token![,]>().map_err(|e| {
19 syn::Error::new(
20 e.span(),
21 "this hook takes 2 arguments but 1 argument was supplied",
22 )
23 })?;
24
25 let expr: Expr = input.parse()?;
27
28 let closure = match expr {
29 Expr::Closure(m) => m,
30 other => return Err(syn::Error::new_spanned(other, "expected closure")),
31 };
32
33 let return_type = match &closure.output {
34 ReturnType::Default => {
35 return Err(syn::Error::new_spanned(
36 &closure,
37 "You must specify a return type for this closure. This is used when the \
38 closure is omitted from the client side rendering bundle.",
39 ))
40 }
41 ReturnType::Type(_rarrow, ty) => *ty.to_owned(),
42 };
43
44 if !input.is_empty() {
45 let maybe_trailing_comma = input.lookahead1();
46
47 if !maybe_trailing_comma.peek(Token![,]) {
48 return Err(maybe_trailing_comma.error());
49 }
50 }
51
52 Ok(Self {
53 closure,
54 return_type,
55 deps,
56 })
57 }
58}
59
60impl PreparedState {
61 #[cfg(not(nightly_yew))]
63 pub fn rewrite_to_closure_with_async_block(&self) -> ExprClosure {
64 use proc_macro2::Span;
65 use syn::parse_quote;
66
67 let async_token = match &self.closure.asyncness {
68 Some(m) => m,
69 None => return self.closure.clone(),
70 };
71
72 let move_token = self
74 .closure
75 .capture
76 .unwrap_or_else(|| Token));
77 let body = &self.closure.body;
78
79 let inner = parse_quote! {
80 #async_token #move_token {
81 #body
82 }
83 };
84
85 let mut closure = self.closure.clone();
86
87 closure.asyncness = None;
88 closure.output = ReturnType::Default;
90
91 closure.body = inner;
92
93 closure.attrs.push(parse_quote! { #[allow(unused_braces)] });
94
95 closure
96 }
97
98 #[cfg(nightly_yew)]
99 pub fn rewrite_to_closure_with_async_block(&self) -> ExprClosure {
100 self.closure.clone()
101 }
102
103 pub fn to_token_stream_with_closure(&self) -> TokenStream {
104 let deps = &self.deps;
105 let rt = &self.return_type;
106 let closure = self.rewrite_to_closure_with_async_block();
107
108 match &self.closure.asyncness {
109 Some(_) => quote! {
110 ::yew::functional::use_prepared_state_with_suspension::<#rt, _, _, _>(#deps, #closure)
111 },
112 None => quote! {
113 ::yew::functional::use_prepared_state::<#rt, _, _>(#deps, #closure)
114 },
115 }
116 }
117
118 pub fn to_token_stream_without_closure(&self) -> TokenStream {
122 let deps = &self.deps;
123 let rt = &self.return_type;
124
125 quote! {
126 ::yew::functional::use_prepared_state::<#rt, _>(#deps)
127 }
128 }
129}