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