cdr_encoding_size_derive/
lib.rs1use proc_macro2::TokenStream;
2use quote::{quote, quote_spanned};
3use syn::{
4 parse_macro_input, parse_quote, spanned::Spanned, Data, DeriveInput, Fields, GenericParam,
5 Generics,
6};
7
8#[proc_macro_derive(CdrEncodingSize)]
16pub fn derive_cdr_encoding_size(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
17 let input = parse_macro_input!(input as DeriveInput);
19
20 let name = input.ident;
22
23 let generics = add_trait_bounds(input.generics);
25 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
26
27 let sum = cdr_size_sum(&input.data);
29
30 let expanded = quote! {
31 impl #impl_generics cdr_encoding_size::CdrEncodingSize for #name #ty_generics #where_clause {
33 fn cdr_encoding_max_size() -> cdr_encoding_size::CdrEncodingMaxSize {
34 #sum
35 }
36 }
37 };
38
39 proc_macro::TokenStream::from(expanded)
41}
42
43fn add_trait_bounds(mut generics: Generics) -> Generics {
45 for param in &mut generics.params {
46 if let GenericParam::Type(ref mut type_param) = *param {
47 type_param
48 .bounds
49 .push(parse_quote!(cdr_encoding_size::CdrEncodingSize));
50 }
51 }
52 generics
53}
54
55fn cdr_size_sum(data: &Data) -> TokenStream {
57 match *data {
58 Data::Struct(ref data) => {
59 match data.fields {
60 Fields::Named(ref fields) => {
61 let recurse = fields.named.iter().map(|f| {
62 let ty = &f.ty;
63 quote_spanned! {f.span()=>
64 <#ty>::cdr_encoding_max_size()
65 }
66 });
67 quote! {
68 cdr_encoding_size::CdrEncodingMaxSize::Bytes(0) #(+ #recurse)*
69 }
70 }
71 Fields::Unnamed(ref fields) => {
72 let recurse = fields.unnamed.iter().enumerate().map(|(_i, f)| {
73 let ty = &f.ty;
74 quote_spanned! {f.span()=>
76 <#ty>::cdr_encoding_max_size()
77 }
78 });
79 quote! {
80 cdr_encoding_size::CdrEncodingMaxSize::Bytes(0) #(+ #recurse)*
81 }
82 }
83 Fields::Unit => {
84 quote!(cdr_encoding_size::CdrEncodingMaxSize::Bytes(0))
85 }
86 }
87 }
88 Data::Enum(_) | Data::Union(_) => unimplemented!(),
89 }
90}