liquid_derive/parse_filter/
parse.rs

1use super::*;
2
3/// Generates implementation of `ParseFilter`.
4fn generate_parse_filter(filter_parser: &ParseFilter<'_>) -> Result<TokenStream> {
5    let ParseFilterMeta {
6        parameters_struct_name,
7        filter_struct_name,
8        ..
9    } = &filter_parser.meta;
10
11    let filter_struct_name = filter_struct_name.as_ref().map_err(|err| err.clone())?;
12
13    let impl_parse_filter =
14        filter_parser.generate_impl(quote! { ::liquid_core::parser::ParseFilter });
15
16    if let Some(parameters_struct_name) = parameters_struct_name {
17        let build_filter_parameters = quote_spanned! {parameters_struct_name.span()=>
18            let args = <#parameters_struct_name as ::liquid_core::parser::FilterParameters>::from_args(args)?;
19        };
20
21        let return_expr = quote_spanned! {filter_struct_name.span()=>
22            Ok(::std::boxed::Box::new(<#filter_struct_name as ::std::convert::From<#parameters_struct_name>>::from(args)))
23        };
24
25        Ok(quote! {
26            #impl_parse_filter {
27                fn parse(&self, args: ::liquid_core::parser::FilterArguments) -> ::liquid_core::error::Result<::std::boxed::Box<dyn ::liquid_core::parser::Filter>> {
28                    #build_filter_parameters
29                    #return_expr
30                }
31
32                fn reflection(&self) -> &dyn ::liquid_core::parser::FilterReflection {
33                    self
34                }
35            }
36        })
37    } else {
38        let return_expr = quote_spanned! {filter_struct_name.span()=>
39            #[allow(unknown_lints)]
40            #[allow(clippy::box_default)]
41            ::std::result::Result::Ok(::std::boxed::Box::new(<#filter_struct_name as ::std::default::Default>::default()))
42        };
43        Ok(quote! {
44            #impl_parse_filter {
45                fn parse(&self, mut args: ::liquid_core::parser::FilterArguments) -> ::liquid_core::error::Result<::std::boxed::Box<dyn ::liquid_core::parser::Filter>> {
46                    if let ::std::option::Option::Some(arg) = args.positional.next() {
47                        return ::std::result::Result::Err(::liquid_core::error::Error::with_msg("Invalid number of positional arguments")
48                            .context("cause", concat!("expected at most 0 positional arguments"))
49                        );
50                    }
51                    if let ::std::option::Option::Some(arg) = args.keyword.next() {
52                        return ::std::result::Result::Err(::liquid_core::error::Error::with_msg(format!("Unexpected named argument `{}`", arg.0)));
53                    }
54
55                    #return_expr
56                }
57
58                fn reflection(&self) -> &dyn ::liquid_core::parser::FilterReflection {
59                    self
60                }
61            }
62        })
63    }
64}
65
66pub(crate) fn derive(input: &DeriveInput) -> TokenStream {
67    let filter_parser = match ParseFilter::from_input(input) {
68        Ok(filter_parser) => filter_parser,
69        Err(err) => return err.to_compile_error(),
70    };
71
72    match generate_parse_filter(&filter_parser) {
73        Ok(output) => output,
74        Err(err) => err.to_compile_error(),
75    }
76}