server_fn_macro/
lib.rs

1#![cfg_attr(all(feature = "nightly", rustc_nightly), feature(proc_macro_span))]
2#![forbid(unsafe_code)]
3#![deny(missing_docs)]
4
5//! Implementation of the `server_fn` macro.
6//!
7//! This crate contains the implementation of the `server_fn` macro. [`server_macro_impl`] can be used to implement custom versions of the macro for different frameworks that allow users to pass a custom context from the server to the server function.
8
9use convert_case::{Case, Converter};
10use proc_macro2::{Span, TokenStream as TokenStream2};
11use quote::{format_ident, quote, quote_spanned, ToTokens};
12use syn::{
13    parse::{Parse, ParseStream},
14    punctuated::Punctuated,
15    spanned::Spanned,
16    *,
17};
18
19/// A parsed server function call.
20pub struct ServerFnCall {
21    args: ServerFnArgs,
22    body: ServerFnBody,
23    default_path: String,
24    server_fn_path: Option<Path>,
25    preset_server: Option<Type>,
26    default_protocol: Option<Type>,
27    default_input_encoding: Option<Type>,
28    default_output_encoding: Option<Type>,
29}
30
31impl ServerFnCall {
32    /// Parse the arguments of a server function call.
33    ///
34    /// ```ignore
35    /// #[proc_macro_attribute]
36    /// pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
37    ///     match ServerFnCall::parse(
38    ///         "/api",
39    ///         args.into(),
40    ///         s.into(),
41    ///     ) {
42    ///         Err(e) => e.to_compile_error().into(),
43    ///         Ok(s) => s.to_token_stream().into(),
44    ///     }
45    /// }
46    /// ```
47    pub fn parse(
48        default_path: &str,
49        args: TokenStream2,
50        body: TokenStream2,
51    ) -> Result<Self> {
52        let args = syn::parse2(args)?;
53        let body = syn::parse2(body)?;
54        let mut myself = ServerFnCall {
55            default_path: default_path.into(),
56            args,
57            body,
58            server_fn_path: None,
59            preset_server: None,
60            default_protocol: None,
61            default_input_encoding: None,
62            default_output_encoding: None,
63        };
64
65        // We need to make the server function body send if actix is enabled. To
66        // do that, we wrap the body in a SendWrapper, which is an async fn that
67        // asserts that the future is always polled from the same thread.
68        if cfg!(feature = "actix") {
69            let server_fn_path = myself.server_fn_path();
70            let block = myself.body.block.to_token_stream();
71            myself.body.block = quote! {
72                {
73                    #server_fn_path::actix::SendWrapper::new(async move {
74                        #block
75                    })
76                    .await
77                }
78            };
79        }
80
81        Ok(myself)
82    }
83
84    /// Get a reference to the server function arguments.
85    pub fn get_args(&self) -> &ServerFnArgs {
86        &self.args
87    }
88
89    /// Get a mutable reference to the server function arguments.
90    pub fn get_args_mut(&mut self) -> &mut ServerFnArgs {
91        &mut self.args
92    }
93
94    /// Get a reference to the server function body.
95    pub fn get_body(&self) -> &ServerFnBody {
96        &self.body
97    }
98
99    /// Get a mutable reference to the server function body.
100    pub fn get_body_mut(&mut self) -> &mut ServerFnBody {
101        &mut self.body
102    }
103
104    /// Set the path to the server function crate.
105    pub fn default_server_fn_path(mut self, path: Option<Path>) -> Self {
106        self.server_fn_path = path;
107        self
108    }
109
110    /// Set the default server implementation.
111    pub fn default_server_type(mut self, server: Option<Type>) -> Self {
112        self.preset_server = server;
113        self
114    }
115
116    /// Set the default protocol.
117    pub fn default_protocol(mut self, protocol: Option<Type>) -> Self {
118        self.default_protocol = protocol;
119        self
120    }
121
122    /// Set the default input http encoding. This will be used by [`Self::protocol`]
123    /// if no protocol or default protocol is set or if only the output encoding is set
124    ///
125    /// Defaults to `PostUrl`
126    pub fn default_input_encoding(mut self, protocol: Option<Type>) -> Self {
127        self.default_input_encoding = protocol;
128        self
129    }
130
131    /// Set the default output http encoding. This will be used by [`Self::protocol`]
132    /// if no protocol or default protocol is set or if only the input encoding is set
133    ///
134    /// Defaults to `Json`
135    pub fn default_output_encoding(mut self, protocol: Option<Type>) -> Self {
136        self.default_output_encoding = protocol;
137        self
138    }
139
140    /// Get the client type to use for the server function.
141    pub fn client_type(&self) -> Type {
142        let server_fn_path = self.server_fn_path();
143        if let Some(client) = self.args.client.clone() {
144            client
145        } else if cfg!(feature = "reqwest") {
146            parse_quote! {
147                #server_fn_path::client::reqwest::ReqwestClient
148            }
149        } else {
150            parse_quote! {
151                #server_fn_path::client::browser::BrowserClient
152            }
153        }
154    }
155
156    /// Get the server type to use for the server function.
157    pub fn server_type(&self) -> Type {
158        let server_fn_path = self.server_fn_path();
159        if !cfg!(feature = "ssr") {
160            parse_quote! {
161                #server_fn_path::mock::BrowserMockServer
162            }
163        } else if cfg!(feature = "axum") {
164            parse_quote! {
165                #server_fn_path::axum::AxumServerFnBackend
166            }
167        } else if cfg!(feature = "actix") {
168            parse_quote! {
169                #server_fn_path::actix::ActixServerFnBackend
170            }
171        } else if cfg!(feature = "generic") {
172            parse_quote! {
173                #server_fn_path::axum::AxumServerFnBackend
174            }
175        } else if let Some(server) = &self.args.server {
176            server.clone()
177        } else if let Some(server) = &self.preset_server {
178            server.clone()
179        } else {
180            // fall back to the browser version, to avoid erroring out
181            // in things like doctests
182            // in reality, one of the above needs to be set
183            parse_quote! {
184                #server_fn_path::mock::BrowserMockServer
185            }
186        }
187    }
188
189    /// Get the path to the server_fn crate.
190    pub fn server_fn_path(&self) -> Path {
191        self.server_fn_path
192            .clone()
193            .unwrap_or_else(|| parse_quote! { server_fn })
194    }
195
196    /// Get the input http encoding if no protocol is set
197    fn input_http_encoding(&self) -> Type {
198        let server_fn_path = self.server_fn_path();
199        self.args
200            .input
201            .as_ref()
202            .map(|n| {
203                if self.args.builtin_encoding {
204                    parse_quote! { #server_fn_path::codec::#n }
205                } else {
206                    n.clone()
207                }
208            })
209            .unwrap_or_else(|| {
210                self.default_input_encoding.clone().unwrap_or_else(
211                    || parse_quote!(#server_fn_path::codec::PostUrl),
212                )
213            })
214    }
215
216    /// Get the output http encoding if no protocol is set
217    fn output_http_encoding(&self) -> Type {
218        let server_fn_path = self.server_fn_path();
219        self.args
220            .output
221            .as_ref()
222            .map(|n| {
223                if self.args.builtin_encoding {
224                    parse_quote! { #server_fn_path::codec::#n }
225                } else {
226                    n.clone()
227                }
228            })
229            .unwrap_or_else(|| {
230                self.default_output_encoding.clone().unwrap_or_else(
231                    || parse_quote!(#server_fn_path::codec::Json),
232                )
233            })
234    }
235
236    /// Get the http input and output encodings for the server function
237    /// if no protocol is set
238    pub fn http_encodings(&self) -> Option<(Type, Type)> {
239        self.args
240            .protocol
241            .is_none()
242            .then(|| (self.input_http_encoding(), self.output_http_encoding()))
243    }
244
245    /// Get the protocol to use for the server function.
246    pub fn protocol(&self) -> Type {
247        let server_fn_path = self.server_fn_path();
248        let default_protocol = &self.default_protocol;
249        self.args.protocol.clone().unwrap_or_else(|| {
250            // If both the input and output encodings are none,
251            // use the default protocol
252            if self.args.input.is_none() && self.args.output.is_none() {
253                default_protocol.clone().unwrap_or_else(|| {
254                    parse_quote! {
255                        #server_fn_path::Http<#server_fn_path::codec::PostUrl, #server_fn_path::codec::Json>
256                    }
257                })
258            } else {
259                // Otherwise use the input and output encodings, filling in
260                // defaults if necessary
261                let input = self.input_http_encoding();
262                let output = self.output_http_encoding();
263                parse_quote! {
264                    #server_fn_path::Http<#input, #output>
265                }
266            }
267        })
268    }
269
270    fn input_ident(&self) -> Option<String> {
271        match &self.args.input {
272            Some(Type::Path(path)) => {
273                path.path.segments.last().map(|seg| seg.ident.to_string())
274            }
275            None => Some("PostUrl".to_string()),
276            _ => None,
277        }
278    }
279
280    fn websocket_protocol(&self) -> bool {
281        if let Type::Path(path) = self.protocol() {
282            path.path
283                .segments
284                .iter()
285                .any(|segment| segment.ident == "Websocket")
286        } else {
287            false
288        }
289    }
290
291    fn serde_path(&self) -> String {
292        let path = self
293            .server_fn_path()
294            .segments
295            .iter()
296            .map(|segment| segment.ident.to_string())
297            .collect::<Vec<_>>();
298        let path = path.join("::");
299        format!("{path}::serde")
300    }
301
302    /// Get the docs for the server function.
303    pub fn docs(&self) -> TokenStream2 {
304        // pass through docs from the function body
305        self.body
306            .docs
307            .iter()
308            .map(|(doc, span)| quote_spanned!(*span=> #[doc = #doc]))
309            .collect::<TokenStream2>()
310    }
311
312    fn fn_name_as_str(&self) -> String {
313        self.body.ident.to_string()
314    }
315
316    fn struct_tokens(&self) -> TokenStream2 {
317        let server_fn_path = self.server_fn_path();
318        let fn_name_as_str = self.fn_name_as_str();
319        let link_to_server_fn = format!(
320            "Serialized arguments for the [`{fn_name_as_str}`] server \
321             function.\n\n"
322        );
323        let args_docs = quote! {
324            #[doc = #link_to_server_fn]
325        };
326
327        let docs = self.docs();
328
329        let input_ident = self.input_ident();
330
331        enum PathInfo {
332            Serde,
333            Rkyv,
334            None,
335        }
336
337        let (path, derives) = match input_ident.as_deref() {
338            Some("Rkyv") => (
339                PathInfo::Rkyv,
340                quote! {
341                    Clone, #server_fn_path::rkyv::Archive, #server_fn_path::rkyv::Serialize, #server_fn_path::rkyv::Deserialize
342                },
343            ),
344            Some("MultipartFormData")
345            | Some("Streaming")
346            | Some("StreamingText") => (PathInfo::None, quote! {}),
347            Some("SerdeLite") => (
348                PathInfo::Serde,
349                quote! {
350                    Clone, #server_fn_path::serde_lite::Serialize, #server_fn_path::serde_lite::Deserialize
351                },
352            ),
353            _ => match &self.args.input_derive {
354                Some(derives) => {
355                    let d = &derives.elems;
356                    (PathInfo::None, quote! { #d })
357                }
358                None => {
359                    if self.websocket_protocol() {
360                        (PathInfo::None, quote! {})
361                    } else {
362                        (
363                            PathInfo::Serde,
364                            quote! {
365                                Clone, #server_fn_path::serde::Serialize, #server_fn_path::serde::Deserialize
366                            },
367                        )
368                    }
369                }
370            },
371        };
372        let addl_path = match path {
373            PathInfo::Serde => {
374                let serde_path = self.serde_path();
375                quote! {
376                    #[serde(crate = #serde_path)]
377                }
378            }
379            PathInfo::Rkyv => quote! {},
380            PathInfo::None => quote! {},
381        };
382
383        let vis = &self.body.vis;
384        let struct_name = self.struct_name();
385        let fields = self
386            .body
387            .inputs
388            .iter()
389            .map(|server_fn_arg| {
390                let mut typed_arg = server_fn_arg.arg.clone();
391                // strip `mut`, which is allowed in fn args but not in struct fields
392                if let Pat::Ident(ident) = &mut *typed_arg.pat {
393                    ident.mutability = None;
394                }
395                let attrs = &server_fn_arg.server_fn_attributes;
396                quote! { #(#attrs ) * #vis #typed_arg }
397            })
398            .collect::<Vec<_>>();
399
400        quote! {
401            #args_docs
402            #docs
403            #[derive(Debug, #derives)]
404            #addl_path
405            #vis struct #struct_name {
406                #(#fields),*
407            }
408        }
409    }
410
411    /// Get the name of the server function struct that will be submitted to inventory.
412    ///
413    /// This will either be the name specified in the macro arguments or the PascalCase
414    /// version of the function name.
415    pub fn struct_name(&self) -> Ident {
416        // default to PascalCase version of function name if no struct name given
417        self.args.struct_name.clone().unwrap_or_else(|| {
418            let upper_camel_case_name = Converter::new()
419                .from_case(Case::Snake)
420                .to_case(Case::UpperCamel)
421                .convert(self.body.ident.to_string());
422            Ident::new(&upper_camel_case_name, self.body.ident.span())
423        })
424    }
425
426    /// Wrap the struct name in any custom wrapper specified in the macro arguments
427    /// and return it as a type
428    fn wrapped_struct_name(&self) -> TokenStream2 {
429        let struct_name = self.struct_name();
430        if let Some(wrapper) = self.args.custom_wrapper.as_ref() {
431            quote! { #wrapper<#struct_name> }
432        } else {
433            quote! { #struct_name }
434        }
435    }
436
437    /// Wrap the struct name in any custom wrapper specified in the macro arguments
438    /// and return it as a type with turbofish
439    fn wrapped_struct_name_turbofish(&self) -> TokenStream2 {
440        let struct_name = self.struct_name();
441        if let Some(wrapper) = self.args.custom_wrapper.as_ref() {
442            quote! { #wrapper::<#struct_name> }
443        } else {
444            quote! { #struct_name }
445        }
446    }
447
448    /// Generate the code to submit the server function type to inventory.
449    pub fn submit_to_inventory(&self) -> TokenStream2 {
450        // auto-registration with inventory
451        if cfg!(feature = "ssr") {
452            let server_fn_path = self.server_fn_path();
453            let wrapped_struct_name = self.wrapped_struct_name();
454            let wrapped_struct_name_turbofish =
455                self.wrapped_struct_name_turbofish();
456            quote! {
457                #server_fn_path::inventory::submit! {{
458                    use #server_fn_path::{ServerFn, codec::Encoding};
459                    #server_fn_path::ServerFnTraitObj::new::<#wrapped_struct_name>(
460                        |req| Box::pin(#wrapped_struct_name_turbofish::run_on_server(req)),
461                    )
462                }}
463            }
464        } else {
465            quote! {}
466        }
467    }
468
469    /// Generate the server function's URL. This will be the prefix path, then by the
470    /// module path if `SERVER_FN_MOD_PATH` is set, then the function name, and finally
471    /// a hash of the function name and location in the source code.
472    pub fn server_fn_url(&self) -> TokenStream2 {
473        let default_path = &self.default_path;
474        let prefix =
475            self.args.prefix.clone().unwrap_or_else(|| {
476                LitStr::new(default_path, Span::call_site())
477            });
478        let server_fn_path = self.server_fn_path();
479        let fn_path = self.args.fn_path.clone().map(|fn_path| {
480            let fn_path = fn_path.value();
481            // Remove any leading slashes, then add one slash back
482            let fn_path = "/".to_string() + fn_path.trim_start_matches('/');
483            fn_path
484        });
485
486        let enable_server_fn_mod_path =
487            option_env!("SERVER_FN_MOD_PATH").is_some();
488        let mod_path = if enable_server_fn_mod_path {
489            quote! {
490                #server_fn_path::const_format::concatcp!(
491                    #server_fn_path::const_str::replace!(module_path!(), "::", "/"),
492                    "/"
493                )
494            }
495        } else {
496            quote! { "" }
497        };
498
499        let enable_hash = option_env!("DISABLE_SERVER_FN_HASH").is_none();
500        let key_env_var = match option_env!("SERVER_FN_OVERRIDE_KEY") {
501            Some(_) => "SERVER_FN_OVERRIDE_KEY",
502            None => "CARGO_MANIFEST_DIR",
503        };
504        let hash = if enable_hash {
505            quote! {
506                #server_fn_path::xxhash_rust::const_xxh64::xxh64(
507                    concat!(env!(#key_env_var), ":", module_path!()).as_bytes(),
508                    0
509                )
510            }
511        } else {
512            quote! { "" }
513        };
514
515        let fn_name_as_str = self.fn_name_as_str();
516        if let Some(fn_path) = fn_path {
517            quote! {
518                #server_fn_path::const_format::concatcp!(
519                    #prefix,
520                    #mod_path,
521                    #fn_path
522                )
523            }
524        } else {
525            quote! {
526                #server_fn_path::const_format::concatcp!(
527                    #prefix,
528                    "/",
529                    #mod_path,
530                    #fn_name_as_str,
531                    #hash
532                )
533            }
534        }
535    }
536
537    /// Get the names of the fields the server function takes as inputs.
538    fn field_names(&self) -> Vec<&std::boxed::Box<syn::Pat>> {
539        self.body
540            .inputs
541            .iter()
542            .map(|f| &f.arg.pat)
543            .collect::<Vec<_>>()
544    }
545
546    /// Generate the implementation for the server function trait.
547    fn server_fn_impl(&self) -> TokenStream2 {
548        let server_fn_path = self.server_fn_path();
549        let struct_name = self.struct_name();
550
551        let protocol = self.protocol();
552        let middlewares = &self.body.middlewares;
553        let return_ty = &self.body.return_ty;
554        let output_ty = self.body.output_ty
555            .as_ref()
556            .map_or_else(|| {
557                quote! {
558                    <#return_ty as #server_fn_path::error::ServerFnMustReturnResult>::Ok
559                }
560            },
561            ToTokens::to_token_stream,
562        );
563        let error_ty = &self.body.error_ty;
564        let error_ty = error_ty
565            .as_ref()
566            .map_or_else(|| {
567                quote! {
568                    <#return_ty as #server_fn_path::error::ServerFnMustReturnResult>::Err
569                }
570            },
571            ToTokens::to_token_stream,
572        );
573        let error_ws_in_ty = if self.websocket_protocol() {
574            self.body
575                .error_ws_in_ty
576                .as_ref()
577                .map(ToTokens::to_token_stream)
578                .unwrap_or(error_ty.clone())
579        } else {
580            error_ty.clone()
581        };
582        let error_ws_out_ty = if self.websocket_protocol() {
583            self.body
584                .error_ws_out_ty
585                .as_ref()
586                .map(ToTokens::to_token_stream)
587                .unwrap_or(error_ty.clone())
588        } else {
589            error_ty.clone()
590        };
591        let field_names = self.field_names();
592
593        // run_body in the trait implementation
594        let run_body = if cfg!(feature = "ssr") {
595            let destructure =
596                if let Some(wrapper) = self.args.custom_wrapper.as_ref() {
597                    quote! {
598                        let #wrapper(#struct_name { #(#field_names),* }) = self;
599                    }
600                } else {
601                    quote! {
602                        let #struct_name { #(#field_names),* } = self;
603                    }
604                };
605            let dummy_name = self.body.to_dummy_ident();
606
607            // using the impl Future syntax here is thanks to Actix
608            //
609            // if we use Actix types inside the function, here, it becomes !Send
610            // so we need to add SendWrapper, because Actix won't actually send it anywhere
611            // but if we used SendWrapper in an async fn, the types don't work out because it
612            // becomes impl Future<Output = SendWrapper<_>>
613            //
614            // however, SendWrapper<Future<Output = T>> impls Future<Output = T>
615            let body = quote! {
616                async move {
617                    #destructure
618                    #dummy_name(#(#field_names),*).await
619                }
620            };
621            quote! {
622                // we need this for Actix, for the SendWrapper to count as impl Future
623                // but non-Actix will have a clippy warning otherwise
624                #[allow(clippy::manual_async_fn)]
625                fn run_body(self) -> impl std::future::Future<Output = #return_ty> + Send {
626                    #body
627                }
628            }
629        } else {
630            quote! {
631                #[allow(unused_variables)]
632                async fn run_body(self) -> #return_ty {
633                    unreachable!()
634                }
635            }
636        };
637        let client = self.client_type();
638
639        let server = self.server_type();
640
641        // generate the url of the server function
642        let path = self.server_fn_url();
643
644        let middlewares = if cfg!(feature = "ssr") {
645            quote! {
646                vec![
647                    #(
648                        std::sync::Arc::new(#middlewares)
649                    ),*
650                ]
651            }
652        } else {
653            quote! { vec![] }
654        };
655        let wrapped_struct_name = self.wrapped_struct_name();
656
657        quote! {
658            impl #server_fn_path::ServerFn for #wrapped_struct_name {
659                const PATH: &'static str = #path;
660
661                type Client = #client;
662                type Server = #server;
663                type Protocol = #protocol;
664                type Output = #output_ty;
665                type Error = #error_ty;
666                type InputStreamError = #error_ws_in_ty;
667                type OutputStreamError = #error_ws_out_ty;
668
669                fn middlewares() -> Vec<std::sync::Arc<dyn #server_fn_path::middleware::Layer<<Self::Server as #server_fn_path::server::Server<Self::Error>>::Request, <Self::Server as #server_fn_path::server::Server<Self::Error>>::Response>>> {
670                    #middlewares
671                }
672
673                #run_body
674            }
675        }
676    }
677
678    /// Return the name and type of the first field if there is only one field.
679    fn single_field(&self) -> Option<(&Pat, &Type)> {
680        self.body
681            .inputs
682            .first()
683            .filter(|_| self.body.inputs.len() == 1)
684            .map(|field| (&*field.arg.pat, &*field.arg.ty))
685    }
686
687    fn deref_impl(&self) -> TokenStream2 {
688        let impl_deref = self
689            .args
690            .impl_deref
691            .as_ref()
692            .map(|v| v.value)
693            .unwrap_or(true)
694            || self.websocket_protocol();
695        if !impl_deref {
696            return quote! {};
697        }
698        // if there's exactly one field, impl Deref<T> for the struct
699        let Some(single_field) = self.single_field() else {
700            return quote! {};
701        };
702        let struct_name = self.struct_name();
703        let (name, ty) = single_field;
704        quote! {
705            impl std::ops::Deref for #struct_name {
706                type Target = #ty;
707                fn deref(&self) -> &Self::Target {
708                    &self.#name
709                }
710            }
711        }
712    }
713
714    fn impl_from(&self) -> TokenStream2 {
715        let impl_from = self
716            .args
717            .impl_from
718            .as_ref()
719            .map(|v| v.value)
720            .unwrap_or(true)
721            || self.websocket_protocol();
722        if !impl_from {
723            return quote! {};
724        }
725        // if there's exactly one field, impl From<T> for the struct
726        let Some(single_field) = self.single_field() else {
727            return quote! {};
728        };
729        let struct_name = self.struct_name();
730        let (name, ty) = single_field;
731        quote! {
732            impl From<#struct_name> for #ty {
733                fn from(value: #struct_name) -> Self {
734                    let #struct_name { #name } = value;
735                    #name
736                }
737            }
738
739            impl From<#ty> for #struct_name {
740                fn from(#name: #ty) -> Self {
741                    #struct_name { #name }
742                }
743            }
744        }
745    }
746
747    fn func_tokens(&self) -> TokenStream2 {
748        let body = &self.body;
749        // default values for args
750        let struct_name = self.struct_name();
751
752        // build struct for type
753        let fn_name = &body.ident;
754        let attrs = &body.attrs;
755
756        let fn_args = body.inputs.iter().map(|f| &f.arg).collect::<Vec<_>>();
757
758        let field_names = self.field_names();
759
760        // check output type
761        let output_arrow = body.output_arrow;
762        let return_ty = &body.return_ty;
763        let vis = &body.vis;
764
765        // Forward the docs from the function
766        let docs = self.docs();
767
768        // the actual function definition
769        if cfg!(feature = "ssr") {
770            let dummy_name = body.to_dummy_ident();
771            quote! {
772                #docs
773                #(#attrs)*
774                #vis async fn #fn_name(#(#fn_args),*) #output_arrow #return_ty {
775                    #dummy_name(#(#field_names),*).await
776                }
777            }
778        } else {
779            let restructure = if let Some(custom_wrapper) =
780                self.args.custom_wrapper.as_ref()
781            {
782                quote! {
783                    let data = #custom_wrapper(#struct_name { #(#field_names),* });
784                }
785            } else {
786                quote! {
787                    let data = #struct_name { #(#field_names),* };
788                }
789            };
790            let server_fn_path = self.server_fn_path();
791            quote! {
792                #docs
793                #(#attrs)*
794                #[allow(unused_variables)]
795                #vis async fn #fn_name(#(#fn_args),*) #output_arrow #return_ty {
796                    use #server_fn_path::ServerFn;
797                    #restructure
798                    data.run_on_client().await
799                }
800            }
801        }
802    }
803}
804
805impl ToTokens for ServerFnCall {
806    fn to_tokens(&self, tokens: &mut TokenStream2) {
807        let body = &self.body;
808
809        // only emit the dummy (unmodified server-only body) for the server build
810        let dummy = cfg!(feature = "ssr").then(|| body.to_dummy_output());
811
812        let impl_from = self.impl_from();
813
814        let deref_impl = self.deref_impl();
815
816        let inventory = self.submit_to_inventory();
817
818        let func = self.func_tokens();
819
820        let server_fn_impl = self.server_fn_impl();
821
822        let struct_tokens = self.struct_tokens();
823
824        tokens.extend(quote! {
825            #struct_tokens
826
827            #impl_from
828
829            #deref_impl
830
831            #server_fn_impl
832
833            #inventory
834
835            #func
836
837            #dummy
838        });
839    }
840}
841
842/// The implementation of the `server` macro.
843/// ```ignore
844/// #[proc_macro_attribute]
845/// pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
846///     match server_macro_impl(
847///         args.into(),
848///         s.into(),
849///         Some(syn::parse_quote!(my_crate::exports::server_fn)),
850///     ) {
851///         Err(e) => e.to_compile_error().into(),
852///         Ok(s) => s.to_token_stream().into(),
853///     }
854/// }
855/// ```
856pub fn server_macro_impl(
857    args: TokenStream2,
858    body: TokenStream2,
859    server_fn_path: Option<Path>,
860    default_path: &str,
861    preset_server: Option<Type>,
862    default_protocol: Option<Type>,
863) -> Result<TokenStream2> {
864    let body = ServerFnCall::parse(default_path, args, body)?
865        .default_server_fn_path(server_fn_path)
866        .default_server_type(preset_server)
867        .default_protocol(default_protocol);
868
869    Ok(body.to_token_stream())
870}
871
872fn type_from_ident(ident: Ident) -> Type {
873    let mut segments = Punctuated::new();
874    segments.push(PathSegment {
875        ident,
876        arguments: PathArguments::None,
877    });
878    Type::Path(TypePath {
879        qself: None,
880        path: Path {
881            leading_colon: None,
882            segments,
883        },
884    })
885}
886
887/// Middleware for a server function.
888#[derive(Debug, Clone)]
889pub struct Middleware {
890    expr: syn::Expr,
891}
892
893impl ToTokens for Middleware {
894    fn to_tokens(&self, tokens: &mut TokenStream2) {
895        let expr = &self.expr;
896        tokens.extend(quote::quote! {
897            #expr
898        });
899    }
900}
901
902impl Parse for Middleware {
903    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
904        let arg: syn::Expr = input.parse()?;
905        Ok(Middleware { expr: arg })
906    }
907}
908
909fn output_type(return_ty: &Type) -> Option<&Type> {
910    if let syn::Type::Path(pat) = &return_ty {
911        if pat.path.segments[0].ident == "Result" {
912            if pat.path.segments.is_empty() {
913                panic!("{:#?}", pat.path);
914            } else if let PathArguments::AngleBracketed(args) =
915                &pat.path.segments[0].arguments
916            {
917                if let GenericArgument::Type(ty) = &args.args[0] {
918                    return Some(ty);
919                }
920            }
921        }
922    };
923
924    None
925}
926
927fn err_type(return_ty: &Type) -> Option<&Type> {
928    if let syn::Type::Path(pat) = &return_ty {
929        if pat.path.segments[0].ident == "Result" {
930            if let PathArguments::AngleBracketed(args) =
931                &pat.path.segments[0].arguments
932            {
933                // Result<T>
934                if args.args.len() == 1 {
935                    return None;
936                }
937                // Result<T, _>
938                else if let GenericArgument::Type(ty) = &args.args[1] {
939                    return Some(ty);
940                }
941            }
942        }
943    };
944
945    None
946}
947
948fn err_ws_in_type(
949    inputs: &Punctuated<ServerFnArg, syn::token::Comma>,
950) -> Option<Type> {
951    inputs.into_iter().find_map(|pat| {
952        if let syn::Type::Path(ref pat) = *pat.arg.ty {
953            if pat.path.segments[0].ident != "BoxedStream" {
954                return None;
955            }
956
957            if let PathArguments::AngleBracketed(args) =
958                &pat.path.segments[0].arguments
959            {
960                // BoxedStream<T>
961                if args.args.len() == 1 {
962                    return None;
963                }
964                // BoxedStream<T, E>
965                else if let GenericArgument::Type(ty) = &args.args[1] {
966                    return Some(ty.clone());
967                }
968            };
969        };
970
971        None
972    })
973}
974
975fn err_ws_out_type(output_ty: &Option<Type>) -> Result<Option<Type>> {
976    if let Some(syn::Type::Path(ref pat)) = output_ty {
977        if pat.path.segments[0].ident == "BoxedStream" {
978            if let PathArguments::AngleBracketed(args) =
979                &pat.path.segments[0].arguments
980            {
981                // BoxedStream<T>
982                if args.args.len() == 1 {
983                    return Ok(None);
984                }
985                // BoxedStream<T, E>
986                else if let GenericArgument::Type(ty) = &args.args[1] {
987                    return Ok(Some(ty.clone()));
988                }
989
990                return Err(syn::Error::new(
991                    output_ty.span(),
992                    "websocket server functions should return \
993                     BoxedStream<Result<T, E>> where E: FromServerFnError",
994                ));
995            };
996        }
997    };
998
999    Ok(None)
1000}
1001
1002/// The arguments to the `server` macro.
1003#[derive(Debug)]
1004#[non_exhaustive]
1005pub struct ServerFnArgs {
1006    /// The name of the struct that will implement the server function trait
1007    /// and be submitted to inventory.
1008    pub struct_name: Option<Ident>,
1009    /// The prefix to use for the server function URL.
1010    pub prefix: Option<LitStr>,
1011    /// The input http encoding to use for the server function.
1012    pub input: Option<Type>,
1013    /// Additional traits to derive on the input struct for the server function.
1014    pub input_derive: Option<ExprTuple>,
1015    /// The output http encoding to use for the server function.
1016    pub output: Option<Type>,
1017    /// The path to the server function crate.
1018    pub fn_path: Option<LitStr>,
1019    /// The server type to use for the server function.
1020    pub server: Option<Type>,
1021    /// The client type to use for the server function.
1022    pub client: Option<Type>,
1023    /// The custom wrapper to use for the server function struct.
1024    pub custom_wrapper: Option<Path>,
1025    /// If the generated input type should implement `From` the only field in the input
1026    pub impl_from: Option<LitBool>,
1027    /// If the generated input type should implement `Deref` to the only field in the input
1028    pub impl_deref: Option<LitBool>,
1029    /// The protocol to use for the server function implementation.
1030    pub protocol: Option<Type>,
1031    builtin_encoding: bool,
1032}
1033
1034impl Parse for ServerFnArgs {
1035    fn parse(stream: ParseStream) -> syn::Result<Self> {
1036        // legacy 4-part arguments
1037        let mut struct_name: Option<Ident> = None;
1038        let mut prefix: Option<LitStr> = None;
1039        let mut encoding: Option<LitStr> = None;
1040        let mut fn_path: Option<LitStr> = None;
1041
1042        // new arguments: can only be keyed by name
1043        let mut input: Option<Type> = None;
1044        let mut input_derive: Option<ExprTuple> = None;
1045        let mut output: Option<Type> = None;
1046        let mut server: Option<Type> = None;
1047        let mut client: Option<Type> = None;
1048        let mut custom_wrapper: Option<Path> = None;
1049        let mut impl_from: Option<LitBool> = None;
1050        let mut impl_deref: Option<LitBool> = None;
1051        let mut protocol: Option<Type> = None;
1052
1053        let mut use_key_and_value = false;
1054        let mut arg_pos = 0;
1055
1056        while !stream.is_empty() {
1057            arg_pos += 1;
1058            let lookahead = stream.lookahead1();
1059            if lookahead.peek(Ident) {
1060                let key_or_value: Ident = stream.parse()?;
1061
1062                let lookahead = stream.lookahead1();
1063                if lookahead.peek(Token![=]) {
1064                    stream.parse::<Token![=]>()?;
1065                    let key = key_or_value;
1066                    use_key_and_value = true;
1067                    if key == "name" {
1068                        if struct_name.is_some() {
1069                            return Err(syn::Error::new(
1070                                key.span(),
1071                                "keyword argument repeated: `name`",
1072                            ));
1073                        }
1074                        struct_name = Some(stream.parse()?);
1075                    } else if key == "prefix" {
1076                        if prefix.is_some() {
1077                            return Err(syn::Error::new(
1078                                key.span(),
1079                                "keyword argument repeated: `prefix`",
1080                            ));
1081                        }
1082                        prefix = Some(stream.parse()?);
1083                    } else if key == "encoding" {
1084                        if encoding.is_some() {
1085                            return Err(syn::Error::new(
1086                                key.span(),
1087                                "keyword argument repeated: `encoding`",
1088                            ));
1089                        }
1090                        encoding = Some(stream.parse()?);
1091                    } else if key == "endpoint" {
1092                        if fn_path.is_some() {
1093                            return Err(syn::Error::new(
1094                                key.span(),
1095                                "keyword argument repeated: `endpoint`",
1096                            ));
1097                        }
1098                        fn_path = Some(stream.parse()?);
1099                    } else if key == "input" {
1100                        if encoding.is_some() {
1101                            return Err(syn::Error::new(
1102                                key.span(),
1103                                "`encoding` and `input` should not both be \
1104                                 specified",
1105                            ));
1106                        } else if input.is_some() {
1107                            return Err(syn::Error::new(
1108                                key.span(),
1109                                "keyword argument repeated: `input`",
1110                            ));
1111                        }
1112                        input = Some(stream.parse()?);
1113                    } else if key == "input_derive" {
1114                        if input_derive.is_some() {
1115                            return Err(syn::Error::new(
1116                                key.span(),
1117                                "keyword argument repeated: `input_derive`",
1118                            ));
1119                        }
1120                        input_derive = Some(stream.parse()?);
1121                    } else if key == "output" {
1122                        if encoding.is_some() {
1123                            return Err(syn::Error::new(
1124                                key.span(),
1125                                "`encoding` and `output` should not both be \
1126                                 specified",
1127                            ));
1128                        } else if output.is_some() {
1129                            return Err(syn::Error::new(
1130                                key.span(),
1131                                "keyword argument repeated: `output`",
1132                            ));
1133                        }
1134                        output = Some(stream.parse()?);
1135                    } else if key == "server" {
1136                        if server.is_some() {
1137                            return Err(syn::Error::new(
1138                                key.span(),
1139                                "keyword argument repeated: `server`",
1140                            ));
1141                        }
1142                        server = Some(stream.parse()?);
1143                    } else if key == "client" {
1144                        if client.is_some() {
1145                            return Err(syn::Error::new(
1146                                key.span(),
1147                                "keyword argument repeated: `client`",
1148                            ));
1149                        }
1150                        client = Some(stream.parse()?);
1151                    } else if key == "custom" {
1152                        if custom_wrapper.is_some() {
1153                            return Err(syn::Error::new(
1154                                key.span(),
1155                                "keyword argument repeated: `custom`",
1156                            ));
1157                        }
1158                        custom_wrapper = Some(stream.parse()?);
1159                    } else if key == "impl_from" {
1160                        if impl_from.is_some() {
1161                            return Err(syn::Error::new(
1162                                key.span(),
1163                                "keyword argument repeated: `impl_from`",
1164                            ));
1165                        }
1166                        impl_from = Some(stream.parse()?);
1167                    } else if key == "impl_deref" {
1168                        if impl_deref.is_some() {
1169                            return Err(syn::Error::new(
1170                                key.span(),
1171                                "keyword argument repeated: `impl_deref`",
1172                            ));
1173                        }
1174                        impl_deref = Some(stream.parse()?);
1175                    } else if key == "protocol" {
1176                        if protocol.is_some() {
1177                            return Err(syn::Error::new(
1178                                key.span(),
1179                                "keyword argument repeated: `protocol`",
1180                            ));
1181                        }
1182                        protocol = Some(stream.parse()?);
1183                    } else {
1184                        return Err(lookahead.error());
1185                    }
1186                } else {
1187                    let value = key_or_value;
1188                    if use_key_and_value {
1189                        return Err(syn::Error::new(
1190                            value.span(),
1191                            "positional argument follows keyword argument",
1192                        ));
1193                    }
1194                    if arg_pos == 1 {
1195                        struct_name = Some(value)
1196                    } else {
1197                        return Err(syn::Error::new(
1198                            value.span(),
1199                            "expected string literal",
1200                        ));
1201                    }
1202                }
1203            } else if lookahead.peek(LitStr) {
1204                if use_key_and_value {
1205                    return Err(syn::Error::new(
1206                        stream.span(),
1207                        "If you use keyword arguments (e.g., `name` = \
1208                         Something), then you can no longer use arguments \
1209                         without a keyword.",
1210                    ));
1211                }
1212                match arg_pos {
1213                    1 => return Err(lookahead.error()),
1214                    2 => prefix = Some(stream.parse()?),
1215                    3 => encoding = Some(stream.parse()?),
1216                    4 => fn_path = Some(stream.parse()?),
1217                    _ => {
1218                        return Err(syn::Error::new(
1219                            stream.span(),
1220                            "unexpected extra argument",
1221                        ))
1222                    }
1223                }
1224            } else {
1225                return Err(lookahead.error());
1226            }
1227
1228            if !stream.is_empty() {
1229                stream.parse::<Token![,]>()?;
1230            }
1231        }
1232
1233        // parse legacy encoding into input/output
1234        let mut builtin_encoding = false;
1235        if let Some(encoding) = encoding {
1236            match encoding.value().to_lowercase().as_str() {
1237                "url" => {
1238                    input = Some(type_from_ident(syn::parse_quote!(Url)));
1239                    output = Some(type_from_ident(syn::parse_quote!(Json)));
1240                    builtin_encoding = true;
1241                }
1242                "cbor" => {
1243                    input = Some(type_from_ident(syn::parse_quote!(Cbor)));
1244                    output = Some(type_from_ident(syn::parse_quote!(Cbor)));
1245                    builtin_encoding = true;
1246                }
1247                "getcbor" => {
1248                    input = Some(type_from_ident(syn::parse_quote!(GetUrl)));
1249                    output = Some(type_from_ident(syn::parse_quote!(Cbor)));
1250                    builtin_encoding = true;
1251                }
1252                "getjson" => {
1253                    input = Some(type_from_ident(syn::parse_quote!(GetUrl)));
1254                    output = Some(syn::parse_quote!(Json));
1255                    builtin_encoding = true;
1256                }
1257                _ => {
1258                    return Err(syn::Error::new(
1259                        encoding.span(),
1260                        "Encoding not found.",
1261                    ))
1262                }
1263            }
1264        }
1265
1266        Ok(Self {
1267            struct_name,
1268            prefix,
1269            input,
1270            input_derive,
1271            output,
1272            fn_path,
1273            builtin_encoding,
1274            server,
1275            client,
1276            custom_wrapper,
1277            impl_from,
1278            impl_deref,
1279            protocol,
1280        })
1281    }
1282}
1283
1284/// An argument type in a server function.
1285#[derive(Debug, Clone)]
1286pub struct ServerFnArg {
1287    /// The attributes on the server function argument.
1288    server_fn_attributes: Vec<Attribute>,
1289    /// The type of the server function argument.
1290    arg: syn::PatType,
1291}
1292
1293impl ToTokens for ServerFnArg {
1294    fn to_tokens(&self, tokens: &mut TokenStream2) {
1295        let ServerFnArg { arg, .. } = self;
1296        tokens.extend(quote! {
1297            #arg
1298        });
1299    }
1300}
1301
1302impl Parse for ServerFnArg {
1303    fn parse(input: ParseStream) -> Result<Self> {
1304        let arg: syn::FnArg = input.parse()?;
1305        let mut arg = match arg {
1306            FnArg::Receiver(_) => {
1307                return Err(syn::Error::new(
1308                    arg.span(),
1309                    "cannot use receiver types in server function macro",
1310                ))
1311            }
1312            FnArg::Typed(t) => t,
1313        };
1314
1315        fn rename_path(path: Path, from_ident: Ident, to_ident: Ident) -> Path {
1316            if path.is_ident(&from_ident) {
1317                Path {
1318                    leading_colon: None,
1319                    segments: Punctuated::from_iter([PathSegment {
1320                        ident: to_ident,
1321                        arguments: PathArguments::None,
1322                    }]),
1323                }
1324            } else {
1325                path
1326            }
1327        }
1328
1329        let server_fn_attributes = arg
1330            .attrs
1331            .iter()
1332            .cloned()
1333            .map(|attr| {
1334                if attr.path().is_ident("server") {
1335                    // Allow the following attributes:
1336                    // - #[server(default)]
1337                    // - #[server(rename = "fieldName")]
1338
1339                    // Rename `server` to `serde`
1340                    let attr = Attribute {
1341                        meta: match attr.meta {
1342                            Meta::Path(path) => Meta::Path(rename_path(
1343                                path,
1344                                format_ident!("server"),
1345                                format_ident!("serde"),
1346                            )),
1347                            Meta::List(mut list) => {
1348                                list.path = rename_path(
1349                                    list.path,
1350                                    format_ident!("server"),
1351                                    format_ident!("serde"),
1352                                );
1353                                Meta::List(list)
1354                            }
1355                            Meta::NameValue(mut name_value) => {
1356                                name_value.path = rename_path(
1357                                    name_value.path,
1358                                    format_ident!("server"),
1359                                    format_ident!("serde"),
1360                                );
1361                                Meta::NameValue(name_value)
1362                            }
1363                        },
1364                        ..attr
1365                    };
1366
1367                    let args = attr.parse_args::<Meta>()?;
1368                    match args {
1369                        // #[server(default)]
1370                        Meta::Path(path) if path.is_ident("default") => {
1371                            Ok(attr.clone())
1372                        }
1373                        // #[server(flatten)]
1374                        Meta::Path(path) if path.is_ident("flatten") => {
1375                            Ok(attr.clone())
1376                        }
1377                        // #[server(default = "value")]
1378                        Meta::NameValue(name_value)
1379                            if name_value.path.is_ident("default") =>
1380                        {
1381                            Ok(attr.clone())
1382                        }
1383                        // #[server(skip)]
1384                        Meta::Path(path) if path.is_ident("skip") => {
1385                            Ok(attr.clone())
1386                        }
1387                        // #[server(rename = "value")]
1388                        Meta::NameValue(name_value)
1389                            if name_value.path.is_ident("rename") =>
1390                        {
1391                            Ok(attr.clone())
1392                        }
1393                        _ => Err(Error::new(
1394                            attr.span(),
1395                            "Unrecognized #[server] attribute, expected \
1396                             #[server(default)] or #[server(rename = \
1397                             \"fieldName\")]",
1398                        )),
1399                    }
1400                } else if attr.path().is_ident("doc") {
1401                    // Allow #[doc = "documentation"]
1402                    Ok(attr.clone())
1403                } else if attr.path().is_ident("allow") {
1404                    // Allow #[allow(...)]
1405                    Ok(attr.clone())
1406                } else if attr.path().is_ident("deny") {
1407                    // Allow #[deny(...)]
1408                    Ok(attr.clone())
1409                } else if attr.path().is_ident("ignore") {
1410                    // Allow #[ignore]
1411                    Ok(attr.clone())
1412                } else {
1413                    Err(Error::new(
1414                        attr.span(),
1415                        "Unrecognized attribute, expected #[server(...)]",
1416                    ))
1417                }
1418            })
1419            .collect::<Result<Vec<_>>>()?;
1420        arg.attrs = vec![];
1421        Ok(ServerFnArg {
1422            arg,
1423            server_fn_attributes,
1424        })
1425    }
1426}
1427
1428/// The body of a server function.
1429#[derive(Debug, Clone)]
1430#[non_exhaustive]
1431pub struct ServerFnBody {
1432    /// The attributes on the server function.
1433    pub attrs: Vec<Attribute>,
1434    /// The visibility of the server function.
1435    pub vis: syn::Visibility,
1436    async_token: Token![async],
1437    fn_token: Token![fn],
1438    /// The name of the server function.
1439    pub ident: Ident,
1440    /// The generics of the server function.
1441    pub generics: Generics,
1442    _paren_token: token::Paren,
1443    /// The arguments to the server function.
1444    pub inputs: Punctuated<ServerFnArg, Token![,]>,
1445    output_arrow: Token![->],
1446    /// The return type of the server function.
1447    pub return_ty: syn::Type,
1448    /// The Ok output type of the server function.
1449    pub output_ty: Option<syn::Type>,
1450    /// The error output type of the server function.
1451    pub error_ty: Option<syn::Type>,
1452    /// The error type of WebSocket client-sent error
1453    pub error_ws_in_ty: Option<syn::Type>,
1454    /// The error type of WebSocket server-sent error
1455    pub error_ws_out_ty: Option<syn::Type>,
1456    /// The body of the server function.
1457    pub block: TokenStream2,
1458    /// The documentation of the server function.
1459    pub docs: Vec<(String, Span)>,
1460    /// The middleware attributes applied to the server function.
1461    pub middlewares: Vec<Middleware>,
1462}
1463
1464impl Parse for ServerFnBody {
1465    fn parse(input: ParseStream) -> Result<Self> {
1466        let mut attrs: Vec<Attribute> = input.call(Attribute::parse_outer)?;
1467
1468        let vis: Visibility = input.parse()?;
1469
1470        let async_token = input.parse()?;
1471
1472        let fn_token = input.parse()?;
1473        let ident = input.parse()?;
1474        let generics: Generics = input.parse()?;
1475
1476        let content;
1477        let _paren_token = syn::parenthesized!(content in input);
1478
1479        let inputs = syn::punctuated::Punctuated::parse_terminated(&content)?;
1480
1481        let output_arrow = input.parse()?;
1482        let return_ty = input.parse()?;
1483        let output_ty = output_type(&return_ty).cloned();
1484        let error_ty = err_type(&return_ty).cloned();
1485        let error_ws_in_ty = err_ws_in_type(&inputs);
1486        let error_ws_out_ty = err_ws_out_type(&output_ty)?;
1487
1488        let block = input.parse()?;
1489
1490        let docs = attrs
1491            .iter()
1492            .filter_map(|attr| {
1493                let Meta::NameValue(attr) = &attr.meta else {
1494                    return None;
1495                };
1496                if !attr.path.is_ident("doc") {
1497                    return None;
1498                }
1499
1500                let value = match &attr.value {
1501                    syn::Expr::Lit(lit) => match &lit.lit {
1502                        syn::Lit::Str(s) => Some(s.value()),
1503                        _ => return None,
1504                    },
1505                    _ => return None,
1506                };
1507
1508                Some((value.unwrap_or_default(), attr.path.span()))
1509            })
1510            .collect();
1511        attrs.retain(|attr| {
1512            let Meta::NameValue(attr) = &attr.meta else {
1513                return true;
1514            };
1515            !attr.path.is_ident("doc")
1516        });
1517        // extract all #[middleware] attributes, removing them from signature of dummy
1518        let mut middlewares: Vec<Middleware> = vec![];
1519        attrs.retain(|attr| {
1520            if attr.meta.path().is_ident("middleware") {
1521                if let Ok(middleware) = attr.parse_args() {
1522                    middlewares.push(middleware);
1523                    false
1524                } else {
1525                    true
1526                }
1527            } else {
1528                // in ssr mode, remove the "lazy" macro
1529                // the lazy macro doesn't do anything on the server anyway, but it can cause confusion for rust-analyzer
1530                // when the lazy macro is applied to both the function and the dummy
1531                !(cfg!(feature = "ssr") && matches!(attr.meta.path().segments.last(), Some(PathSegment { ident, .. }) if ident == "lazy") )
1532            }
1533        });
1534
1535        Ok(Self {
1536            vis,
1537            async_token,
1538            fn_token,
1539            ident,
1540            generics,
1541            _paren_token,
1542            inputs,
1543            output_arrow,
1544            return_ty,
1545            output_ty,
1546            error_ty,
1547            error_ws_in_ty,
1548            error_ws_out_ty,
1549            block,
1550            attrs,
1551            docs,
1552            middlewares,
1553        })
1554    }
1555}
1556
1557impl ServerFnBody {
1558    fn to_dummy_ident(&self) -> Ident {
1559        Ident::new(&format!("__server_{}", self.ident), self.ident.span())
1560    }
1561
1562    fn to_dummy_output(&self) -> TokenStream2 {
1563        let ident = self.to_dummy_ident();
1564        let Self {
1565            attrs,
1566            vis,
1567            async_token,
1568            fn_token,
1569            generics,
1570            inputs,
1571            output_arrow,
1572            return_ty,
1573            block,
1574            ..
1575        } = &self;
1576        quote! {
1577            #[doc(hidden)]
1578            #(#attrs)*
1579            #vis #async_token #fn_token #ident #generics ( #inputs ) #output_arrow #return_ty
1580            #block
1581        }
1582    }
1583}