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
#[proc_macro_derive(Service)]
pub fn service_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
if std::env::var("MANTLE_BUILD_NO_SERVICE_DERIVE").is_ok() {
return proc_macro::TokenStream::new();
}
let input = parse_macro_input!(input as syn::DeriveInput);
let service = &input.ident;
proc_macro::TokenStream::from(match get_serde(&input) {
Some((ser, de)) => {
quote! {
impl mantle::exe::Service for #service {
fn coalesce() -> Self {
#de
}
fn sunder(service: Self) {
#ser
}
}
}
}
None => quote! {},
})
}
fn get_serde(
input: &syn::DeriveInput,
) -> Option<(proc_macro2::TokenStream, proc_macro2::TokenStream)> {
if input.generics.type_params().count() > 0 {
return None;
}
let (named, fields) = match &input.data {
syn::Data::Struct(s) => {
let named = match &s.fields {
syn::Fields::Named(_) | syn::Fields::Unit => true,
syn::Fields::Unnamed(_) => false,
};
(named, s.fields.iter())
}
_ => {
err!(input: "`#[derive(Service)]` can only be applied to structs.");
return None;
}
};
let (sers, des): (Vec<proc_macro2::TokenStream>, Vec<proc_macro2::TokenStream>) = fields
.enumerate()
.map(|(index, field)| {
let (struct_idx, key) = match &field.ident {
Some(ident) => (
syn::Member::Named(ident.clone()),
proc_macro2::Literal::string(&ident.to_string()),
),
None => (
syn::Member::Unnamed(syn::Index {
index: index as u32,
span: proc_macro2::Span::call_site(),
}),
proc_macro2::Literal::string(&index.to_string()),
),
};
let (ser, de) = get_type_serde(&field.ty, struct_idx, key);
let de = match &field.ident {
Some(ident) => quote! { #ident: #de },
None => de,
};
(ser, de)
})
.unzip();
let ser = quote! { #(#sers);* };
let de = if named {
quote! { Self { #(#des),* } }
} else {
quote! { Self(#(#des),*) }
};
Some((ser, de))
}
fn get_type_serde(
ty: &syn::Type,
struct_idx: syn::Member,
key: proc_macro2::Literal,
) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
use syn::Type::*;
match ty {
Group(g) => get_type_serde(&*g.elem, struct_idx, key),
Paren(p) => get_type_serde(&*p.elem, struct_idx, key),
Array(_) | Tuple(_) | Path(_) => (
quote! {
mantle::backend::write(
#key.as_bytes(),
&mantle::reexports::serde_cbor::to_vec(&service.#struct_idx).unwrap()
)
},
quote! {
mantle::reexports::serde_cbor::from_slice(
&mantle::backend::read(#key.as_bytes())).unwrap()
},
),
ty => {
err!(ty: "Service field must be a POD type.");
(quote!(unreachable!()), quote!(unreachable!()))
}
}
}