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
#![feature(try_blocks)]
use convert_case::Casing;
use proc_macro2::TokenStream;
use quote::quote as q;
use syn::Ident;
use syn::Token;
struct Argument {
name: Ident,
ty: syn::Type,
enum_attr: Vec<proc_macro2::Group>,
to_owned: bool,
}
impl std::fmt::Debug for Argument {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let t = &self.ty;
f.debug_struct("Argument")
.field("name", &self.name.to_string())
.field("ty", &format!("{}", q! {#t}))
.finish()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum ReceiverStyle {
Move,
Mut,
Ref,
}
struct Method {
name: Ident,
receiver_style: ReceiverStyle,
args: Vec<Argument>,
ret: Option<syn::Type>,
enum_attr: Vec<syn::Attribute>,
return_attr: Vec<syn::Attribute>,
doc_attr: Vec<syn::Attribute>,
r#async: bool,
}
impl Method {
fn variant_name(&self) -> proc_macro2::Ident {
let mut ident = quote::format_ident!(
"{}",
self.name
.to_string()
.to_case(convert_case::Case::UpperCamel)
);
ident.set_span(self.name.span());
ident
}
}
impl std::fmt::Debug for Method {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Method")
.field("name", &self.name.to_string())
.field("receiver_style", &self.receiver_style)
.field("args", &self.args)
.finish()
}
}
pub struct InputData {
name: Ident,
generics: syn::Generics,
struct_args: syn::PathArguments,
methods: Vec<Method>,
params: Params,
}
impl InputData {
fn has_async_functions(&self) -> bool {
self.methods.iter().any(|x| x.r#async)
}
}
pub enum Proxy {
Trait(Token![trait], syn::Ident),
}
pub struct Params {
visibility: syn::Visibility,
returnval: Option<syn::Type>,
proxies: Vec<Proxy>,
enum_attr: Vec<syn::Attribute>,
enum_name: Ident,
context: Option<(syn::Ident, syn::Type)>,
}
pub mod generate;
pub mod parse_args;
pub mod parse_input;
pub fn ctrlgen_impl(attrs: TokenStream, input: TokenStream) -> syn::Result<TokenStream> {
let params = syn::parse2(attrs)?;
let mut ret = TokenStream::new();
let mut imp: syn::ItemImpl = syn::parse2(input)?;
let input_data = InputData::parse_inherent_impl(&mut imp, params)?;
ret.extend(input_data.generate_enum());
ret.extend(input_data.generate_call_impl());
ret.extend(input_data.generate_proxies());
ret.extend(quote::quote! {#imp});
syn::Result::<TokenStream>::Ok(ret)
}