box_dyn/lib.rs
1use quote::{quote, ToTokens};
2use syn::punctuated::Punctuated;
3
4#[proc_macro_attribute]
5pub fn box_dyn(
6 args: proc_macro::TokenStream,
7 input: proc_macro::TokenStream,
8) -> proc_macro::TokenStream {
9 // let mut input: syn::DeriveInput = syn::parse2(input.into()).unwrap();
10 // let additional_bounds = syn::parse_macro_input!(args with syn::punctuated::Punctuated::<syn::Path, syn::Token![,]>::parse_terminated);
11 // $crate::parse::Parser::parse($parser, $tokenstream)
12 let additional_bounds_comma_separated = syn::parse::Parser::parse(
13 <Punctuated<syn::TraitBound, syn::Token![,]>>::parse_terminated,
14 args.clone().into(),
15 )
16 .map(|bounds| bounds.into_iter().collect());
17 // dbg!(additional_bounds_comma_separated.is_ok());
18
19 let additional_bounds_plus_separated = syn::parse::Parser::parse(
20 <Punctuated<syn::TraitBound, syn::Token![+]>>::parse_terminated,
21 args.clone().into(),
22 )
23 .map(|bounds| bounds.into_iter().collect());
24 // dbg!(additional_bounds_plus_separated.is_ok());
25
26 let additional_bounds: Vec<syn::TraitBound> = additional_bounds_plus_separated
27 .or(additional_bounds_comma_separated)
28 .unwrap();
29
30 // dbg!(additional_bounds
31 // .iter()
32 // .map(|b| quote! { #b })
33 // .collect::<Vec<_>>());
34
35 // .unwrap();
36 // let additional_bounds = syn::parse_macro_input!(args with ;
37 // Punctuated<GenericParam, Token![,]>
38 // let args_parsed: syn::punctuated::Punctuated<syn::Path, syn::Token![,]>::parse_terminated =
39 // syn::parse2(input.into()).unwrap();
40 // let args_parsed = syn::punctuated::Punctuated::<syn::Path, syn::Token![,]>::parse_terminated
41 // .parse2(args)
42 // .unwrap();
43 let trait_item: syn::ItemTrait = syn::parse2(input.into()).unwrap();
44 let trait_name = &trait_item.ident;
45 let trait_generics = &trait_item.generics;
46 // let trait_with_generics = quote! { #trait_name };
47 // generics
48 // dbg!(trait_name.to_string());
49
50 let trait_items: Vec<_> = trait_item
51 .items
52 .clone()
53 .into_iter()
54 .filter_map(|mut item| {
55 match item {
56 // An associated constant within the definition of a trait.
57 syn::TraitItem::Const(ref mut val) => {
58 // default
59 // syn::TraitItemConst
60 val.default = todo!();
61 Some(item)
62 // Some(val.into_token_stream())
63 }
64 // An associated function within the definition of a trait.
65 syn::TraitItem::Fn(ref mut func) => {
66 // syn::TraitItemFn
67 let func_name = &func.sig.ident;
68 // dbg!(&func_name);
69 let receiver = func
70 .sig
71 .inputs
72 .iter()
73 .find_map(|arg| match arg {
74 syn::FnArg::Receiver(ty) => Some(ty.clone()),
75 _ => None,
76 })
77 .expect("trait functions need receiver type");
78 let self_typ =
79 match (receiver.reference.is_some(), receiver.mutability.is_some()) {
80 (true, true) => quote! { self.as_mut() },
81 (true, false) => quote! { self.as_ref() },
82 (false, _) => quote! { self },
83 };
84 // pub reference: Option<(Token![&], Option<Lifetime>)>,
85 // pub mutability: Option<Token![mut]>,
86
87 let param_names: Vec<_> = func
88 .sig
89 .inputs
90 .iter()
91 .filter_map(|arg| match arg {
92 syn::FnArg::Typed(ty) => Some(ty.pat.clone()),
93 _ => None,
94 })
95 .collect();
96
97 // dbg!(&trait_name);
98 // dbg!(&func_name);
99 // dbg!(&self_typ);
100 // dbg!(¶m_names
101 // .iter()
102 // .map(|p| quote! { #p })
103 // .collect::<Vec<_>>());
104
105 // println!(
106 // "{}",
107 // pretty_print(quote! {{
108 // #trait_name::#func_name(#self_typ, #(#param_names),*)
109 // }})
110 // );
111 func.default = Some(
112 syn::parse2::<syn::Block>(quote! {{
113 #trait_name::#func_name(#self_typ, #(#param_names),*)
114 }})
115 .unwrap(),
116 );
117 Some(item)
118 // Some(func)
119 // pub attrs: Vec<Attribute>,
120 // pub sig: Signature,
121 // pub default: Option<Block>,
122 //
123 }
124
125 // An associated type within the definition of a trait.
126 syn::TraitItem::Type(typ) => {
127 // syn::TraitItemType
128 typ.default = todo!();
129 Some(item)
130 }
131 // A macro invocation within the definition of a trait.
132 // syn::TraitItemMacro
133 // syn::TraitItem::Macro(_) => None,
134 // Tokens within the definition of a trait not interpreted by Syn.
135 // syn::TokenStream
136 // syn::TraitItem::Verbatim(_) => None,
137 _ => None,
138 }
139 })
140 .collect();
141
142 let t = quote! { __BoxDynT };
143 let trait_where_predicates = &trait_generics
144 .where_clause
145 .as_ref()
146 .map(|clause| &clause.predicates);
147 let trait_generic_params = &trait_generics.params;
148
149 let t_bounds: Vec<_> = [quote! { #trait_name #trait_generics }]
150 .into_iter()
151 .chain(additional_bounds.into_iter().map(|b| quote! { #b }))
152 .collect();
153
154 let out = quote! {
155 #trait_item
156
157 impl<#t, #trait_generic_params> #trait_name #trait_generics for Box<#t>
158 where
159 #t: #(#t_bounds)+*,
160 #trait_where_predicates
161 {
162 #(#trait_items)*
163 }
164 };
165 println!("{}", pretty_print(&out));
166 out.into()
167}
168
169#[allow(dead_code)]
170fn pretty_print<T>(input: T) -> String
171where
172 T: quote::ToTokens,
173{
174 let file: syn::File = syn::parse2(quote! {
175 fn main() {
176 #input
177 }
178 })
179 .unwrap();
180 prettyplease::unparse(&file)
181}