trait_enumizer_derive/
lib.rs1use convert_case::Casing;
2use proc_macro2::TokenStream;
3use syn::Ident;
4
5struct Argument {
6 name: Ident,
7 ty: syn::Type,
8 enum_attr: Vec<proc_macro2::Group>,
9 to_owned: bool,
10}
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13enum ReceiverStyle {
14 Move,
15 Mut,
16 Ref,
17}
18
19struct Method {
20 name: Ident,
21 receiver_style: ReceiverStyle,
22 args: Vec<Argument>,
23 ret: Option<syn::Type>,
24 enum_attr: Vec<proc_macro2::Group>,
25 return_attr: Vec<proc_macro2::Group>,
26 r#async: bool,
27}
28
29impl Method {
30 fn variant_name(&self) -> proc_macro2::Ident {
31 quote::format_ident!(
32 "{}",
33 self.name
34 .to_string()
35 .to_case(convert_case::Case::UpperCamel)
36 )
37 }
38}
39
40impl std::fmt::Debug for Method {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 f.debug_struct("Method")
43 .field("name", &self.name.to_string())
44 .field("receiver_style", &self.receiver_style)
45 .field("args", &self.args)
46 .finish()
47 }
48}
49
50struct InputData {
51 name: Ident,
53 methods: Vec<Method>,
54 params: Params,
55}
56
57mod generate;
58mod parse_args;
59mod parse_input;
60mod util;
61
62
63struct GenProxyParams {
64 level: ReceiverStyle,
65 gen_infallible: bool,
66 gen_unwrapping: bool,
67 gen_unwrapping_and_panicking: bool,
68 extra_arg: Option<proc_macro2::TokenStream>,
69 name: Ident,
70 traitname: Option<Ident>,
71 r#async: bool,
72}
73impl GenProxyParams {
74 fn some_impl_requested(&self) -> bool {
75 self.gen_infallible || self.gen_unwrapping || self.gen_unwrapping_and_panicking
76 }
77}
78
79struct CallFnParams {
80 level: ReceiverStyle,
81 allow_panic: bool,
82 extra_arg: Option<proc_macro2::TokenStream>,
83 name: Ident,
84 r#async: bool,
85}
86
87
88#[derive(PartialEq, Eq, Copy, Clone, Debug)]
89enum AccessMode {
90 Priv,
91 Pub,
92 PubCrate,
93}
94
95
96struct Params {
97 proxies: Vec<GenProxyParams>,
98 call_fns: Vec<CallFnParams>,
99 access_mode: AccessMode,
100 returnval: Option<proc_macro2::Ident>,
101 enum_attr: Vec<proc_macro2::Group>,
102 enum_name: Ident,
103 inherent_impl_mode : bool,
104}
105
106#[proc_macro_attribute]
107pub fn enumizer(
108 attrs: proc_macro::TokenStream,
109 item: proc_macro::TokenStream,
110) -> proc_macro::TokenStream {
111 let input: TokenStream = item.into();
112 let attrs: TokenStream = attrs.into();
113
114 let params = parse_args::parse_args(attrs);
115
116 let mut ret = TokenStream::new();
117 let input_data = if ! params.inherent_impl_mode {
118 let mut tra: syn::ItemTrait = syn::parse2(input).unwrap();
119 let input_data = InputData::parse_trait(&mut tra, params);
120 ret.extend(quote::quote! {#tra});
121 input_data
122 } else {
123 let mut imp: syn::ItemImpl = syn::parse2(input).unwrap();
124 let input_data = InputData::parse_inherent_impl(&mut imp, params);
125 ret.extend(quote::quote! {#imp});
126 input_data
127 };
128 let params = &input_data.params;
129
130 input_data.generate_enum(&mut ret);
132
133 let caller_inconv = input_data.receiver_style_that_is_the_most_inconvenient_for_caller();
134
135 for g in ¶ms.call_fns {
136 match g.level {
137 ReceiverStyle::Move => (),
138 ReceiverStyle::Mut => {
139 if caller_inconv == ReceiverStyle::Move && !g.allow_panic {
140 panic!("Cannot generate `call_fn(ref_mut)` function because of trait have `self` methods. Use `call_fn(... ,allow_panic)` to override.");
141 }
142 }
143 ReceiverStyle::Ref => {
144 if caller_inconv != ReceiverStyle::Ref && !g.allow_panic {
145 panic!("Cannot generate `call_fn(ref)` function because of trait have non-`&self` methods. Use `call_fn(... ,allow_panic)` to override.");
146 }
147 }
148 }
149 input_data.generate_call_fn(&mut ret, g);
150 }
151
152 let callee_inconv = input_data.receiver_style_that_is_the_most_inconvenient_for_callee();
153
154 for g in ¶ms.proxies {
155 if params.inherent_impl_mode && g.some_impl_requested() {
156 panic!("Generating trait impls is incompatible with inherent_impl mode");
157 }
158
159 if g.gen_infallible {
160 if params.returnval.is_some() {
161 panic!("infallible_impl and returnval are incompatible");
162 }
163 }
164 match g.level {
165 ReceiverStyle::Move => {
166 if g.gen_infallible || g.gen_unwrapping {
167 if callee_inconv != ReceiverStyle::Move {
168 panic!("The trait contains `&self` or `&mut self` methods. The FnOnce proxy cannot implement it - only for traits with solely `self` methods. Use `unwrapping_and_panicking_impl` to force generation and retain only some methods");
169 }
170 }
171 }
172 ReceiverStyle::Mut => {
173 if g.gen_infallible || g.gen_unwrapping {
174 if callee_inconv == ReceiverStyle::Ref {
175 panic!("The trait contains &self methods. The FnMut proxy cannot implement it. Use `unwrapping_and_panicking_impl` to force generation and retain only some methods");
176 }
177 }
178 }
179 ReceiverStyle::Ref => {
180
181 }
182 }
183
184 if g.traitname.is_some() {
185 input_data.generate_resultified_trait(&mut ret, g);
186 }
187 input_data.generate_proxy(&mut ret, g);
188 if g.gen_infallible {
189 input_data.generate_infallible_impl(&mut ret, g);
190 }
191 if g.gen_unwrapping || g.gen_unwrapping_and_panicking {
192 input_data.generate_unwrapping_impl(&mut ret, g);
193 }
194 }
195
196 ret.into()
197}