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
157#[derive(Debug, Clone, Default)]
166struct ContainerAttributes {
167 disable_encode: bool,
168 disable_pack: bool,
169}
170
171fn get_container_attributes(attrs: &[Attribute]) -> ContainerAttributes {
189 let mut disable_encode = false;
190 let mut disable_pack = false;
191
192 for attr in attrs {
193 if attr.path().is_ident("senax") {
194 let parsed = attr.parse_args_with(|input: syn::parse::ParseStream| {
195 let mut parsed_disable_encode = false;
196 let mut parsed_disable_pack = false;
197
198 while !input.is_empty() {
199 let ident = input.parse::<syn::Ident>()?;
200
201 if ident == "disable_encode" {
202 parsed_disable_encode = true;
203 } else if ident == "disable_pack" {
204 parsed_disable_pack = true;
205 } else {
206 return Err(syn::Error::new(
207 ident.span(),
208 format!("Unknown container attribute: {}", ident),
209 ));
210 }
211
212 if input.peek(syn::Token![,]) {
214 input.parse::<syn::Token![,]>()?;
215 }
216 }
217
218 Ok((parsed_disable_encode, parsed_disable_pack))
219 });
220
221 if let Ok((parsed_disable_encode, parsed_disable_pack)) = parsed {
222 disable_encode = disable_encode || parsed_disable_encode;
223 disable_pack = disable_pack || parsed_disable_pack;
224 }
225 }
226 }
227
228 ContainerAttributes {
229 disable_encode,
230 disable_pack,
231 }
232}
233
234fn get_field_attributes(attrs: &[Attribute], field_name: &str) -> FieldAttributes {
260 let mut id = None;
261 let mut default = false;
262 let mut skip_encode = false;
263 let mut skip_decode = false;
264 let mut skip_default = false;
265 let mut rename = None;
266
267 for attr in attrs {
268 if attr.path().is_ident("senax") {
269 let parsed = attr.parse_args_with(|input: syn::parse::ParseStream| {
271 let mut parsed_id = None;
272 let mut parsed_default = false;
273 let mut parsed_skip_encode = false;
274 let mut parsed_skip_decode = false;
275 let mut parsed_skip_default = false;
276 let mut parsed_rename = None;
277
278 while !input.is_empty() {
279 let ident = input.parse::<syn::Ident>()?;
280
281 if ident == "id" {
282 input.parse::<syn::Token![=]>()?;
283 let lit = input.parse::<syn::LitInt>()?;
284 if let Ok(id_val) = lit.base10_parse::<u64>() {
285 if id_val == 0 {
286 return Err(syn::Error::new(
287 lit.span(),
288 "Field ID 0 is reserved as a terminator",
289 ));
290 }
291 parsed_id = Some(id_val);
292 } else {
293 return Err(syn::Error::new(lit.span(), "Failed to parse ID value"));
294 }
295 } else if ident == "default" {
296 parsed_default = true;
297 } else if ident == "skip_encode" {
298 parsed_skip_encode = true;
299 } else if ident == "skip_decode" {
300 parsed_skip_decode = true;
301 } else if ident == "skip_default" {
302 parsed_skip_default = true;
303 } else if ident == "rename" {
304 input.parse::<syn::Token![=]>()?;
305 let lit_str = input.parse::<syn::LitStr>()?;
306 parsed_rename = Some(lit_str.value());
307 } else {
308 return Err(syn::Error::new(
309 ident.span(),
310 format!("Unknown attribute: {}", ident),
311 ));
312 }
313
314 if input.peek(syn::Token![,]) {
316 input.parse::<syn::Token![,]>()?;
317 }
318 }
319
320 Ok((
321 parsed_id,
322 parsed_default,
323 parsed_skip_encode,
324 parsed_skip_decode,
325 parsed_skip_default,
326 parsed_rename,
327 ))
328 });
329
330 if let Ok((
331 parsed_id,
332 parsed_default,
333 parsed_skip_encode,
334 parsed_skip_decode,
335 parsed_skip_default,
336 parsed_rename,
337 )) = parsed
338 {
339 if let Some(id_val) = parsed_id {
340 id = Some(id_val);
341 }
342 default = default || parsed_default;
343 skip_encode = skip_encode || parsed_skip_encode;
344 skip_decode = skip_decode || parsed_skip_decode;
345 skip_default = skip_default || parsed_skip_default;
346 if let Some(rename_val) = parsed_rename {
347 rename = Some(rename_val);
348 }
349 } else {
350 eprintln!(
351 "Warning: #[senax(...)] attribute for field '{}' is not in the correct format.",
352 field_name
353 );
354 }
355 }
356 }
357
358 let calculated_id = id.unwrap_or_else(|| {
360 let name_for_id = if let Some(ref rename_val) = rename {
361 rename_val.as_str()
362 } else {
363 field_name
364 };
365 calculate_id_from_name(name_for_id)
366 });
367
368 FieldAttributes {
369 id: calculated_id,
370 default,
371 skip_encode,
372 skip_decode,
373 skip_default,
374 rename,
375 }
376}
377
378fn is_option_type(ty: &Type) -> bool {
382 if let Type::Path(type_path) = ty {
383 type_path
384 .path
385 .segments
386 .last()
387 .is_some_and(|seg| seg.ident == "Option")
388 } else {
389 false
390 }
391}
392
393fn extract_inner_type_from_option(ty: &Type) -> Option<&Type> {
398 if let Type::Path(type_path) = ty {
399 if type_path
400 .path
401 .segments
402 .last()
403 .is_some_and(|seg| seg.ident == "Option")
404 {
405 if let PathArguments::AngleBracketed(args) =
406 &type_path.path.segments.last().unwrap().arguments
407 {
408 if let Some(GenericArgument::Type(inner_ty)) = args.args.first() {
409 return Some(inner_ty);
410 }
411 }
412 }
413 }
414 None
415}
416
417#[proc_macro_derive(Encode, attributes(senax))]
453pub fn derive_encode(input: TokenStream) -> TokenStream {
454 let input = parse_macro_input!(input as DeriveInput);
455 let name = &input.ident;
456 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
457
458 let container_attrs = get_container_attributes(&input.attrs);
460 if container_attrs.disable_encode {
461 return TokenStream::from(quote! {
462 impl #impl_generics senax_encoder::Encoder for #name #ty_generics #where_clause {
463 fn encode(&self, _writer: &mut bytes::BytesMut) -> senax_encoder::Result<()> {
464 unimplemented!("Encode trait is disabled for {}", stringify!(#name))
465 }
466
467 fn is_default(&self) -> bool {
468 unimplemented!("Encode trait is disabled for {}", stringify!(#name))
469 }
470 }
471 });
472 }
473
474 let mut default_variant_checks = Vec::new();
475
476 let encode_fields = match &input.data {
477 Data::Struct(s) => match &s.fields {
478 Fields::Named(fields) => {
479 let mut field_encode = Vec::new();
480 let mut used_ids_struct = HashSet::new();
481 for f in &fields.named {
482 let field_name_str = f.ident.as_ref().unwrap().to_string();
483 let field_attrs = get_field_attributes(&f.attrs, &field_name_str);
484
485 if field_attrs.skip_encode {
487 continue;
488 }
489
490 if !used_ids_struct.insert(field_attrs.id) {
491 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);
492 }
493
494 let field_ident = &f.ident;
495 let ty = &f.ty;
496 let is_option = is_option_type(ty);
497 let field_id = field_attrs.id;
498
499 if is_option {
500 field_encode.push(quote! {
501 if let Some(val) = &self.#field_ident {
502 senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
503 senax_encoder::Encoder::encode(&val, writer)?;
504 }
505 });
506 } else if field_attrs.skip_default {
507 field_encode.push(quote! {
509 if senax_encoder::Encoder::is_default(&self.#field_ident) == false {
510 senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
511 senax_encoder::Encoder::encode(&self.#field_ident, writer)?;
512 }
513 });
514 } else {
515 field_encode.push(quote! {
516 senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
517 senax_encoder::Encoder::encode(&self.#field_ident, writer)?;
518 });
519 }
520 }
521 quote! {
522 writer.put_u8(senax_encoder::core::TAG_STRUCT_NAMED);
523 #(#field_encode)*
524 senax_encoder::core::write_field_id_optimized(writer, 0)?;
525 }
526 }
527 Fields::Unnamed(fields) => {
528 let field_count = fields.unnamed.len();
529 let field_encode = fields.unnamed.iter().enumerate().map(|(i, _)| {
530 let index = syn::Index::from(i);
531 quote! {
532 senax_encoder::Encoder::encode(&self.#index, writer)?;
533 }
534 });
535 quote! {
536 writer.put_u8(senax_encoder::core::TAG_STRUCT_UNNAMED);
537 let count: usize = #field_count;
538 senax_encoder::Encoder::encode(&count, writer)?;
539 #(#field_encode)*
540 }
541 }
542 Fields::Unit => quote! {
543 writer.put_u8(senax_encoder::core::TAG_STRUCT_UNIT);
544 },
545 },
546 Data::Enum(e) => {
547 let mut variant_encode = Vec::new();
548 let mut used_ids_enum = HashSet::new();
549
550 for v in &e.variants {
551 let variant_name_str = v.ident.to_string();
552 let variant_attrs = get_field_attributes(&v.attrs, &variant_name_str);
553 let variant_id = variant_attrs.id;
554 let is_default_variant = has_default_attribute(&v.attrs);
555
556 if !used_ids_enum.insert(variant_id) {
557 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);
558 }
559
560 let variant_ident = &v.ident;
561
562 if is_default_variant {
564 match &v.fields {
565 Fields::Named(fields) => {
566 let field_idents: Vec<_> = fields
567 .named
568 .iter()
569 .map(|f| f.ident.as_ref().unwrap())
570 .collect();
571 let field_default_checks: Vec<_> = field_idents
572 .iter()
573 .map(|ident| {
574 quote! { senax_encoder::Encoder::is_default(#ident) }
575 })
576 .collect();
577
578 if field_default_checks.is_empty() {
579 default_variant_checks.push(quote! {
580 #name::#variant_ident { .. } => true,
581 });
582 } else {
583 default_variant_checks.push(quote! {
584 #name::#variant_ident { #(#field_idents),* } => {
585 #(#field_default_checks)&&*
586 },
587 });
588 }
589 }
590 Fields::Unnamed(fields) => {
591 let field_count = fields.unnamed.len();
592 let field_bindings: Vec<_> = (0..field_count)
593 .map(|i| Ident::new(&format!("field{}", i), Span::call_site()))
594 .collect();
595 let field_default_checks: Vec<_> = field_bindings
596 .iter()
597 .map(|binding| {
598 quote! { senax_encoder::Encoder::is_default(#binding) }
599 })
600 .collect();
601
602 if field_default_checks.is_empty() {
603 default_variant_checks.push(quote! {
604 #name::#variant_ident(..) => true,
605 });
606 } else {
607 default_variant_checks.push(quote! {
608 #name::#variant_ident(#(#field_bindings),*) => {
609 #(#field_default_checks)&&*
610 },
611 });
612 }
613 }
614 Fields::Unit => {
615 default_variant_checks.push(quote! {
616 #name::#variant_ident => true,
617 });
618 }
619 }
620 }
621
622 match &v.fields {
623 Fields::Named(fields) => {
624 let field_idents: Vec<_> = fields
625 .named
626 .iter()
627 .map(|f| f.ident.as_ref().unwrap())
628 .collect();
629 let mut field_encode = Vec::new();
630 let mut used_ids_struct = HashSet::new();
631 for f in &fields.named {
632 let field_name_str = f.ident.as_ref().unwrap().to_string();
633 let field_attrs = get_field_attributes(&f.attrs, &field_name_str);
634
635 if field_attrs.skip_encode {
637 continue;
638 }
639
640 if !used_ids_struct.insert(field_attrs.id) {
641 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);
642 }
643 let field_ident = &f.ident;
644 let ty = &f.ty;
645 let is_option = is_option_type(ty);
646 let field_id = field_attrs.id;
647 if is_option {
648 field_encode.push(quote! {
649 if let Some(val) = #field_ident {
650 senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
651 senax_encoder::Encoder::encode(&val, writer)?;
652 }
653 });
654 } else if field_attrs.skip_default {
655 field_encode.push(quote! {
657 if senax_encoder::Encoder::is_default(#field_ident) == false {
658 senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
659 senax_encoder::Encoder::encode(&#field_ident, writer)?;
660 }
661 });
662 } else {
663 field_encode.push(quote! {
664 senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
665 senax_encoder::Encoder::encode(&#field_ident, writer)?;
666 });
667 }
668 }
669 variant_encode.push(quote! {
670 #name::#variant_ident { #(#field_idents),* } => {
671 writer.put_u8(senax_encoder::core::TAG_ENUM_NAMED);
672 senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
673 #(#field_encode)*
674 senax_encoder::core::write_field_id_optimized(writer, 0)?;
675 }
676 });
677 }
678 Fields::Unnamed(fields) => {
679 let field_count = fields.unnamed.len();
680 let field_bindings: Vec<_> = (0..field_count)
681 .map(|i| Ident::new(&format!("field{}", i), Span::call_site()))
682 .collect();
683 let field_bindings_ref = &field_bindings;
684 variant_encode.push(quote! {
685 #name::#variant_ident( #(#field_bindings_ref),* ) => {
686 writer.put_u8(senax_encoder::core::TAG_ENUM_UNNAMED);
687 senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
688 let count: usize = #field_count;
689 senax_encoder::Encoder::encode(&count, writer)?;
690 #(
691 senax_encoder::Encoder::encode(&#field_bindings_ref, writer)?;
692 )*
693 }
694 });
695 }
696 Fields::Unit => {
697 variant_encode.push(quote! {
698 #name::#variant_ident => {
699 writer.put_u8(senax_encoder::core::TAG_ENUM);
700 senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
701 }
702 });
703 }
704 }
705 }
706 quote! {
707 match self {
708 #(#variant_encode)*
709 }
710 }
711 }
712 Data::Union(_) => unimplemented!("Unions are not supported"),
713 };
714
715 let is_default_impl = match &input.data {
716 Data::Enum(_) => {
717 if default_variant_checks.is_empty() {
718 quote! { false }
719 } else {
720 quote! {
721 match self {
722 #(#default_variant_checks)*
723 _ => false,
724 }
725 }
726 }
727 }
728 _ => quote! { false },
729 };
730
731 let encode_method = quote! {
732 fn encode(&self, writer: &mut bytes::BytesMut) -> senax_encoder::Result<()> {
733 use bytes::{Buf, BufMut};
734 #encode_fields
735 Ok(())
736 }
737
738 fn is_default(&self) -> bool {
739 #is_default_impl
740 }
741 };
742
743 TokenStream::from(quote! {
744 impl #impl_generics senax_encoder::Encoder for #name #ty_generics #where_clause {
745 #encode_method
746 }
747 })
748}
749
750#[proc_macro_derive(Decode, attributes(senax))]
790pub fn derive_decode(input: TokenStream) -> TokenStream {
791 let input = parse_macro_input!(input as DeriveInput);
792 let name = &input.ident;
793 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
794
795 let container_attrs = get_container_attributes(&input.attrs);
797 if container_attrs.disable_encode {
798 return TokenStream::from(quote! {
799 impl #impl_generics senax_encoder::Decoder for #name #ty_generics #where_clause {
800 fn decode(_reader: &mut bytes::Bytes) -> senax_encoder::Result<Self> {
801 unimplemented!("Decode trait is disabled for {}", stringify!(#name))
802 }
803 }
804 });
805 }
806
807 let decode_fields = match &input.data {
808 Data::Struct(s) => match &s.fields {
809 Fields::Named(fields) => {
810 let mut field_idents = Vec::new();
811 let mut field_original_types = Vec::new();
812 let mut field_ids_for_match = Vec::new();
813 let mut field_is_option_flags = Vec::new();
814 let mut field_attrs_list = Vec::new();
815 let mut used_ids_struct_decode = HashMap::new();
816
817 for f in &fields.named {
818 let field_name_str = f.ident.as_ref().unwrap().to_string();
819 let field_attrs = get_field_attributes(&f.attrs, &field_name_str);
820
821 if let Some(dup_field_name) =
822 used_ids_struct_decode.insert(field_attrs.id, field_name_str.clone())
823 {
824 panic!("Field ID (0x{:016X}) is duplicated for struct '{}'. Please specify a different ID for field '{}' and '{}' using #[senax(id=...)].",
825 field_attrs.id, name, dup_field_name, field_name_str);
826 }
827
828 field_idents.push(f.ident.as_ref().unwrap().clone());
829 field_original_types.push(f.ty.clone());
830 field_ids_for_match.push(field_attrs.id);
831 field_is_option_flags.push(is_option_type(&f.ty));
832 field_attrs_list.push(field_attrs);
833 }
834
835 let field_value_definitions = field_idents
836 .iter()
837 .zip(field_original_types.iter())
838 .zip(field_attrs_list.iter())
839 .filter_map(|((ident, original_ty), attrs)| {
840 if attrs.skip_decode {
841 None
843 } else if is_option_type(original_ty) {
844 Some(quote! { #ident: #original_ty, })
845 } else {
846 Some(quote! { #ident: Option<#original_ty>, })
847 }
848 });
849
850 let match_arms = field_idents
851 .iter()
852 .zip(field_original_types.iter())
853 .zip(field_ids_for_match.iter())
854 .zip(field_attrs_list.iter())
855 .filter_map(|(((ident, original_ty), id_val), attrs)| {
856 if attrs.skip_decode {
857 None
859 } else if is_option_type(original_ty) {
860 let inner_ty = extract_inner_type_from_option(original_ty)
861 .unwrap_or_else(|| {
862 panic!(
863 "Failed to extract inner type from Option for field {}",
864 ident
865 )
866 });
867 Some(quote! {
868 x if x == #id_val => {
869 field_values.#ident = Some(<#inner_ty as senax_encoder::Decoder>::decode(reader)?);
870 }
871 })
872 } else {
873 Some(quote! {
874 x if x == #id_val => {
875 field_values.#ident = Some(<#original_ty as senax_encoder::Decoder>::decode(reader)?);
876 }
877 })
878 }
879 });
880
881 let struct_assignments = field_idents
882 .iter()
883 .zip(field_is_option_flags.iter())
884 .zip(field_attrs_list.iter())
885 .map(|((ident, is_opt_flag), attrs)| {
886 if attrs.skip_decode {
887 quote! {
889 #ident: Default::default(),
890 }
891 } else if *is_opt_flag {
892 quote! {
893 #ident: field_values.#ident,
894 }
895 } else if attrs.default || attrs.skip_default {
896 quote! {
898 #ident: field_values.#ident.unwrap_or_default(),
899 }
900 } else {
901 quote! {
902 #ident: field_values.#ident.ok_or_else(||
903 senax_encoder::EncoderError::StructDecode(
904 senax_encoder::StructDecodeError::MissingRequiredField {
905 field: stringify!(#ident),
906 struct_name: stringify!(#name),
907 }
908 )
909 )?,
910 }
911 }
912 });
913
914 quote! {
915 if reader.remaining() == 0 {
916 return Err(senax_encoder::EncoderError::InsufficientData);
917 }
918 let tag = reader.get_u8();
919 if tag != senax_encoder::core::TAG_STRUCT_NAMED {
920 return Err(senax_encoder::EncoderError::StructDecode(
921 senax_encoder::StructDecodeError::InvalidTag {
922 expected: senax_encoder::core::TAG_STRUCT_NAMED,
923 actual: tag,
924 }
925 ));
926 }
927
928 #[derive(Default)]
929 struct FieldValues {
930 #( #field_value_definitions )*
931 }
932
933 let mut field_values = FieldValues::default();
934
935 loop {
936 let field_id = senax_encoder::core::read_field_id_optimized(reader)?;
937 if field_id == 0 {
938 break;
939 }
940 match field_id {
941 #( #match_arms )*
942 _unknown_id => { senax_encoder::core::skip_value(reader)?; }
943 }
944 }
945
946 Ok(#name {
947 #( #struct_assignments )*
948 })
949 }
950 }
951 Fields::Unnamed(fields) => {
952 let field_count = fields.unnamed.len();
953 let field_decode = fields.unnamed.iter().map(|f| {
954 let field_ty = &f.ty;
955 quote! {
956 <#field_ty as senax_encoder::Decoder>::decode(reader)?
957 }
958 });
959 quote! {
960 if reader.remaining() == 0 {
961 return Err(senax_encoder::EncoderError::InsufficientData);
962 }
963 let tag = reader.get_u8();
964 if tag != senax_encoder::core::TAG_STRUCT_UNNAMED {
965 return Err(senax_encoder::EncoderError::StructDecode(
966 senax_encoder::StructDecodeError::InvalidTag {
967 expected: senax_encoder::core::TAG_STRUCT_UNNAMED,
968 actual: tag,
969 }
970 ));
971 }
972 let count = <usize as senax_encoder::Decoder>::decode(reader)?;
973 if count != #field_count {
974 return Err(senax_encoder::EncoderError::StructDecode(
975 senax_encoder::StructDecodeError::FieldCountMismatch {
976 struct_name: stringify!(#name),
977 expected: #field_count,
978 actual: count,
979 }
980 ));
981 }
982 Ok(#name(
983 #(#field_decode),*
984 ))
985 }
986 }
987 Fields::Unit => quote! {
988 if reader.remaining() == 0 {
989 return Err(senax_encoder::EncoderError::InsufficientData);
990 }
991 let tag = reader.get_u8();
992 if tag != senax_encoder::core::TAG_STRUCT_UNIT {
993 return Err(senax_encoder::EncoderError::StructDecode(
994 senax_encoder::StructDecodeError::InvalidTag {
995 expected: senax_encoder::core::TAG_STRUCT_UNIT,
996 actual: tag,
997 }
998 ));
999 }
1000 Ok(#name)
1001 },
1002 },
1003 Data::Enum(e) => {
1004 let mut unit_variant_arms = Vec::new();
1005 let mut named_variant_arms = Vec::new();
1006 let mut unnamed_variant_arms = Vec::new();
1007 let mut used_ids_enum_decode = HashMap::new();
1008
1009 for v in &e.variants {
1010 let variant_name_str = v.ident.to_string();
1011 let variant_attrs = get_field_attributes(&v.attrs, &variant_name_str);
1012 let variant_id = variant_attrs.id;
1013
1014 if let Some(dup_variant) =
1015 used_ids_enum_decode.insert(variant_id, variant_name_str.clone())
1016 {
1017 panic!("Variant ID (0x{:016X}) is duplicated for enum '{}'. Please specify a different ID for variant '{}' and '{}' using #[senax(id=...)].",
1018 variant_id, name, dup_variant, variant_name_str);
1019 }
1020
1021 let variant_ident = &v.ident;
1022 match &v.fields {
1023 Fields::Named(fields) => {
1024 let field_idents: Vec<_> = fields
1025 .named
1026 .iter()
1027 .map(|f| f.ident.as_ref().unwrap().clone())
1028 .collect();
1029 let field_types: Vec<_> =
1030 fields.named.iter().map(|f| f.ty.clone()).collect();
1031 let field_attrs_list: Vec<_> = fields
1032 .named
1033 .iter()
1034 .map(|f| {
1035 get_field_attributes(
1036 &f.attrs,
1037 &f.ident.as_ref().unwrap().to_string(),
1038 )
1039 })
1040 .collect();
1041
1042 let mut field_value_definitions_enum = Vec::new();
1043 let mut match_arms_enum_named = Vec::new();
1044 let mut struct_assignments_enum_named = Vec::new();
1045
1046 for (ident, ty, attrs) in izip!(
1047 field_idents.iter(),
1048 field_types.iter(),
1049 field_attrs_list.iter()
1050 ) {
1051 if attrs.skip_decode {
1052 } else if is_option_type(ty) {
1054 field_value_definitions_enum.push(quote! { #ident: #ty, });
1055 } else {
1056 field_value_definitions_enum.push(quote! { #ident: Option<#ty>, });
1057 }
1058
1059 if attrs.skip_decode {
1060 } else if is_option_type(ty) {
1062 let inner_ty = extract_inner_type_from_option(ty).unwrap();
1063 let field_id = attrs.id;
1064 match_arms_enum_named.push(quote! {
1065 x if x == #field_id => { field_values.#ident = Some(<#inner_ty as senax_encoder::Decoder>::decode(reader)?); }
1066 });
1067 } else {
1068 let field_id = attrs.id;
1069 match_arms_enum_named.push(quote! {
1070 x if x == #field_id => { field_values.#ident = Some(<#ty as senax_encoder::Decoder>::decode(reader)?); }
1071 });
1072 }
1073
1074 if attrs.skip_decode {
1075 struct_assignments_enum_named
1077 .push(quote! { #ident: Default::default(), });
1078 } else if is_option_type(ty) {
1079 struct_assignments_enum_named
1080 .push(quote! { #ident: field_values.#ident, });
1081 } else if attrs.default || attrs.skip_default {
1082 struct_assignments_enum_named.push(quote! {
1084 #ident: field_values.#ident.unwrap_or_default(),
1085 });
1086 } else {
1087 struct_assignments_enum_named.push(quote! {
1088 #ident: field_values.#ident.ok_or_else(||
1089 senax_encoder::EncoderError::EnumDecode(
1090 senax_encoder::EnumDecodeError::MissingRequiredField {
1091 field: stringify!(#ident),
1092 enum_name: stringify!(#name),
1093 variant_name: stringify!(#variant_ident),
1094 }
1095 )
1096 )?,
1097 });
1098 }
1099 }
1100
1101 named_variant_arms.push(quote! {
1102 x if x == #variant_id => {
1103 #[derive(Default)]
1104 struct FieldValues { #(#field_value_definitions_enum)* }
1105 let mut field_values = FieldValues::default();
1106 loop {
1107 let field_id = {
1108 if reader.remaining() == 0 { break; }
1109 let id = senax_encoder::core::read_field_id_optimized(reader)?;
1110 if id == 0 { break; }
1111 id
1112 };
1113 match field_id {
1114 #(#match_arms_enum_named)*
1115 _unknown_id => { senax_encoder::core::skip_value(reader)?; }
1116 }
1117 }
1118 Ok(#name::#variant_ident { #(#struct_assignments_enum_named)* })
1119 }
1120 });
1121 }
1122 Fields::Unnamed(fields) => {
1123 let field_types: Vec<_> = fields.unnamed.iter().map(|f| &f.ty).collect();
1124 let field_count = field_types.len();
1125 unnamed_variant_arms.push(quote! {
1126 x if x == #variant_id => {
1127 let count = <usize as senax_encoder::Decoder>::decode(reader)?;
1128 if count != #field_count {
1129 return Err(senax_encoder::EncoderError::EnumDecode(
1130 senax_encoder::EnumDecodeError::FieldCountMismatch {
1131 enum_name: stringify!(#name),
1132 variant_name: stringify!(#variant_ident),
1133 expected: #field_count,
1134 actual: count,
1135 }
1136 ));
1137 }
1138 Ok(#name::#variant_ident(
1139 #(
1140 <#field_types as senax_encoder::Decoder>::decode(reader)?,
1141 )*
1142 ))
1143 }
1144 });
1145 }
1146 Fields::Unit => {
1147 unit_variant_arms.push(quote! {
1148 x if x == #variant_id => {
1149 Ok(#name::#variant_ident)
1150 }
1151 });
1152 }
1153 }
1154 }
1155 quote! {
1156 if reader.remaining() == 0 {
1157 return Err(senax_encoder::EncoderError::InsufficientData);
1158 }
1159 let tag = reader.get_u8();
1160 match tag {
1161 senax_encoder::core::TAG_ENUM => {
1162 let variant_id = senax_encoder::core::read_field_id_optimized(reader)?;
1163 match variant_id {
1164 #(#unit_variant_arms)*
1165 _ => Err(senax_encoder::EncoderError::EnumDecode(
1166 senax_encoder::EnumDecodeError::UnknownVariantId {
1167 variant_id,
1168 enum_name: stringify!(#name),
1169 }
1170 ))
1171 }
1172 }
1173 senax_encoder::core::TAG_ENUM_NAMED => {
1174 let variant_id = senax_encoder::core::read_field_id_optimized(reader)?;
1175 match variant_id {
1176 #(#named_variant_arms)*
1177 _ => Err(senax_encoder::EncoderError::EnumDecode(
1178 senax_encoder::EnumDecodeError::UnknownVariantId {
1179 variant_id,
1180 enum_name: stringify!(#name),
1181 }
1182 ))
1183 }
1184 }
1185 senax_encoder::core::TAG_ENUM_UNNAMED => {
1186 let variant_id = senax_encoder::core::read_field_id_optimized(reader)?;
1187 match variant_id {
1188 #(#unnamed_variant_arms)*
1189 _ => Err(senax_encoder::EncoderError::EnumDecode(
1190 senax_encoder::EnumDecodeError::UnknownVariantId {
1191 variant_id,
1192 enum_name: stringify!(#name),
1193 }
1194 ))
1195 }
1196 }
1197 unknown_tag => Err(senax_encoder::EncoderError::EnumDecode(
1198 senax_encoder::EnumDecodeError::UnknownTag {
1199 tag: unknown_tag,
1200 enum_name: stringify!(#name),
1201 }
1202 ))
1203 }
1204 }
1205 }
1206 Data::Union(_) => unimplemented!("Unions are not supported"),
1207 };
1208
1209 let decode_method = quote! {
1210 fn decode(reader: &mut bytes::Bytes) -> senax_encoder::Result<Self> {
1211 use bytes::{Buf, BufMut};
1212 #decode_fields
1213 }
1214 };
1215
1216 TokenStream::from(quote! {
1217 impl #impl_generics senax_encoder::Decoder for #name #ty_generics #where_clause {
1218 #decode_method
1219 }
1220 })
1221}
1222
1223#[proc_macro_derive(Pack, attributes(senax))]
1250pub fn derive_pack(input: TokenStream) -> TokenStream {
1251 let input = parse_macro_input!(input as DeriveInput);
1252 let name = &input.ident;
1253 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
1254
1255 let container_attrs = get_container_attributes(&input.attrs);
1257 if container_attrs.disable_pack {
1258 return TokenStream::from(quote! {
1259 impl #impl_generics senax_encoder::Packer for #name #ty_generics #where_clause {
1260 fn pack(&self, _writer: &mut bytes::BytesMut) -> senax_encoder::Result<()> {
1261 unimplemented!("Pack trait is disabled for {}", stringify!(#name))
1262 }
1263 }
1264 });
1265 }
1266
1267 let structure_info = generate_structure_info(&input);
1269 let structure_hash = CRC64.checksum(structure_info.as_bytes());
1270
1271 let pack_fields = match &input.data {
1273 Data::Struct(s) => match &s.fields {
1274 Fields::Named(fields) => {
1275 let field_encode = fields.named.iter().map(|f| {
1276 let field_ident = &f.ident;
1277 quote! {
1278 senax_encoder::Packer::pack(&self.#field_ident, writer)?;
1279 }
1280 });
1281 quote! {
1282 writer.put_u64_le(#structure_hash);
1284 #(#field_encode)*
1285 }
1286 }
1287 Fields::Unnamed(fields) => {
1288 let field_count = fields.unnamed.len();
1289 let field_encode = fields.unnamed.iter().enumerate().map(|(i, _)| {
1290 let index = syn::Index::from(i);
1291 quote! {
1292 senax_encoder::Packer::pack(&self.#index, writer)?;
1293 }
1294 });
1295 quote! {
1296 let count: usize = #field_count;
1298 senax_encoder::Encoder::encode(&count, writer)?;
1299 #(#field_encode)*
1300 }
1301 }
1302 Fields::Unit => quote! {
1303 },
1305 },
1306 Data::Enum(e) => {
1307 let mut variant_pack = Vec::new();
1308 let mut used_ids_enum_pack = HashSet::new();
1309
1310 for v in &e.variants {
1311 let variant_name_str = v.ident.to_string();
1312 let variant_attrs = get_field_attributes(&v.attrs, &variant_name_str);
1313 let variant_id = variant_attrs.id;
1314
1315 if !used_ids_enum_pack.insert(variant_id) {
1316 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);
1317 }
1318
1319 let variant_ident = &v.ident;
1320
1321 match &v.fields {
1322 Fields::Named(fields) => {
1323 let field_idents: Vec<_> = fields
1324 .named
1325 .iter()
1326 .map(|f| f.ident.as_ref().unwrap())
1327 .collect();
1328 let field_pack = field_idents.iter().map(|field_ident| {
1330 quote! {
1331 senax_encoder::Packer::pack(#field_ident, writer)?;
1332 }
1333 });
1334 variant_pack.push(quote! {
1335 #name::#variant_ident { #(#field_idents),* } => {
1336 senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
1338 writer.put_u64_le(#structure_hash);
1339 #(#field_pack)*
1340 }
1341 });
1342 }
1343 Fields::Unnamed(fields) => {
1344 let field_count = fields.unnamed.len();
1345 let field_bindings: Vec<_> = (0..field_count)
1346 .map(|i| Ident::new(&format!("field{}", i), Span::call_site()))
1347 .collect();
1348 let field_bindings_ref = &field_bindings;
1349 variant_pack.push(quote! {
1350 #name::#variant_ident( #(#field_bindings_ref),* ) => {
1351 senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
1353 let count: usize = #field_count;
1354 senax_encoder::Encoder::encode(&count, writer)?;
1355 #(
1356 senax_encoder::Packer::pack(&#field_bindings_ref, writer)?;
1357 )*
1358 }
1359 });
1360 }
1361 Fields::Unit => {
1362 variant_pack.push(quote! {
1363 #name::#variant_ident => {
1364 senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
1366 }
1367 });
1368 }
1369 }
1370 }
1371 quote! {
1372 match self {
1373 #(#variant_pack)*
1374 }
1375 }
1376 }
1377 Data::Union(_) => unimplemented!("Unions are not supported"),
1378 };
1379
1380 let pack_method = quote! {
1381 fn pack(&self, writer: &mut bytes::BytesMut) -> senax_encoder::Result<()> {
1382 use bytes::{Buf, BufMut};
1383 #pack_fields
1384 Ok(())
1385 }
1386 };
1387
1388 TokenStream::from(quote! {
1389 impl #impl_generics senax_encoder::Packer for #name #ty_generics #where_clause {
1390 #pack_method
1391 }
1392 })
1393}
1394
1395#[proc_macro_derive(Unpack, attributes(senax))]
1422pub fn derive_unpack(input: TokenStream) -> TokenStream {
1423 let input = parse_macro_input!(input as DeriveInput);
1424 let name = &input.ident;
1425 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
1426
1427 let container_attrs = get_container_attributes(&input.attrs);
1429 if container_attrs.disable_pack {
1430 return TokenStream::from(quote! {
1431 impl #impl_generics senax_encoder::Unpacker for #name #ty_generics #where_clause {
1432 fn unpack(_reader: &mut bytes::Bytes) -> senax_encoder::Result<Self> {
1433 unimplemented!("Unpack trait is disabled for {}", stringify!(#name))
1434 }
1435 }
1436 });
1437 }
1438
1439 let structure_info = generate_structure_info(&input);
1441 let structure_hash = CRC64.checksum(structure_info.as_bytes());
1442
1443 let unpack_fields = match &input.data {
1445 Data::Struct(s) => match &s.fields {
1446 Fields::Named(fields) => {
1447 let field_assignments = fields.named.iter().map(|f| {
1448 let field_ident = &f.ident;
1449 let field_ty = &f.ty;
1450 quote! {
1451 #field_ident: <#field_ty as senax_encoder::Unpacker>::unpack(reader)?,
1452 }
1453 });
1454 quote! {
1455 if reader.remaining() < 8 {
1457 return Err(senax_encoder::EncoderError::InsufficientData);
1458 }
1459 let received_hash = reader.get_u64_le();
1460 if received_hash != #structure_hash {
1461 return Err(senax_encoder::EncoderError::StructDecode(
1462 senax_encoder::StructDecodeError::StructureHashMismatch {
1463 struct_name: stringify!(#name),
1464 expected: #structure_hash,
1465 actual: received_hash,
1466 }
1467 ));
1468 }
1469
1470 Ok(#name {
1471 #(#field_assignments)*
1472 })
1473 }
1474 }
1475 Fields::Unnamed(fields) => {
1476 let expected_field_count = fields.unnamed.len();
1477 let field_decode = fields.unnamed.iter().map(|f| {
1478 let field_ty = &f.ty;
1479 quote! {
1480 <#field_ty as senax_encoder::Unpacker>::unpack(reader)?
1481 }
1482 });
1483 quote! {
1484 let field_count = <usize as senax_encoder::Decoder>::decode(reader)?;
1486 if field_count != #expected_field_count {
1487 return Err(senax_encoder::EncoderError::StructDecode(
1488 senax_encoder::StructDecodeError::FieldCountMismatch {
1489 struct_name: stringify!(#name),
1490 expected: #expected_field_count,
1491 actual: field_count,
1492 }
1493 ));
1494 }
1495
1496 Ok(#name(
1497 #(#field_decode),*
1498 ))
1499 }
1500 }
1501 Fields::Unit => quote! {
1502 Ok(#name)
1504 },
1505 },
1506 Data::Enum(e) => {
1507 let mut variant_unpack = Vec::new();
1508 let mut used_ids_enum_unpack = HashSet::new();
1509
1510 for v in &e.variants {
1511 let variant_name_str = v.ident.to_string();
1512 let variant_attrs = get_field_attributes(&v.attrs, &variant_name_str);
1513 let variant_id = variant_attrs.id;
1514
1515 if !used_ids_enum_unpack.insert(variant_id) {
1516 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);
1517 }
1518
1519 let variant_ident = &v.ident;
1520 match &v.fields {
1521 Fields::Named(fields) => {
1522 let field_idents: Vec<_> = fields
1523 .named
1524 .iter()
1525 .map(|f| f.ident.as_ref().unwrap().clone())
1526 .collect();
1527 let field_types: Vec<_> =
1528 fields.named.iter().map(|f| f.ty.clone()).collect();
1529
1530 let field_assignments =
1532 field_idents
1533 .iter()
1534 .zip(field_types.iter())
1535 .map(|(ident, ty)| {
1536 quote! {
1537 #ident: <#ty as senax_encoder::Unpacker>::unpack(reader)?,
1538 }
1539 });
1540
1541 variant_unpack.push(quote! {
1542 x if x == #variant_id => {
1543 if reader.remaining() < 8 {
1545 return Err(senax_encoder::EncoderError::InsufficientData);
1546 }
1547 let received_hash = reader.get_u64_le();
1548 if received_hash != #structure_hash {
1549 return Err(senax_encoder::EncoderError::EnumDecode(
1550 senax_encoder::EnumDecodeError::StructureHashMismatch {
1551 enum_name: stringify!(#name),
1552 variant_name: stringify!(#variant_ident),
1553 expected: #structure_hash,
1554 actual: received_hash,
1555 }
1556 ));
1557 }
1558 Ok(#name::#variant_ident { #(#field_assignments)* })
1559 }
1560 });
1561 }
1562 Fields::Unnamed(fields) => {
1563 let field_types: Vec<_> = fields.unnamed.iter().map(|f| &f.ty).collect();
1564 let expected_field_count = field_types.len();
1565 variant_unpack.push(quote! {
1566 x if x == #variant_id => {
1567 let field_count = <usize as senax_encoder::Decoder>::decode(reader)?;
1569 if field_count != #expected_field_count {
1570 return Err(senax_encoder::EncoderError::EnumDecode(
1571 senax_encoder::EnumDecodeError::FieldCountMismatch {
1572 enum_name: stringify!(#name),
1573 variant_name: stringify!(#variant_ident),
1574 expected: #expected_field_count,
1575 actual: field_count,
1576 }
1577 ));
1578 }
1579 Ok(#name::#variant_ident(
1580 #(
1581 <#field_types as senax_encoder::Unpacker>::unpack(reader)?,
1582 )*
1583 ))
1584 }
1585 });
1586 }
1587 Fields::Unit => {
1588 variant_unpack.push(quote! {
1589 x if x == #variant_id => {
1590 Ok(#name::#variant_ident)
1591 }
1592 });
1593 }
1594 }
1595 }
1596
1597 quote! {
1599 let variant_id = senax_encoder::core::read_field_id_optimized(reader)?;
1600 match variant_id {
1601 #(#variant_unpack)*
1602 _ => Err(senax_encoder::EncoderError::EnumDecode(
1603 senax_encoder::EnumDecodeError::UnknownVariantId {
1604 variant_id,
1605 enum_name: stringify!(#name),
1606 }
1607 ))
1608 }
1609 }
1610 }
1611 Data::Union(_) => unimplemented!("Unions are not supported"),
1612 };
1613
1614 let unpack_method = quote! {
1615 fn unpack(reader: &mut bytes::Bytes) -> senax_encoder::Result<Self> {
1616 use bytes::{Buf, BufMut};
1617 #unpack_fields
1618 }
1619 };
1620
1621 TokenStream::from(quote! {
1622 impl #impl_generics senax_encoder::Unpacker for #name #ty_generics #where_clause {
1623 #unpack_method
1624 }
1625 })
1626}