1use proc_macro::TokenStream;
2use proc_macro2::TokenStream as TokenStream2;
3use quote::quote;
4use syn::{Data, DeriveInput, Fields};
5
6#[proc_macro_attribute]
7pub fn payload(_attr: TokenStream, item: TokenStream) -> TokenStream {
8 let input: DeriveInput = syn::parse(item).unwrap();
9 let name = &input.ident;
10
11 let field_sizes = field_sizes(&input.data);
12
13 let expanded = quote! {
14 #[derive(
15 ::mcu_comms::serde::Serialize,
16 ::mcu_comms::serde::Deserialize,
17 )]
18 #[serde(crate = "::mcu_comms::serde")]
19 #input
20
21 impl ::mcu_comms::payload_size::MaxSize for #name {
22 const MAX_SIZE: usize = 0 #(+ #field_sizes)*;
23 }
24 impl ::mcu_comms::payload_size::MaxPayloadSize for #name {
25 const FRAME_SIZE: usize = <#name as ::mcu_comms::payload_size::MaxSize>::MAX_SIZE
26 + ::mcu_comms::aesccm::HEADER_SIZE
27 + ::mcu_comms::aesccm::TAG_SIZE;
28 type FrameBuf = [u8; Self::FRAME_SIZE];
29 fn new_buf() -> Self::FrameBuf {
30 [0_u8; Self::FRAME_SIZE]
31 }
32 }
33 impl ::mcu_comms::payload_size::Payload for #name {}
34 };
35 expanded.into()
36}
37
38fn field_sizes(data: &syn::Data) -> Vec<TokenStream2> {
39 let field_sizes = match data {
40 Data::Struct(data) => match &data.fields {
41 Fields::Named(fields) => fields
42 .named
43 .iter()
44 .map(|f| {
45 let ty = &f.ty;
46 quote! { <#ty as ::mcu_comms::payload_size::MaxSize>::MAX_SIZE }
47 })
48 .collect(),
49 Fields::Unnamed(fields) => fields
50 .unnamed
51 .iter()
52 .map(|f| {
53 let ty = &f.ty;
54 quote! {<#ty as ::mcu_comms::payload_size::MaxSize>::MAX_SIZE}
55 })
56 .collect(),
57 Fields::Unit => vec![],
58 },
59 Data::Enum(data) => {
60 let variant_sizes: Vec<TokenStream2> = data
61 .variants
62 .iter()
63 .map(|v| {
64 let field_sizes: Vec<TokenStream2> = v
65 .fields
66 .iter()
67 .map(|f| {
68 let ty = &f.ty;
69 quote! { <#ty as ::mcu_comms::payload_size::MaxSize>::MAX_SIZE }
70 })
71 .collect();
72 quote! { (0 #(+ #field_sizes)*) }
73 })
74 .collect();
75
76 vec![quote! {{
77 const fn max(a: usize, b: usize) -> usize {
78 if a > b { a } else { b }
79 }
80 let mut m = 0;
81 #( m = max(m, #variant_sizes); )*
82 m + 5
83 }}]
84 }
85 _ => panic!("Payload does not support this type"),
86 };
87 field_sizes
88}