oasis_macros/
service_derive.rs1#[proc_macro_derive(Service)]
2pub fn service_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
3 if std::env::var("OASIS_BUILD_NO_SERVICE_DERIVE").is_ok() {
4 return proc_macro::TokenStream::new();
5 }
6 let input = parse_macro_input!(input as syn::DeriveInput);
7 let service = &input.ident;
8 let impl_wrapper_ident = format_ident!("_IMPL_SERVICE_FOR_{}", service);
9 proc_macro::TokenStream::from(match get_serde(&input) {
10 Some((ser, de)) => {
11 quote! {
12 #[allow(non_upper_case_globals)]
13 const #impl_wrapper_ident: () = {
14 use oasis_std::abi::*;
15
16 impl oasis_std::exe::Service for #service {
17 fn coalesce() -> Self {
18 #de
19 }
20
21 fn sunder(service: Self) {
22 #ser
23 }
24 }
25 };
26 }
27 }
28 None => quote! {},
29 })
30}
31
32fn get_serde(
33 input: &syn::DeriveInput,
34) -> Option<(proc_macro2::TokenStream, proc_macro2::TokenStream)> {
35 if input.generics.type_params().count() > 0 {
36 return None;
40 }
41
42 let (named, fields) = match &input.data {
43 syn::Data::Struct(s) => {
44 let named = match &s.fields {
45 syn::Fields::Named(_) | syn::Fields::Unit => true,
46 syn::Fields::Unnamed(_) => false,
47 };
48 (named, s.fields.iter())
49 }
50 _ => {
51 err!(input: "`#[derive(Service)]` can only be applied to structs.");
52 return None;
53 }
54 };
55
56 let (sers, des): (Vec<proc_macro2::TokenStream>, Vec<proc_macro2::TokenStream>) = fields
57 .enumerate()
58 .map(|(index, field)| {
59 let (struct_idx, key) = match &field.ident {
60 Some(ident) => (
61 syn::Member::Named(ident.clone()),
62 proc_macro2::Literal::string(&ident.to_string()),
63 ),
64 None => (
65 syn::Member::Unnamed(syn::Index {
66 index: index as u32,
67 span: proc_macro2::Span::call_site(),
68 }),
69 proc_macro2::Literal::string(&index.to_string()),
70 ),
71 };
72 let (ser, de) = get_type_serde(&field.ty, struct_idx, key);
73 let de = match &field.ident {
74 Some(ident) => quote! { #ident: #de },
75 None => de,
76 };
77 (ser, de)
78 })
79 .unzip();
80
81 let ser = quote! { #(#sers);* };
82
83 let de = if named {
84 quote! { Self { #(#des),* } }
85 } else {
86 quote! { Self(#(#des),*) }
87 };
88
89 Some((ser, de))
90}
91
92fn get_type_serde(
94 ty: &syn::Type,
95 struct_idx: syn::Member,
96 key: proc_macro2::Literal,
97) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
98 use syn::Type::*;
99 match ty {
100 Group(g) => get_type_serde(&*g.elem, struct_idx, key),
101 Paren(p) => get_type_serde(&*p.elem, struct_idx, key),
102 Array(_) | Tuple(_) | Path(_) => (
103 quote! {
104 oasis_std::backend::write(
105 #key.as_bytes(),
106 &service.#struct_idx.try_to_vec().unwrap()
107 )
108 },
109 quote! {
110 <_>::try_from_slice(
111 &oasis_std::backend::read(#key.as_bytes())
112 ).unwrap()
113 },
114 ),
115 ty => {
116 err!(ty: "Service field must be a POD type.");
117 (quote!(unreachable!()), quote!(unreachable!()))
118 }
119 }
120}