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
extern crate proc_macro;
use quote::quote;
mod generate;
mod parse;
use crate::{
generate::{FieldType, GetType},
parse::{FieldDef, GetTypeConf, PropertyDef, SetTypeConf},
};
#[proc_macro_derive(Property, attributes(property))]
pub fn derive_property(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = syn::parse_macro_input!(input as PropertyDef);
let expanded = {
let PropertyDef {
name,
generics,
fields,
} = input;
let (impl_generics, type_generics, where_clause_opt) = generics.split_for_impl();
let methods = fields.into_iter().fold(Vec::new(), |mut r, f| {
r.append(&mut derive_property_for_field(f));
r
});
quote!(
impl #impl_generics #name #type_generics #where_clause_opt {
#(#[inline(always)] #methods)*
}
)
};
expanded.into()
}
fn derive_property_for_field(field: FieldDef) -> Vec<proc_macro2::TokenStream> {
let mut property = Vec::new();
let field_type = &field.ty;
let field_name = &field.ident;
let field_conf = &field.conf;
let prop_field_type = FieldType::from_type(field_type);
if let Some(ts) = field_conf.get.vis.to_ts().and_then(|visibility| {
let method_name = field_conf.get.name.complete(field_name);
let get_type = match field_conf.get.typ {
GetTypeConf::NotSet => GetType::from_field_type(&prop_field_type),
GetTypeConf::Ref => GetType::Ref,
GetTypeConf::Copy_ => GetType::Copy_,
GetTypeConf::Clone_ => GetType::Clone_,
};
let generated = match get_type {
GetType::Ref => quote!(
#visibility fn #method_name(&self) -> &#field_type {
&self.#field_name
}
),
GetType::Copy_ => quote!(
#visibility fn #method_name(&self) -> #field_type {
self.#field_name
}
),
GetType::Clone_ => quote!(
#visibility fn #method_name(&self) -> #field_type {
self.#field_name.clone()
}
),
GetType::String_ => quote!(
#visibility fn #method_name(&self) -> &str {
&self.#field_name[..]
}
),
GetType::Slice(field_type) => quote!(
#visibility fn #method_name(&self) -> &#field_type {
&self.#field_name[..]
}
),
GetType::Option_(field_type) => quote!(
#visibility fn #method_name(&self) -> Option<&#field_type> {
self.#field_name.as_ref()
}
),
};
Some(generated)
}) {
property.push(ts);
}
if let Some(ts) = field_conf.set.vis.to_ts().and_then(|visibility| {
let method_name = field_conf.set.name.complete(field_name);
let generated = match field_conf.set.typ {
SetTypeConf::Ref => quote!(
#visibility fn #method_name(&mut self, val: #field_type) -> &mut Self {
self.#field_name = val;
self
}
),
SetTypeConf::Own => quote!(
#visibility fn #method_name(mut self, val: #field_type) -> Self {
self.#field_name = val;
self
}
),
};
Some(generated)
}) {
property.push(ts);
}
if let Some(ts) = field_conf.mut_.vis.to_ts().and_then(|visibility| {
let method_name = field_conf.mut_.name.complete(field_name);
let generated = quote!(
#visibility fn #method_name(&mut self) -> &mut #field_type {
&mut self.#field_name
}
);
Some(generated)
}) {
property.push(ts);
}
property
}