trait_enumizer_derive/
lib.rs

1use 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    /// Source trait or inherent impl name.
52    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    //dbg!(thetrait);
131    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 &params.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 &params.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}