portrait_framework/
impl_completer.rs1extern crate proc_macro;
2
3use proc_macro2::TokenStream;
4use quote::quote;
5use syn::parse::Parse;
6use syn::Result;
7
8use crate::{impl_filler, subtract_items, FillImpl};
9
10#[macro_export]
46macro_rules! proc_macro_impl_filler {
47 ($ident:ident, $generator:path) => {
48 pub fn $ident(input: ::proc_macro::TokenStream) -> ::proc_macro::TokenStream {
49 portrait_framework::completer_impl_filler(input, $generator)
50 }
51 };
52}
53
54pub fn completer_impl_filler<ArgsT: Parse, GeneratorT: GenerateImpl>(
56 input: proc_macro::TokenStream,
57 ctor: fn(ArgsT) -> GeneratorT,
58) -> proc_macro::TokenStream {
59 completer_impl_filler2(input.into(), ctor).unwrap_or_else(syn::Error::into_compile_error).into()
60}
61
62pub fn completer_impl_filler2<ArgsT: Parse, GeneratorT: GenerateImpl>(
64 input: TokenStream,
65 ctor: fn(ArgsT) -> GeneratorT,
66) -> Result<TokenStream> {
67 struct Filler<GenerateT, ArgsT>(fn(ArgsT) -> GenerateT);
68
69 impl<GenerateT: GenerateImpl, ArgsT: Parse> FillImpl for Filler<GenerateT, ArgsT> {
70 type Args = ArgsT;
71
72 fn fill(
73 self,
74 portrait: &[syn::TraitItem],
75 args: Self::Args,
76 item_impl: &syn::ItemImpl,
77 ) -> Result<TokenStream> {
78 let tokens = complete_impl(portrait, item_impl, self.0(args))?;
79 Ok(quote!(#tokens))
80 }
81 }
82
83 impl_filler(input, Filler(ctor))
84}
85
86pub fn complete_impl(
89 trait_items: &[syn::TraitItem],
90 impl_block: &syn::ItemImpl,
91 mut generator: impl GenerateImpl,
92) -> syn::Result<syn::ItemImpl> {
93 let mut output = impl_block.clone();
94
95 let ctx = ImplContext { all_trait_items: trait_items, impl_block };
96
97 let items = subtract_items(trait_items, impl_block)?;
98 for trait_item in items.consts.values() {
99 let impl_item = generator.generate_const(ImplContext { ..ctx }, trait_item)?;
100 output.items.push(syn::ImplItem::Const(impl_item));
101 }
102 for trait_item in items.fns.values() {
103 let impl_item = generator.generate_fn(ImplContext { ..ctx }, trait_item)?;
104 output.items.push(syn::ImplItem::Fn(impl_item));
105 }
106 for trait_item in items.types.values() {
107 let impl_item = generator.generate_type(ImplContext { ..ctx }, trait_item)?;
108 output.items.push(syn::ImplItem::Type(impl_item));
109 }
110
111 Ok(output)
112}
113
114#[non_exhaustive]
116pub struct ImplContext<'t> {
117 pub all_trait_items: &'t [syn::TraitItem],
119 pub impl_block: &'t syn::ItemImpl,
121}
122
123pub trait GenerateImpl {
125 fn generate_const(
127 &mut self,
128 ctx: ImplContext,
129 item: &syn::TraitItemConst,
130 ) -> Result<syn::ImplItemConst>;
131
132 fn generate_fn(&mut self, ctx: ImplContext, item: &syn::TraitItemFn)
134 -> Result<syn::ImplItemFn>;
135
136 fn generate_type(
138 &mut self,
139 ctx: ImplContext,
140 item: &syn::TraitItemType,
141 ) -> Result<syn::ImplItemType>;
142}