1extern crate proc_macro;
2
3use crc::{Crc, CRC_64_ECMA_182};
4use itertools::izip;
5use proc_macro::TokenStream;
6use proc_macro2::Span;
7use quote::quote;
8use std::collections::{HashMap, HashSet};
9use syn::{
10 parse_macro_input, Attribute, Data, DeriveInput, Fields, GenericArgument, Ident, PathArguments,
11 Type,
12};
13
14const CRC64: Crc<u64> = Crc::<u64>::new(&CRC_64_ECMA_182);
16
17fn calculate_id_from_name(name: &str) -> u64 {
31 let crc64_hash = CRC64.checksum(name.as_bytes());
32 if crc64_hash == 0 {
34 u64::MAX
35 } else {
36 crc64_hash
37 }
38}
39
40fn generate_structure_info(input: &DeriveInput) -> String {
54 let mut info = String::new();
55 info.push_str(&format!("type:{}", input.ident));
56
57 match &input.data {
58 Data::Struct(s) => {
59 info.push_str("|struct");
60 match &s.fields {
61 Fields::Named(fields) => {
62 info.push_str("|named");
63 for field in &fields.named {
64 let field_name = field.ident.as_ref().unwrap().to_string();
65 let field_type = {
66 let ty = &field.ty;
67 quote!(#ty).to_string()
68 };
69 info.push_str(&format!("|{}:{}", field_name, field_type));
70 }
71 }
72 Fields::Unnamed(fields) => {
73 info.push_str("|unnamed");
74 for (i, field) in fields.unnamed.iter().enumerate() {
75 let field_type = {
76 let ty = &field.ty;
77 quote!(#ty).to_string()
78 };
79 info.push_str(&format!("|{}:{}", i, field_type));
80 }
81 }
82 Fields::Unit => {
83 info.push_str("|unit");
84 }
85 }
86 }
87 Data::Enum(e) => {
88 info.push_str("|enum");
89 for variant in &e.variants {
90 let variant_name = variant.ident.to_string();
91 info.push_str(&format!("|variant:{}", variant_name));
92 match &variant.fields {
93 Fields::Named(fields) => {
94 info.push_str("|named");
95 for field in &fields.named {
96 let field_name = field.ident.as_ref().unwrap().to_string();
97 let field_type = {
98 let ty = &field.ty;
99 quote!(#ty).to_string()
100 };
101 info.push_str(&format!("|{}:{}", field_name, field_type));
102 }
103 }
104 Fields::Unnamed(fields) => {
105 info.push_str("|unnamed");
106 for (i, field) in fields.unnamed.iter().enumerate() {
107 let field_type = {
108 let ty = &field.ty;
109 quote!(#ty).to_string()
110 };
111 info.push_str(&format!("|{}:{}", i, field_type));
112 }
113 }
114 Fields::Unit => {
115 info.push_str("|unit");
116 }
117 }
118 }
119 }
120 Data::Union(_) => {
121 info.push_str("|union");
122 }
123 }
124
125 info
126}
127
128fn has_default_attribute(attrs: &[Attribute]) -> bool {
130 attrs.iter().any(|attr| attr.path().is_ident("default"))
131}
132
133#[derive(Debug, Clone)]
147#[allow(dead_code)] struct FieldAttributes {
149 id: u64,
150 default: bool,
151 skip_encode: bool,
152 skip_decode: bool,
153 skip_default: bool,
154 rename: Option<String>,
155}
156
157fn get_field_attributes(attrs: &[Attribute], field_name: &str) -> FieldAttributes {
183 let mut id = None;
184 let mut default = false;
185 let mut skip_encode = false;
186 let mut skip_decode = false;
187 let mut skip_default = false;
188 let mut rename = None;
189
190 for attr in attrs {
191 if attr.path().is_ident("senax") {
192 let parsed = attr.parse_args_with(|input: syn::parse::ParseStream| {
194 let mut parsed_id = None;
195 let mut parsed_default = false;
196 let mut parsed_skip_encode = false;
197 let mut parsed_skip_decode = false;
198 let mut parsed_skip_default = false;
199 let mut parsed_rename = None;
200
201 while !input.is_empty() {
202 let ident = input.parse::<syn::Ident>()?;
203
204 if ident == "id" {
205 input.parse::<syn::Token![=]>()?;
206 let lit = input.parse::<syn::LitInt>()?;
207 if let Ok(id_val) = lit.base10_parse::<u64>() {
208 if id_val == 0 {
209 return Err(syn::Error::new(
210 lit.span(),
211 "Field ID 0 is reserved as a terminator",
212 ));
213 }
214 parsed_id = Some(id_val);
215 } else {
216 return Err(syn::Error::new(lit.span(), "Failed to parse ID value"));
217 }
218 } else if ident == "default" {
219 parsed_default = true;
220 } else if ident == "skip_encode" {
221 parsed_skip_encode = true;
222 } else if ident == "skip_decode" {
223 parsed_skip_decode = true;
224 } else if ident == "skip_default" {
225 parsed_skip_default = true;
226 } else if ident == "rename" {
227 input.parse::<syn::Token![=]>()?;
228 let lit_str = input.parse::<syn::LitStr>()?;
229 parsed_rename = Some(lit_str.value());
230 } else {
231 return Err(syn::Error::new(
232 ident.span(),
233 format!("Unknown attribute: {}", ident),
234 ));
235 }
236
237 if input.peek(syn::Token![,]) {
239 input.parse::<syn::Token![,]>()?;
240 }
241 }
242
243 Ok((
244 parsed_id,
245 parsed_default,
246 parsed_skip_encode,
247 parsed_skip_decode,
248 parsed_skip_default,
249 parsed_rename,
250 ))
251 });
252
253 if let Ok((
254 parsed_id,
255 parsed_default,
256 parsed_skip_encode,
257 parsed_skip_decode,
258 parsed_skip_default,
259 parsed_rename,
260 )) = parsed
261 {
262 if let Some(id_val) = parsed_id {
263 id = Some(id_val);
264 }
265 default = default || parsed_default;
266 skip_encode = skip_encode || parsed_skip_encode;
267 skip_decode = skip_decode || parsed_skip_decode;
268 skip_default = skip_default || parsed_skip_default;
269 if let Some(rename_val) = parsed_rename {
270 rename = Some(rename_val);
271 }
272 } else {
273 eprintln!(
274 "Warning: #[senax(...)] attribute for field '{}' is not in the correct format.",
275 field_name
276 );
277 }
278 }
279 }
280
281 let calculated_id = id.unwrap_or_else(|| {
283 let name_for_id = if let Some(ref rename_val) = rename {
284 rename_val.as_str()
285 } else {
286 field_name
287 };
288 calculate_id_from_name(name_for_id)
289 });
290
291 FieldAttributes {
292 id: calculated_id,
293 default,
294 skip_encode,
295 skip_decode,
296 skip_default,
297 rename,
298 }
299}
300
301fn is_option_type(ty: &Type) -> bool {
305 if let Type::Path(type_path) = ty {
306 type_path
307 .path
308 .segments
309 .last()
310 .is_some_and(|seg| seg.ident == "Option")
311 } else {
312 false
313 }
314}
315
316fn extract_inner_type_from_option(ty: &Type) -> Option<&Type> {
321 if let Type::Path(type_path) = ty {
322 if type_path
323 .path
324 .segments
325 .last()
326 .is_some_and(|seg| seg.ident == "Option")
327 {
328 if let PathArguments::AngleBracketed(args) =
329 &type_path.path.segments.last().unwrap().arguments
330 {
331 if let Some(GenericArgument::Type(inner_ty)) = args.args.first() {
332 return Some(inner_ty);
333 }
334 }
335 }
336 }
337 None
338}
339
340#[proc_macro_derive(Encode, attributes(senax))]
364pub fn derive_encode(input: TokenStream) -> TokenStream {
365 let input = parse_macro_input!(input as DeriveInput);
366 let name = &input.ident;
367 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
368
369 let mut default_variant_checks = Vec::new();
370
371 let encode_fields = match &input.data {
372 Data::Struct(s) => match &s.fields {
373 Fields::Named(fields) => {
374 let mut field_encode = Vec::new();
375 let mut used_ids_struct = HashSet::new();
376 for f in &fields.named {
377 let field_name_str = f.ident.as_ref().unwrap().to_string();
378 let field_attrs = get_field_attributes(&f.attrs, &field_name_str);
379
380 if field_attrs.skip_encode {
382 continue;
383 }
384
385 if !used_ids_struct.insert(field_attrs.id) {
386 panic!("Field ID (0x{:016X}) is duplicated for struct '{}'. Please specify a different ID for field '{}' using #[senax(id=...)].", field_attrs.id, name, field_name_str);
387 }
388
389 let field_ident = &f.ident;
390 let ty = &f.ty;
391 let is_option = is_option_type(ty);
392 let field_id = field_attrs.id;
393
394 if is_option {
395 field_encode.push(quote! {
396 if let Some(val) = &self.#field_ident {
397 senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
398 senax_encoder::Encoder::encode(&val, writer)?;
399 }
400 });
401 } else if field_attrs.skip_default {
402 field_encode.push(quote! {
404 if senax_encoder::Encoder::is_default(&self.#field_ident) == false {
405 senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
406 senax_encoder::Encoder::encode(&self.#field_ident, writer)?;
407 }
408 });
409 } else {
410 field_encode.push(quote! {
411 senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
412 senax_encoder::Encoder::encode(&self.#field_ident, writer)?;
413 });
414 }
415 }
416 quote! {
417 writer.put_u8(senax_encoder::core::TAG_STRUCT_NAMED);
418 #(#field_encode)*
419 senax_encoder::core::write_field_id_optimized(writer, 0)?;
420 }
421 }
422 Fields::Unnamed(fields) => {
423 let field_count = fields.unnamed.len();
424 let field_encode = fields.unnamed.iter().enumerate().map(|(i, _)| {
425 let index = syn::Index::from(i);
426 quote! {
427 senax_encoder::Encoder::encode(&self.#index, writer)?;
428 }
429 });
430 quote! {
431 writer.put_u8(senax_encoder::core::TAG_STRUCT_UNNAMED);
432 let count: usize = #field_count;
433 senax_encoder::Encoder::encode(&count, writer)?;
434 #(#field_encode)*
435 }
436 }
437 Fields::Unit => quote! {
438 writer.put_u8(senax_encoder::core::TAG_STRUCT_UNIT);
439 },
440 },
441 Data::Enum(e) => {
442 let mut variant_encode = Vec::new();
443 let mut used_ids_enum = HashSet::new();
444
445 for v in &e.variants {
446 let variant_name_str = v.ident.to_string();
447 let variant_attrs = get_field_attributes(&v.attrs, &variant_name_str);
448 let variant_id = variant_attrs.id;
449 let is_default_variant = has_default_attribute(&v.attrs);
450
451 if !used_ids_enum.insert(variant_id) {
452 panic!("Variant ID (0x{:016X}) is duplicated for enum '{}'. Please specify a different ID for variant '{}' using #[senax(id=...)].", variant_id, name, variant_name_str);
453 }
454
455 let variant_ident = &v.ident;
456
457 if is_default_variant {
459 match &v.fields {
460 Fields::Named(fields) => {
461 let field_idents: Vec<_> = fields
462 .named
463 .iter()
464 .map(|f| f.ident.as_ref().unwrap())
465 .collect();
466 let field_default_checks: Vec<_> = field_idents
467 .iter()
468 .map(|ident| {
469 quote! { senax_encoder::Encoder::is_default(#ident) }
470 })
471 .collect();
472
473 if field_default_checks.is_empty() {
474 default_variant_checks.push(quote! {
475 #name::#variant_ident { .. } => true,
476 });
477 } else {
478 default_variant_checks.push(quote! {
479 #name::#variant_ident { #(#field_idents),* } => {
480 #(#field_default_checks)&&*
481 },
482 });
483 }
484 }
485 Fields::Unnamed(fields) => {
486 let field_count = fields.unnamed.len();
487 let field_bindings: Vec<_> = (0..field_count)
488 .map(|i| Ident::new(&format!("field{}", i), Span::call_site()))
489 .collect();
490 let field_default_checks: Vec<_> = field_bindings
491 .iter()
492 .map(|binding| {
493 quote! { senax_encoder::Encoder::is_default(#binding) }
494 })
495 .collect();
496
497 if field_default_checks.is_empty() {
498 default_variant_checks.push(quote! {
499 #name::#variant_ident(..) => true,
500 });
501 } else {
502 default_variant_checks.push(quote! {
503 #name::#variant_ident(#(#field_bindings),*) => {
504 #(#field_default_checks)&&*
505 },
506 });
507 }
508 }
509 Fields::Unit => {
510 default_variant_checks.push(quote! {
511 #name::#variant_ident => true,
512 });
513 }
514 }
515 }
516
517 match &v.fields {
518 Fields::Named(fields) => {
519 let field_idents: Vec<_> = fields
520 .named
521 .iter()
522 .map(|f| f.ident.as_ref().unwrap())
523 .collect();
524 let mut field_encode = Vec::new();
525 let mut used_ids_struct = HashSet::new();
526 for f in &fields.named {
527 let field_name_str = f.ident.as_ref().unwrap().to_string();
528 let field_attrs = get_field_attributes(&f.attrs, &field_name_str);
529
530 if field_attrs.skip_encode {
532 continue;
533 }
534
535 if !used_ids_struct.insert(field_attrs.id) {
536 panic!("Field ID (0x{:016X}) is duplicated for enum variant '{}'. Please specify a different ID for field '{}' using #[senax(id=...)].", field_attrs.id, variant_ident, field_name_str);
537 }
538 let field_ident = &f.ident;
539 let ty = &f.ty;
540 let is_option = is_option_type(ty);
541 let field_id = field_attrs.id;
542 if is_option {
543 field_encode.push(quote! {
544 if let Some(val) = #field_ident {
545 senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
546 senax_encoder::Encoder::encode(&val, writer)?;
547 }
548 });
549 } else if field_attrs.skip_default {
550 field_encode.push(quote! {
552 if senax_encoder::Encoder::is_default(#field_ident) == false {
553 senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
554 senax_encoder::Encoder::encode(&#field_ident, writer)?;
555 }
556 });
557 } else {
558 field_encode.push(quote! {
559 senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
560 senax_encoder::Encoder::encode(&#field_ident, writer)?;
561 });
562 }
563 }
564 variant_encode.push(quote! {
565 #name::#variant_ident { #(#field_idents),* } => {
566 writer.put_u8(senax_encoder::core::TAG_ENUM_NAMED);
567 senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
568 #(#field_encode)*
569 senax_encoder::core::write_field_id_optimized(writer, 0)?;
570 }
571 });
572 }
573 Fields::Unnamed(fields) => {
574 let field_count = fields.unnamed.len();
575 let field_bindings: Vec<_> = (0..field_count)
576 .map(|i| Ident::new(&format!("field{}", i), Span::call_site()))
577 .collect();
578 let field_bindings_ref = &field_bindings;
579 variant_encode.push(quote! {
580 #name::#variant_ident( #(#field_bindings_ref),* ) => {
581 writer.put_u8(senax_encoder::core::TAG_ENUM_UNNAMED);
582 senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
583 let count: usize = #field_count;
584 senax_encoder::Encoder::encode(&count, writer)?;
585 #(
586 senax_encoder::Encoder::encode(&#field_bindings_ref, writer)?;
587 )*
588 }
589 });
590 }
591 Fields::Unit => {
592 variant_encode.push(quote! {
593 #name::#variant_ident => {
594 writer.put_u8(senax_encoder::core::TAG_ENUM);
595 senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
596 }
597 });
598 }
599 }
600 }
601 quote! {
602 match self {
603 #(#variant_encode)*
604 }
605 }
606 }
607 Data::Union(_) => unimplemented!("Unions are not supported"),
608 };
609
610 let is_default_impl = match &input.data {
611 Data::Enum(_) => {
612 if default_variant_checks.is_empty() {
613 quote! { false }
614 } else {
615 quote! {
616 match self {
617 #(#default_variant_checks)*
618 _ => false,
619 }
620 }
621 }
622 }
623 _ => quote! { false },
624 };
625
626 let encode_method = quote! {
627 fn encode(&self, writer: &mut bytes::BytesMut) -> senax_encoder::Result<()> {
628 use bytes::{Buf, BufMut};
629 #encode_fields
630 Ok(())
631 }
632
633 fn is_default(&self) -> bool {
634 #is_default_impl
635 }
636 };
637
638 TokenStream::from(quote! {
639 impl #impl_generics senax_encoder::Encoder for #name #ty_generics #where_clause {
640 #encode_method
641 }
642 })
643}
644
645#[proc_macro_derive(Decode, attributes(senax))]
673pub fn derive_decode(input: TokenStream) -> TokenStream {
674 let input = parse_macro_input!(input as DeriveInput);
675 let name = &input.ident;
676 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
677
678 let decode_fields = match &input.data {
679 Data::Struct(s) => match &s.fields {
680 Fields::Named(fields) => {
681 let mut field_idents = Vec::new();
682 let mut field_original_types = Vec::new();
683 let mut field_ids_for_match = Vec::new();
684 let mut field_is_option_flags = Vec::new();
685 let mut field_attrs_list = Vec::new();
686 let mut used_ids_struct_decode = HashMap::new();
687
688 for f in &fields.named {
689 let field_name_str = f.ident.as_ref().unwrap().to_string();
690 let field_attrs = get_field_attributes(&f.attrs, &field_name_str);
691
692 if let Some(dup_field_name) =
693 used_ids_struct_decode.insert(field_attrs.id, field_name_str.clone())
694 {
695 panic!("Field ID (0x{:016X}) is duplicated for struct '{}'. Please specify a different ID for field '{}' and '{}' using #[senax(id=...)].",
696 field_attrs.id, name, dup_field_name, field_name_str);
697 }
698
699 field_idents.push(f.ident.as_ref().unwrap().clone());
700 field_original_types.push(f.ty.clone());
701 field_ids_for_match.push(field_attrs.id);
702 field_is_option_flags.push(is_option_type(&f.ty));
703 field_attrs_list.push(field_attrs);
704 }
705
706 let field_value_definitions = field_idents
707 .iter()
708 .zip(field_original_types.iter())
709 .zip(field_attrs_list.iter())
710 .filter_map(|((ident, original_ty), attrs)| {
711 if attrs.skip_decode {
712 None
714 } else if is_option_type(original_ty) {
715 Some(quote! { #ident: #original_ty, })
716 } else {
717 Some(quote! { #ident: Option<#original_ty>, })
718 }
719 });
720
721 let match_arms = field_idents
722 .iter()
723 .zip(field_original_types.iter())
724 .zip(field_ids_for_match.iter())
725 .zip(field_attrs_list.iter())
726 .filter_map(|(((ident, original_ty), id_val), attrs)| {
727 if attrs.skip_decode {
728 None
730 } else if is_option_type(original_ty) {
731 let inner_ty = extract_inner_type_from_option(original_ty)
732 .unwrap_or_else(|| {
733 panic!(
734 "Failed to extract inner type from Option for field {}",
735 ident
736 )
737 });
738 Some(quote! {
739 x if x == #id_val => {
740 field_values.#ident = Some(<#inner_ty as senax_encoder::Decoder>::decode(reader)?);
741 }
742 })
743 } else {
744 Some(quote! {
745 x if x == #id_val => {
746 field_values.#ident = Some(<#original_ty as senax_encoder::Decoder>::decode(reader)?);
747 }
748 })
749 }
750 });
751
752 let struct_assignments = field_idents
753 .iter()
754 .zip(field_is_option_flags.iter())
755 .zip(field_attrs_list.iter())
756 .map(|((ident, is_opt_flag), attrs)| {
757 if attrs.skip_decode {
758 quote! {
760 #ident: Default::default(),
761 }
762 } else if *is_opt_flag {
763 quote! {
764 #ident: field_values.#ident,
765 }
766 } else if attrs.default || attrs.skip_default {
767 quote! {
769 #ident: field_values.#ident.unwrap_or_default(),
770 }
771 } else {
772 quote! {
773 #ident: field_values.#ident.ok_or_else(||
774 senax_encoder::EncoderError::StructDecode(
775 senax_encoder::StructDecodeError::MissingRequiredField {
776 field: stringify!(#ident),
777 struct_name: stringify!(#name),
778 }
779 )
780 )?,
781 }
782 }
783 });
784
785 quote! {
786 if reader.remaining() == 0 {
787 return Err(senax_encoder::EncoderError::InsufficientData);
788 }
789 let tag = reader.get_u8();
790 if tag != senax_encoder::core::TAG_STRUCT_NAMED {
791 return Err(senax_encoder::EncoderError::StructDecode(
792 senax_encoder::StructDecodeError::InvalidTag {
793 expected: senax_encoder::core::TAG_STRUCT_NAMED,
794 actual: tag,
795 }
796 ));
797 }
798
799 #[derive(Default)]
800 struct FieldValues {
801 #( #field_value_definitions )*
802 }
803
804 let mut field_values = FieldValues::default();
805
806 loop {
807 let field_id = senax_encoder::core::read_field_id_optimized(reader)?;
808 if field_id == 0 {
809 break;
810 }
811 match field_id {
812 #( #match_arms )*
813 _unknown_id => { senax_encoder::core::skip_value(reader)?; }
814 }
815 }
816
817 Ok(#name {
818 #( #struct_assignments )*
819 })
820 }
821 }
822 Fields::Unnamed(fields) => {
823 let field_count = fields.unnamed.len();
824 let field_decode = fields.unnamed.iter().map(|f| {
825 let field_ty = &f.ty;
826 quote! {
827 <#field_ty as senax_encoder::Decoder>::decode(reader)?
828 }
829 });
830 quote! {
831 if reader.remaining() == 0 {
832 return Err(senax_encoder::EncoderError::InsufficientData);
833 }
834 let tag = reader.get_u8();
835 if tag != senax_encoder::core::TAG_STRUCT_UNNAMED {
836 return Err(senax_encoder::EncoderError::StructDecode(
837 senax_encoder::StructDecodeError::InvalidTag {
838 expected: senax_encoder::core::TAG_STRUCT_UNNAMED,
839 actual: tag,
840 }
841 ));
842 }
843 let count = <usize as senax_encoder::Decoder>::decode(reader)?;
844 if count != #field_count {
845 return Err(senax_encoder::EncoderError::StructDecode(
846 senax_encoder::StructDecodeError::FieldCountMismatch {
847 struct_name: stringify!(#name),
848 expected: #field_count,
849 actual: count,
850 }
851 ));
852 }
853 Ok(#name(
854 #(#field_decode),*
855 ))
856 }
857 }
858 Fields::Unit => quote! {
859 if reader.remaining() == 0 {
860 return Err(senax_encoder::EncoderError::InsufficientData);
861 }
862 let tag = reader.get_u8();
863 if tag != senax_encoder::core::TAG_STRUCT_UNIT {
864 return Err(senax_encoder::EncoderError::StructDecode(
865 senax_encoder::StructDecodeError::InvalidTag {
866 expected: senax_encoder::core::TAG_STRUCT_UNIT,
867 actual: tag,
868 }
869 ));
870 }
871 Ok(#name)
872 },
873 },
874 Data::Enum(e) => {
875 let mut unit_variant_arms = Vec::new();
876 let mut named_variant_arms = Vec::new();
877 let mut unnamed_variant_arms = Vec::new();
878 let mut used_ids_enum_decode = HashMap::new();
879
880 for v in &e.variants {
881 let variant_name_str = v.ident.to_string();
882 let variant_attrs = get_field_attributes(&v.attrs, &variant_name_str);
883 let variant_id = variant_attrs.id;
884
885 if let Some(dup_variant) =
886 used_ids_enum_decode.insert(variant_id, variant_name_str.clone())
887 {
888 panic!("Variant ID (0x{:016X}) is duplicated for enum '{}'. Please specify a different ID for variant '{}' and '{}' using #[senax(id=...)].",
889 variant_id, name, dup_variant, variant_name_str);
890 }
891
892 let variant_ident = &v.ident;
893 match &v.fields {
894 Fields::Named(fields) => {
895 let field_idents: Vec<_> = fields
896 .named
897 .iter()
898 .map(|f| f.ident.as_ref().unwrap().clone())
899 .collect();
900 let field_types: Vec<_> =
901 fields.named.iter().map(|f| f.ty.clone()).collect();
902 let field_attrs_list: Vec<_> = fields
903 .named
904 .iter()
905 .map(|f| {
906 get_field_attributes(
907 &f.attrs,
908 &f.ident.as_ref().unwrap().to_string(),
909 )
910 })
911 .collect();
912
913 let mut field_value_definitions_enum = Vec::new();
914 let mut match_arms_enum_named = Vec::new();
915 let mut struct_assignments_enum_named = Vec::new();
916
917 for (ident, ty, attrs) in izip!(
918 field_idents.iter(),
919 field_types.iter(),
920 field_attrs_list.iter()
921 ) {
922 if attrs.skip_decode {
923 } else if is_option_type(ty) {
925 field_value_definitions_enum.push(quote! { #ident: #ty, });
926 } else {
927 field_value_definitions_enum.push(quote! { #ident: Option<#ty>, });
928 }
929
930 if attrs.skip_decode {
931 } else if is_option_type(ty) {
933 let inner_ty = extract_inner_type_from_option(ty).unwrap();
934 let field_id = attrs.id;
935 match_arms_enum_named.push(quote! {
936 x if x == #field_id => { field_values.#ident = Some(<#inner_ty as senax_encoder::Decoder>::decode(reader)?); }
937 });
938 } else {
939 let field_id = attrs.id;
940 match_arms_enum_named.push(quote! {
941 x if x == #field_id => { field_values.#ident = Some(<#ty as senax_encoder::Decoder>::decode(reader)?); }
942 });
943 }
944
945 if attrs.skip_decode {
946 struct_assignments_enum_named
948 .push(quote! { #ident: Default::default(), });
949 } else if is_option_type(ty) {
950 struct_assignments_enum_named
951 .push(quote! { #ident: field_values.#ident, });
952 } else if attrs.default || attrs.skip_default {
953 struct_assignments_enum_named.push(quote! {
955 #ident: field_values.#ident.unwrap_or_default(),
956 });
957 } else {
958 struct_assignments_enum_named.push(quote! {
959 #ident: field_values.#ident.ok_or_else(||
960 senax_encoder::EncoderError::EnumDecode(
961 senax_encoder::EnumDecodeError::MissingRequiredField {
962 field: stringify!(#ident),
963 enum_name: stringify!(#name),
964 variant_name: stringify!(#variant_ident),
965 }
966 )
967 )?,
968 });
969 }
970 }
971
972 named_variant_arms.push(quote! {
973 x if x == #variant_id => {
974 #[derive(Default)]
975 struct FieldValues { #(#field_value_definitions_enum)* }
976 let mut field_values = FieldValues::default();
977 loop {
978 let field_id = {
979 if reader.remaining() == 0 { break; }
980 let id = senax_encoder::core::read_field_id_optimized(reader)?;
981 if id == 0 { break; }
982 id
983 };
984 match field_id {
985 #(#match_arms_enum_named)*
986 _unknown_id => { senax_encoder::core::skip_value(reader)?; }
987 }
988 }
989 Ok(#name::#variant_ident { #(#struct_assignments_enum_named)* })
990 }
991 });
992 }
993 Fields::Unnamed(fields) => {
994 let field_types: Vec<_> = fields.unnamed.iter().map(|f| &f.ty).collect();
995 let field_count = field_types.len();
996 unnamed_variant_arms.push(quote! {
997 x if x == #variant_id => {
998 let count = <usize as senax_encoder::Decoder>::decode(reader)?;
999 if count != #field_count {
1000 return Err(senax_encoder::EncoderError::EnumDecode(
1001 senax_encoder::EnumDecodeError::FieldCountMismatch {
1002 enum_name: stringify!(#name),
1003 variant_name: stringify!(#variant_ident),
1004 expected: #field_count,
1005 actual: count,
1006 }
1007 ));
1008 }
1009 Ok(#name::#variant_ident(
1010 #(
1011 <#field_types as senax_encoder::Decoder>::decode(reader)?,
1012 )*
1013 ))
1014 }
1015 });
1016 }
1017 Fields::Unit => {
1018 unit_variant_arms.push(quote! {
1019 x if x == #variant_id => {
1020 Ok(#name::#variant_ident)
1021 }
1022 });
1023 }
1024 }
1025 }
1026 quote! {
1027 if reader.remaining() == 0 {
1028 return Err(senax_encoder::EncoderError::InsufficientData);
1029 }
1030 let tag = reader.get_u8();
1031 match tag {
1032 senax_encoder::core::TAG_ENUM => {
1033 let variant_id = senax_encoder::core::read_field_id_optimized(reader)?;
1034 match variant_id {
1035 #(#unit_variant_arms)*
1036 _ => Err(senax_encoder::EncoderError::EnumDecode(
1037 senax_encoder::EnumDecodeError::UnknownVariantId {
1038 variant_id,
1039 enum_name: stringify!(#name),
1040 }
1041 ))
1042 }
1043 }
1044 senax_encoder::core::TAG_ENUM_NAMED => {
1045 let variant_id = senax_encoder::core::read_field_id_optimized(reader)?;
1046 match variant_id {
1047 #(#named_variant_arms)*
1048 _ => Err(senax_encoder::EncoderError::EnumDecode(
1049 senax_encoder::EnumDecodeError::UnknownVariantId {
1050 variant_id,
1051 enum_name: stringify!(#name),
1052 }
1053 ))
1054 }
1055 }
1056 senax_encoder::core::TAG_ENUM_UNNAMED => {
1057 let variant_id = senax_encoder::core::read_field_id_optimized(reader)?;
1058 match variant_id {
1059 #(#unnamed_variant_arms)*
1060 _ => Err(senax_encoder::EncoderError::EnumDecode(
1061 senax_encoder::EnumDecodeError::UnknownVariantId {
1062 variant_id,
1063 enum_name: stringify!(#name),
1064 }
1065 ))
1066 }
1067 }
1068 unknown_tag => Err(senax_encoder::EncoderError::EnumDecode(
1069 senax_encoder::EnumDecodeError::UnknownTag {
1070 tag: unknown_tag,
1071 enum_name: stringify!(#name),
1072 }
1073 ))
1074 }
1075 }
1076 }
1077 Data::Union(_) => unimplemented!("Unions are not supported"),
1078 };
1079
1080 let decode_method = quote! {
1081 fn decode(reader: &mut bytes::Bytes) -> senax_encoder::Result<Self> {
1082 use bytes::{Buf, BufMut};
1083 #decode_fields
1084 }
1085 };
1086
1087 TokenStream::from(quote! {
1088 impl #impl_generics senax_encoder::Decoder for #name #ty_generics #where_clause {
1089 #decode_method
1090 }
1091 })
1092}
1093
1094#[proc_macro_derive(Pack, attributes(senax))]
1109pub fn derive_pack(input: TokenStream) -> TokenStream {
1110 let input = parse_macro_input!(input as DeriveInput);
1111 let name = &input.ident;
1112 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
1113
1114 let structure_info = generate_structure_info(&input);
1116 let structure_hash = CRC64.checksum(structure_info.as_bytes());
1117
1118 let pack_fields = match &input.data {
1120 Data::Struct(s) => match &s.fields {
1121 Fields::Named(fields) => {
1122 let field_encode = fields.named.iter().map(|f| {
1123 let field_ident = &f.ident;
1124 quote! {
1125 senax_encoder::Packer::pack(&self.#field_ident, writer)?;
1126 }
1127 });
1128 quote! {
1129 writer.put_u64_le(#structure_hash);
1131 #(#field_encode)*
1132 }
1133 }
1134 Fields::Unnamed(fields) => {
1135 let field_count = fields.unnamed.len();
1136 let field_encode = fields.unnamed.iter().enumerate().map(|(i, _)| {
1137 let index = syn::Index::from(i);
1138 quote! {
1139 senax_encoder::Packer::pack(&self.#index, writer)?;
1140 }
1141 });
1142 quote! {
1143 let count: usize = #field_count;
1145 senax_encoder::Encoder::encode(&count, writer)?;
1146 #(#field_encode)*
1147 }
1148 }
1149 Fields::Unit => quote! {
1150 },
1152 },
1153 Data::Enum(e) => {
1154 let mut variant_pack = Vec::new();
1155 let mut used_ids_enum_pack = HashSet::new();
1156
1157 for v in &e.variants {
1158 let variant_name_str = v.ident.to_string();
1159 let variant_attrs = get_field_attributes(&v.attrs, &variant_name_str);
1160 let variant_id = variant_attrs.id;
1161
1162 if !used_ids_enum_pack.insert(variant_id) {
1163 panic!("Variant ID (0x{:016X}) is duplicated for enum '{}'. Please specify a different ID for variant '{}' using #[senax(id=...)].", variant_id, name, variant_name_str);
1164 }
1165
1166 let variant_ident = &v.ident;
1167
1168 match &v.fields {
1169 Fields::Named(fields) => {
1170 let field_idents: Vec<_> = fields
1171 .named
1172 .iter()
1173 .map(|f| f.ident.as_ref().unwrap())
1174 .collect();
1175 let field_pack = field_idents.iter().map(|field_ident| {
1177 quote! {
1178 senax_encoder::Packer::pack(#field_ident, writer)?;
1179 }
1180 });
1181 variant_pack.push(quote! {
1182 #name::#variant_ident { #(#field_idents),* } => {
1183 senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
1185 writer.put_u64_le(#structure_hash);
1186 #(#field_pack)*
1187 }
1188 });
1189 }
1190 Fields::Unnamed(fields) => {
1191 let field_count = fields.unnamed.len();
1192 let field_bindings: Vec<_> = (0..field_count)
1193 .map(|i| Ident::new(&format!("field{}", i), Span::call_site()))
1194 .collect();
1195 let field_bindings_ref = &field_bindings;
1196 variant_pack.push(quote! {
1197 #name::#variant_ident( #(#field_bindings_ref),* ) => {
1198 senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
1200 let count: usize = #field_count;
1201 senax_encoder::Encoder::encode(&count, writer)?;
1202 #(
1203 senax_encoder::Packer::pack(&#field_bindings_ref, writer)?;
1204 )*
1205 }
1206 });
1207 }
1208 Fields::Unit => {
1209 variant_pack.push(quote! {
1210 #name::#variant_ident => {
1211 senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
1213 }
1214 });
1215 }
1216 }
1217 }
1218 quote! {
1219 match self {
1220 #(#variant_pack)*
1221 }
1222 }
1223 }
1224 Data::Union(_) => unimplemented!("Unions are not supported"),
1225 };
1226
1227 let pack_method = quote! {
1228 fn pack(&self, writer: &mut bytes::BytesMut) -> senax_encoder::Result<()> {
1229 use bytes::{Buf, BufMut};
1230 #pack_fields
1231 Ok(())
1232 }
1233 };
1234
1235 TokenStream::from(quote! {
1236 impl #impl_generics senax_encoder::Packer for #name #ty_generics #where_clause {
1237 #pack_method
1238 }
1239 })
1240}
1241
1242#[proc_macro_derive(Unpack, attributes(senax))]
1257pub fn derive_unpack(input: TokenStream) -> TokenStream {
1258 let input = parse_macro_input!(input as DeriveInput);
1259 let name = &input.ident;
1260 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
1261
1262 let structure_info = generate_structure_info(&input);
1264 let structure_hash = CRC64.checksum(structure_info.as_bytes());
1265
1266 let unpack_fields = match &input.data {
1268 Data::Struct(s) => match &s.fields {
1269 Fields::Named(fields) => {
1270 let field_assignments = fields.named.iter().map(|f| {
1271 let field_ident = &f.ident;
1272 let field_ty = &f.ty;
1273 quote! {
1274 #field_ident: <#field_ty as senax_encoder::Unpacker>::unpack(reader)?,
1275 }
1276 });
1277 quote! {
1278 if reader.remaining() < 8 {
1280 return Err(senax_encoder::EncoderError::InsufficientData);
1281 }
1282 let received_hash = reader.get_u64_le();
1283 if received_hash != #structure_hash {
1284 return Err(senax_encoder::EncoderError::StructDecode(
1285 senax_encoder::StructDecodeError::StructureHashMismatch {
1286 struct_name: stringify!(#name),
1287 expected: #structure_hash,
1288 actual: received_hash,
1289 }
1290 ));
1291 }
1292
1293 Ok(#name {
1294 #(#field_assignments)*
1295 })
1296 }
1297 }
1298 Fields::Unnamed(fields) => {
1299 let expected_field_count = fields.unnamed.len();
1300 let field_decode = fields.unnamed.iter().map(|f| {
1301 let field_ty = &f.ty;
1302 quote! {
1303 <#field_ty as senax_encoder::Unpacker>::unpack(reader)?
1304 }
1305 });
1306 quote! {
1307 let field_count = <usize as senax_encoder::Decoder>::decode(reader)?;
1309 if field_count != #expected_field_count {
1310 return Err(senax_encoder::EncoderError::StructDecode(
1311 senax_encoder::StructDecodeError::FieldCountMismatch {
1312 struct_name: stringify!(#name),
1313 expected: #expected_field_count,
1314 actual: field_count,
1315 }
1316 ));
1317 }
1318
1319 Ok(#name(
1320 #(#field_decode),*
1321 ))
1322 }
1323 }
1324 Fields::Unit => quote! {
1325 Ok(#name)
1327 },
1328 },
1329 Data::Enum(e) => {
1330 let mut variant_unpack = Vec::new();
1331 let mut used_ids_enum_unpack = HashSet::new();
1332
1333 for v in &e.variants {
1334 let variant_name_str = v.ident.to_string();
1335 let variant_attrs = get_field_attributes(&v.attrs, &variant_name_str);
1336 let variant_id = variant_attrs.id;
1337
1338 if !used_ids_enum_unpack.insert(variant_id) {
1339 panic!("Variant ID (0x{:016X}) is duplicated for enum '{}'. Please specify a different ID for variant '{}' using #[senax(id=...)].", variant_id, name, variant_name_str);
1340 }
1341
1342 let variant_ident = &v.ident;
1343 match &v.fields {
1344 Fields::Named(fields) => {
1345 let field_idents: Vec<_> = fields
1346 .named
1347 .iter()
1348 .map(|f| f.ident.as_ref().unwrap().clone())
1349 .collect();
1350 let field_types: Vec<_> =
1351 fields.named.iter().map(|f| f.ty.clone()).collect();
1352
1353 let field_assignments =
1355 field_idents
1356 .iter()
1357 .zip(field_types.iter())
1358 .map(|(ident, ty)| {
1359 quote! {
1360 #ident: <#ty as senax_encoder::Unpacker>::unpack(reader)?,
1361 }
1362 });
1363
1364 variant_unpack.push(quote! {
1365 x if x == #variant_id => {
1366 if reader.remaining() < 8 {
1368 return Err(senax_encoder::EncoderError::InsufficientData);
1369 }
1370 let received_hash = reader.get_u64_le();
1371 if received_hash != #structure_hash {
1372 return Err(senax_encoder::EncoderError::EnumDecode(
1373 senax_encoder::EnumDecodeError::StructureHashMismatch {
1374 enum_name: stringify!(#name),
1375 variant_name: stringify!(#variant_ident),
1376 expected: #structure_hash,
1377 actual: received_hash,
1378 }
1379 ));
1380 }
1381 Ok(#name::#variant_ident { #(#field_assignments)* })
1382 }
1383 });
1384 }
1385 Fields::Unnamed(fields) => {
1386 let field_types: Vec<_> = fields.unnamed.iter().map(|f| &f.ty).collect();
1387 let expected_field_count = field_types.len();
1388 variant_unpack.push(quote! {
1389 x if x == #variant_id => {
1390 let field_count = <usize as senax_encoder::Decoder>::decode(reader)?;
1392 if field_count != #expected_field_count {
1393 return Err(senax_encoder::EncoderError::EnumDecode(
1394 senax_encoder::EnumDecodeError::FieldCountMismatch {
1395 enum_name: stringify!(#name),
1396 variant_name: stringify!(#variant_ident),
1397 expected: #expected_field_count,
1398 actual: field_count,
1399 }
1400 ));
1401 }
1402 Ok(#name::#variant_ident(
1403 #(
1404 <#field_types as senax_encoder::Unpacker>::unpack(reader)?,
1405 )*
1406 ))
1407 }
1408 });
1409 }
1410 Fields::Unit => {
1411 variant_unpack.push(quote! {
1412 x if x == #variant_id => {
1413 Ok(#name::#variant_ident)
1414 }
1415 });
1416 }
1417 }
1418 }
1419
1420 quote! {
1422 let variant_id = senax_encoder::core::read_field_id_optimized(reader)?;
1423 match variant_id {
1424 #(#variant_unpack)*
1425 _ => Err(senax_encoder::EncoderError::EnumDecode(
1426 senax_encoder::EnumDecodeError::UnknownVariantId {
1427 variant_id,
1428 enum_name: stringify!(#name),
1429 }
1430 ))
1431 }
1432 }
1433 }
1434 Data::Union(_) => unimplemented!("Unions are not supported"),
1435 };
1436
1437 let unpack_method = quote! {
1438 fn unpack(reader: &mut bytes::Bytes) -> senax_encoder::Result<Self> {
1439 use bytes::{Buf, BufMut};
1440 #unpack_fields
1441 }
1442 };
1443
1444 TokenStream::from(quote! {
1445 impl #impl_generics senax_encoder::Unpacker for #name #ty_generics #where_clause {
1446 #unpack_method
1447 }
1448 })
1449}