ctrlgen_impl/
lib.rs

1use convert_case::Casing;
2use proc_macro2::TokenStream;
3use quote::quote as q;
4use syn::Ident;
5use syn::Token;
6
7struct Argument {
8    name: Ident,
9    ty: syn::Type,
10    enum_attr: Vec<proc_macro2::Group>,
11    to_owned: bool,
12}
13
14impl std::fmt::Debug for Argument {
15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16        let t = &self.ty;
17        f.debug_struct("Argument")
18            .field("name", &self.name.to_string())
19            .field("ty", &format!("{}", q! {#t}))
20            .finish()
21    }
22}
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25enum ReceiverStyle {
26    Move,
27    Mut,
28    Ref,
29}
30
31struct Method {
32    name: Ident,
33    receiver_style: ReceiverStyle,
34    args: Vec<Argument>,
35    ret: Option<syn::Type>,
36    enum_attr: Vec<syn::Attribute>,
37    return_attr: Vec<syn::Attribute>,
38    doc_attr: Vec<syn::Attribute>,
39    r#async: bool,
40}
41
42impl Method {
43    fn variant_name(&self) -> proc_macro2::Ident {
44        let mut ident = quote::format_ident!(
45            "{}",
46            self.name
47                .to_string()
48                .to_case(convert_case::Case::UpperCamel)
49        );
50        ident.set_span(self.name.span());
51        ident
52    }
53}
54
55impl std::fmt::Debug for Method {
56    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57        f.debug_struct("Method")
58            .field("name", &self.name.to_string())
59            .field("receiver_style", &self.receiver_style)
60            .field("args", &self.args)
61            .finish()
62    }
63}
64
65pub struct InputData {
66    /// Inherent impl name.
67    name: Ident,
68    generics: syn::Generics,
69    struct_args: syn::PathArguments,
70    methods: Vec<Method>,
71    params: Params,
72}
73
74impl InputData {
75    fn has_async_functions(&self) -> bool {
76        self.methods.iter().any(|x| x.r#async)
77    }
78}
79
80pub enum Proxy {
81    Trait(Token![trait], syn::Ident),
82}
83
84pub struct Params {
85    visibility: syn::Visibility,
86    returnval: Option<syn::Type>,
87    proxies: Vec<Proxy>,
88    enum_attr: Vec<syn::Attribute>,
89    enum_name: Ident,
90    context: Option<(syn::Ident, syn::Type)>,
91}
92
93pub mod generate;
94pub mod parse_args;
95pub mod parse_input;
96
97pub fn ctrlgen_impl(attrs: TokenStream, input: TokenStream) -> syn::Result<TokenStream> {
98    let params = syn::parse2(attrs)?;
99
100    let mut ret = TokenStream::new();
101    let mut imp: syn::ItemImpl = syn::parse2(input)?;
102    let input_data = InputData::parse_inherent_impl(&mut imp, params)?;
103
104    ret.extend(input_data.generate_enum());
105    ret.extend(input_data.generate_call_impl());
106    ret.extend(input_data.generate_proxies());
107    ret.extend(quote::quote! {#imp});
108
109    syn::Result::<TokenStream>::Ok(ret)
110}