portrait_framework/
impl_filler.rs

1use proc_macro2::TokenStream;
2use syn::parse::{Parse, ParseStream};
3use syn::Result;
4
5/// Determines how to fill an `impl` block.
6pub trait FillImpl {
7    /// The arguments passed to the filler through macros.
8    type Args: Parse;
9
10    /// Completes the impl given a portrait of the trait items.
11    fn fill(
12        self,
13        portrait: &[syn::TraitItem],
14        args: Self::Args,
15        item_impl: &syn::ItemImpl,
16    ) -> Result<TokenStream>;
17}
18
19/// Parses the macro input directly and passes them to the filler.
20///
21/// Use this function if information of all implemented/unimplemented trait/impl items
22/// are required at the same time.
23/// If the filler just maps each unimplemented trait item to an impl item statelessly,
24/// use [`completer_impl_filler2`](crate::completer_impl_filler2)/[`proc_macro_impl_filler`](crate::proc_macro_impl_filler) for shorthand.
25pub fn impl_filler<FillerT: FillImpl>(input: TokenStream, filler: FillerT) -> Result<TokenStream> {
26    let Input::<FillerT::Args> { portrait, args, item_impl, debug_print } = syn::parse2(input)?;
27
28    let output = filler.fill(&portrait, args, &item_impl)?;
29
30    if debug_print {
31        println!("{output}");
32    }
33
34    Ok(output)
35}
36
37mod kw {
38    syn::custom_keyword!(TRAIT_PORTRAIT);
39    syn::custom_keyword!(ARGS);
40    syn::custom_keyword!(IMPL);
41    syn::custom_keyword!(DEBUG_PRINT_FILLER_OUTPUT);
42}
43
44pub(crate) struct Input<ArgsT> {
45    pub(crate) portrait:    Vec<syn::TraitItem>,
46    pub(crate) args:        ArgsT,
47    pub(crate) item_impl:   syn::ItemImpl,
48    pub(crate) debug_print: bool,
49}
50
51impl<ArgsT: Parse> Parse for Input<ArgsT> {
52    fn parse(input: ParseStream) -> Result<Self> {
53        input.parse::<kw::TRAIT_PORTRAIT>()?;
54
55        let portrait_braced;
56        syn::braced!(portrait_braced in input);
57        let mut portrait = Vec::new();
58        while !portrait_braced.is_empty() {
59            let item_braced;
60            syn::braced!(item_braced in portrait_braced);
61            let item: syn::TraitItem = item_braced.parse()?;
62            if !item_braced.is_empty() {
63                return Err(item_braced.error("braces should only contain one trait item"));
64            }
65            portrait.push(item);
66        }
67
68        input.parse::<kw::ARGS>()?;
69        let args_braced;
70        syn::braced!(args_braced in input);
71        let args: ArgsT = args_braced.parse()?;
72        if !args_braced.is_empty() {
73            return Err(args_braced.error("args not fully parsed"));
74        }
75
76        input.parse::<kw::IMPL>()?;
77        let impl_braced;
78        syn::braced!(impl_braced in input);
79        let item_impl = impl_braced.parse()?;
80        if !impl_braced.is_empty() {
81            return Err(impl_braced.error("trailing tokens after impl block"));
82        }
83
84        input.parse::<kw::DEBUG_PRINT_FILLER_OUTPUT>()?;
85        let dpfo_braced;
86        syn::braced!(dpfo_braced in input);
87        let dpfo: syn::LitBool = dpfo_braced.parse()?;
88        if !dpfo_braced.is_empty() {
89            return Err(impl_braced.error("trailing tokens after impl block"));
90        }
91
92        if !input.is_empty() {
93            return Err(input.error("trailing tokens in macro input"));
94        }
95
96        Ok(Self { portrait, args, item_impl, debug_print: dpfo.value })
97    }
98}