neli_proc_macros/
derive_tobytes.rs
1use proc_macro2::TokenStream as TokenStream2;
2use quote::quote;
3use syn::{FieldsNamed, FieldsUnnamed, Ident, ItemEnum, ItemStruct};
4
5use crate::shared::{
6 generate_arms, generate_named_fields, generate_unnamed_fields, process_impl_generics,
7 process_trait_bounds, FieldInfo, StructInfo,
8};
9
10pub fn impl_tobytes_struct(is: ItemStruct) -> TokenStream2 {
11 let info = StructInfo::from_item_struct(is, Some("ToBytes"), "to_bytes_bound", true);
12 let (struct_name, generics, generics_without_bounds, field_names, field_types, _, padded) =
13 info.into_tuple();
14
15 if field_names.is_empty() {
16 return quote! {
17 impl neli::ToBytes for #struct_name {
18 fn to_bytes(&self, _: &mut std::io::Cursor<Vec<u8>>) -> Result<(), neli::err::SerError> {
19 Ok(())
20 }
21 }
22 };
23 }
24
25 let padding = if padded {
26 quote! {
27 <#struct_name#generics_without_bounds as neli::ToBytes>::pad(&self, buffer)?;
28 }
29 } else {
30 TokenStream2::new()
31 };
32
33 quote! {
34 impl#generics neli::ToBytes for #struct_name#generics_without_bounds {
35 fn to_bytes(&self, buffer: &mut std::io::Cursor<Vec<u8>>) -> Result<(), neli::err::SerError> {
36 #( <#field_types as neli::ToBytes>::to_bytes(&self.#field_names, buffer)?; )*
37 #padding
38 Ok(())
39 }
40 }
41 }
42}
43
44fn generate_named_pat_and_expr(
45 enum_name: Ident,
46 var_name: Ident,
47 fields: FieldsNamed,
48) -> TokenStream2 {
49 let (field_names, types, _) = FieldInfo::to_vecs(generate_named_fields(fields).into_iter());
50 quote! {
51 #enum_name::#var_name {
52 #(#field_names),*
53 } => {
54 #(<#types as neli::ToBytes>::to_bytes(&#field_names, buffer)?; )*
55 Ok(())
56 },
57 }
58}
59
60fn generate_unnamed_pat_and_expr(
61 enum_name: Ident,
62 var_name: Ident,
63 fields: FieldsUnnamed,
64) -> TokenStream2 {
65 let (field_names, types, _) =
66 FieldInfo::to_vecs(generate_unnamed_fields(fields, false).into_iter());
67 quote! {
68 #enum_name::#var_name(
69 #( #field_names ),*
70 ) => {
71 #( <#types as neli::ToBytes>::to_bytes(#field_names, buffer)?; )*
72 Ok(())
73 }
74 }
75}
76
77pub fn impl_tobytes_enum(ie: ItemEnum) -> TokenStream2 {
78 let (generics, generics_without_bounds) = process_impl_generics(ie.generics, Some("ToBytes"));
79 let trait_bounds = process_trait_bounds(&ie.attrs, "to_bytes_bound");
80
81 let enum_name = ie.ident;
82 let arms = generate_arms(
83 enum_name.clone(),
84 ie.variants.into_iter().collect::<Vec<_>>(),
85 generate_named_pat_and_expr,
86 generate_unnamed_pat_and_expr,
87 quote! {
88 Ok(())
89 },
90 );
91 quote! {
92 impl#generics neli::ToBytes for #enum_name#generics_without_bounds where #( #trait_bounds ),* {
93 fn to_bytes(&self, buffer: &mut std::io::Cursor<Vec<u8>>) -> Result<(), neli::err::SerError> {
94 match self {
95 #(#arms)*
96 }
97 }
98 }
99 }
100}