portrait_framework/
derive_completer.rs1extern crate proc_macro;
2
3use proc_macro2::{Span, TokenStream};
4use quote::{quote, ToTokens};
5use syn::parse::Parse;
6use syn::spanned::Spanned;
7use syn::Result;
8
9use crate::{derive_filler, FillDerive};
10
11#[macro_export]
47macro_rules! proc_macro_derive_filler {
48 ($ident:ident, $generator:path) => {
49 pub fn $ident(input: ::proc_macro::TokenStream) -> ::proc_macro::TokenStream {
50 portrait_framework::completer_derive_filler(input, $generator)
51 }
52 };
53}
54
55pub fn completer_derive_filler<ArgsT: Parse, GeneratorT: GenerateDerive>(
57 input: proc_macro::TokenStream,
58 ctor: fn(ArgsT) -> GeneratorT,
59) -> proc_macro::TokenStream {
60 completer_derive_filler2(input.into(), ctor)
61 .unwrap_or_else(syn::Error::into_compile_error)
62 .into()
63}
64
65pub fn completer_derive_filler2<ArgsT: Parse, GeneratorT: GenerateDerive>(
67 input: TokenStream,
68 ctor: fn(ArgsT) -> GeneratorT,
69) -> Result<TokenStream> {
70 struct Filler<GenerateT, ArgsT>(fn(ArgsT) -> GenerateT);
71
72 impl<GenerateT: GenerateDerive, ArgsT: Parse> FillDerive for Filler<GenerateT, ArgsT> {
73 type Args = ArgsT;
74
75 fn fill(
76 self,
77 trait_path: &syn::Path,
78 portrait: &[syn::TraitItem],
79 args: Self::Args,
80 input: &syn::DeriveInput,
81 ) -> Result<TokenStream> {
82 let tokens = complete_derive(trait_path, portrait, input, self.0(args))?;
83 Ok(quote!(#tokens))
84 }
85 }
86
87 derive_filler(input, Filler(ctor))
88}
89
90pub fn complete_derive(
93 trait_path: &syn::Path,
94 trait_items: &[syn::TraitItem],
95 input: &syn::DeriveInput,
96 mut generator: impl GenerateDerive,
97) -> syn::Result<syn::ItemImpl> {
98 let ctx = DeriveContext { trait_path, all_trait_items: trait_items, input };
99
100 let mut generics_params: Vec<_> = input.generics.params.iter().cloned().collect();
101 let mut generics_where: Vec<_> = input
102 .generics
103 .where_clause
104 .iter()
105 .flat_map(|clause| clause.predicates.iter().cloned())
106 .collect();
107 generator.extend_generics(
109 DeriveContext { ..ctx },
110 &mut generics_params,
111 &mut generics_where,
112 )?;
113
114 let self_ty = syn::Type::Path({
115 let input_ident = &input.ident;
116 let self_generics = (!input.generics.params.is_empty()).then(|| {
117 let type_param_names = input.generics.params.iter().map(|param| match param {
118 syn::GenericParam::Lifetime(lt) => lt.lifetime.to_token_stream(),
119 syn::GenericParam::Type(ty) => ty.ident.to_token_stream(),
120 syn::GenericParam::Const(const_) => const_.ident.to_token_stream(),
121 });
122
123 quote!(<#(#type_param_names),*>)
124 });
125
126 syn::parse_quote!(#input_ident #self_generics)
127 });
128
129 let mut items = Vec::new();
130 for trait_item in trait_items {
131 let item = match trait_item {
132 syn::TraitItem::Const(const_item) => {
133 syn::ImplItem::Const(generator.generate_const(DeriveContext { ..ctx }, const_item)?)
134 }
135 syn::TraitItem::Fn(fn_item) => {
136 syn::ImplItem::Fn(generator.generate_fn(DeriveContext { ..ctx }, fn_item)?)
137 }
138 syn::TraitItem::Type(type_item) => {
139 syn::ImplItem::Type(generator.generate_type(DeriveContext { ..ctx }, type_item)?)
140 }
141 _ => continue, };
143 items.push(item);
144 }
145
146 let mut attrs: Vec<_> =
147 input.attrs.iter().filter(|attr| attr.path().is_ident("cfg")).cloned().collect();
148 generator.extend_attrs(DeriveContext { ..ctx }, &mut attrs)?;
149
150 Ok(syn::ItemImpl {
151 attrs,
152 defaultness: None,
153 unsafety: None, impl_token: syn::Token),
155 generics: syn::Generics {
156 lt_token: (!generics_params.is_empty())
157 .then(|| syn::Token)),
158 gt_token: (!generics_params.is_empty())
159 .then(|| syn::Token)),
160 params: generics_params.into_iter().collect(),
161 where_clause: (!generics_where.is_empty()).then(|| syn::WhereClause {
162 where_token: syn::Token),
163 predicates: generics_where.into_iter().collect(),
164 }),
165 },
166 trait_: Some((None, trait_path.clone(), syn::Token))),
167 self_ty: Box::new(self_ty),
168 brace_token: syn::token::Brace::default(),
169 items,
170 })
171}
172
173#[non_exhaustive]
175pub struct DeriveContext<'t> {
176 pub trait_path: &'t syn::Path,
178 pub all_trait_items: &'t [syn::TraitItem],
180 pub input: &'t syn::DeriveInput,
182}
183
184pub trait GenerateDerive {
186 fn generate_const(
188 &mut self,
189 ctx: DeriveContext,
190 item: &syn::TraitItemConst,
191 ) -> Result<syn::ImplItemConst>;
192
193 fn generate_fn(
195 &mut self,
196 ctx: DeriveContext,
197 item: &syn::TraitItemFn,
198 ) -> Result<syn::ImplItemFn>;
199
200 fn generate_type(
202 &mut self,
203 ctx: DeriveContext,
204 item: &syn::TraitItemType,
205 ) -> Result<syn::ImplItemType>;
206
207 fn extend_generics(
209 &mut self,
210 _ctx: DeriveContext,
211 _generics_params: &mut Vec<syn::GenericParam>,
212 _generics_where: &mut Vec<syn::WherePredicate>,
213 ) -> Result<()> {
214 Ok(())
215 }
216
217 fn extend_attrs(
219 &mut self,
220 _ctx: DeriveContext,
221 _attrs: &mut Vec<syn::Attribute>,
222 ) -> Result<()> {
223 Ok(())
224 }
225}