portrait_framework/
impl_filler.rs1use proc_macro2::TokenStream;
2use syn::parse::{Parse, ParseStream};
3use syn::Result;
4
5pub trait FillImpl {
7 type Args: Parse;
9
10 fn fill(
12 self,
13 portrait: &[syn::TraitItem],
14 args: Self::Args,
15 item_impl: &syn::ItemImpl,
16 ) -> Result<TokenStream>;
17}
18
19pub 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}