Skip to main content

voidmc_codec/
lib.rs

1mod primitives;
2
3pub use primitives::*;
4pub use voidmc_codec_macros::{Decode, Encode};
5
6pub trait Encode {
7    fn encode(&self, buf: &mut Vec<u8>);
8}
9
10pub trait Decode: Sized {
11    fn decode(buf: &mut &[u8]) -> Result<Self, DecodeError>;
12}
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum DecodeError {
16    UnexpectedEof,
17    InvalidVarintLength,
18    InvalidPacketId(Option<u8>),
19    InvalidLength,
20}
21
22impl std::fmt::Display for DecodeError {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        match self {
25            DecodeError::UnexpectedEof => write!(f, "Unexpected end of stream"),
26            DecodeError::InvalidVarintLength => write!(f, "Invalid variable-length integer"),
27            DecodeError::InvalidPacketId(Some(id)) => {
28                write!(f, "Unsupported packet id 0x{:02X}", id)
29            }
30            DecodeError::InvalidPacketId(None) => write!(f, "Invalid packet id"),
31            DecodeError::InvalidLength => write!(f, "Invalid length value"),
32        }
33    }
34}
35
36impl std::error::Error for DecodeError {}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41    use crate as voidmc_codec;
42
43    #[test]
44    fn test_struct_with_mixed_fields() {
45        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
46        pub struct TestPacket {
47            pub a: u8,
48            pub b: i32,
49            pub c: bool,
50        }
51
52        let packet = TestPacket {
53            a: 42,
54            b: 12345,
55            c: true,
56        };
57
58        let mut buf = Vec::new();
59        packet.encode(&mut buf);
60
61        let mut slice = buf.as_slice();
62        let decoded = TestPacket::decode(&mut slice).unwrap();
63
64        assert_eq!(decoded, packet);
65        assert_eq!(slice.len(), 0);
66    }
67
68    #[test]
69    fn test_struct_with_vari32() {
70        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
71        pub struct VarPacket {
72            pub prefix: u8,
73            #[codec(varint32)]
74            pub value: i32,
75        }
76
77        let packet = VarPacket {
78            prefix: 1,
79            value: 12345,
80        };
81
82        let mut buf = Vec::new();
83        packet.encode(&mut buf);
84
85        let mut slice = buf.as_slice();
86        let decoded = VarPacket::decode(&mut slice).unwrap();
87
88        assert_eq!(decoded, packet);
89        assert_eq!(slice.len(), 0);
90    }
91
92    #[test]
93    fn test_struct_with_vari32_compression() {
94        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
95        pub struct SmallVarPacket {
96            #[codec(varint32)]
97            pub value: i32,
98        }
99
100        let packet = SmallVarPacket { value: 100 };
101
102        let mut buf = Vec::new();
103        packet.encode(&mut buf);
104
105        let small_vari_size = buf.len();
106
107        let packet2 = SmallVarPacket { value: i32::MAX };
108
109        let mut buf2 = Vec::new();
110        packet2.encode(&mut buf2);
111
112        let large_vari_size = buf2.len();
113
114        assert!(small_vari_size < large_vari_size);
115        assert_eq!(small_vari_size, 1);
116        assert_eq!(large_vari_size, 5);
117    }
118
119    #[test]
120    fn test_tagged_enum() {
121        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
122        pub struct Packet1 {
123            pub data: u8,
124        }
125
126        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
127        pub struct Packet2 {
128            pub value: i32,
129        }
130
131        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode)]
132        #[codec(tagged)]
133        pub enum StatePacket {
134            #[codec(packet_id = 0)]
135            First(Packet1),
136            #[codec(packet_id = 1)]
137            Second(Packet2),
138        }
139
140        let packet = StatePacket::First(Packet1 { data: 42 });
141
142        let mut buf = Vec::new();
143        packet.encode(&mut buf);
144
145        assert_eq!(buf[0], 0);
146
147        let mut slice = buf.as_slice();
148        let decoded = StatePacket::decode(&mut slice).unwrap();
149
150        match decoded {
151            StatePacket::First(p) => assert_eq!(p.data, 42),
152            _ => panic!("Wrong variant"),
153        }
154    }
155
156    #[test]
157    fn test_tagged_enum_second_variant() {
158        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
159        pub struct Packet1 {
160            pub data: u8,
161        }
162
163        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
164        pub struct Packet2 {
165            pub value: i32,
166        }
167
168        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode)]
169        #[codec(tagged)]
170        pub enum StatePacket {
171            #[codec(packet_id = 0)]
172            First(Packet1),
173            #[codec(packet_id = 1)]
174            Second(Packet2),
175        }
176
177        let packet = StatePacket::Second(Packet2 { value: 12345 });
178
179        let mut buf = Vec::new();
180        packet.encode(&mut buf);
181
182        assert_eq!(buf[0], 1);
183
184        let mut slice = buf.as_slice();
185        let decoded = StatePacket::decode(&mut slice).unwrap();
186
187        match decoded {
188            StatePacket::Second(p) => assert_eq!(p.value, 12345),
189            _ => panic!("Wrong variant"),
190        }
191    }
192
193    #[test]
194    fn test_tagged_enum_invalid_id() {
195        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, Debug, PartialEq)]
196        #[codec(tagged)]
197        pub enum StatePacket {
198            #[codec(packet_id = 0)]
199            First(u8),
200        }
201
202        let buf = vec![255];
203        let mut slice = buf.as_slice();
204        let result = StatePacket::decode(&mut slice);
205
206        assert_eq!(result, Err(DecodeError::InvalidPacketId(Some(255))));
207    }
208
209    #[test]
210    fn test_unit_struct() {
211        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
212        pub struct UnitPacket;
213
214        let packet = UnitPacket;
215
216        let mut buf = Vec::new();
217        packet.encode(&mut buf);
218
219        assert_eq!(buf.len(), 0);
220
221        let mut slice = buf.as_slice();
222        let decoded = UnitPacket::decode(&mut slice).unwrap();
223
224        assert_eq!(decoded, packet);
225    }
226
227    #[test]
228    fn test_empty_decode() {
229        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
230        pub struct TestPacket {
231            pub a: i32,
232        }
233
234        let mut slice = &[][..];
235        let result = TestPacket::decode(&mut slice);
236
237        assert_eq!(result, Err(DecodeError::UnexpectedEof));
238    }
239
240    #[test]
241    fn test_multiple_vari32_fields() {
242        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
243        pub struct MultiVarPacket {
244            #[codec(varint32)]
245            pub a: i32,
246            #[codec(varint32)]
247            pub b: i32,
248            #[codec(varint32)]
249            pub c: i32,
250        }
251
252        let packet = MultiVarPacket {
253            a: 1,
254            b: 128,
255            c: -1,
256        };
257
258        let mut buf = Vec::new();
259        packet.encode(&mut buf);
260
261        let mut slice = buf.as_slice();
262        let decoded = MultiVarPacket::decode(&mut slice).unwrap();
263
264        assert_eq!(decoded, packet);
265    }
266
267    #[test]
268    fn test_mixed_vari32_and_regular() {
269        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
270        pub struct MixedPacket {
271            pub regular: u8,
272            #[codec(varint32)]
273            pub compact: i32,
274            pub regular2: i32,
275            #[codec(varint32)]
276            pub compact2: i32,
277        }
278
279        let packet = MixedPacket {
280            regular: 255,
281            compact: 100,
282            regular2: 0x12345678,
283            compact2: 50000,
284        };
285
286        let mut buf = Vec::new();
287        packet.encode(&mut buf);
288
289        let mut slice = buf.as_slice();
290        let decoded = MixedPacket::decode(&mut slice).unwrap();
291
292        assert_eq!(decoded, packet);
293    }
294
295    #[test]
296    fn test_nested_structs() {
297        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
298        pub struct Inner {
299            pub value: u8,
300        }
301
302        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
303        pub struct Outer {
304            pub inner: Inner,
305            pub extra: i32,
306        }
307
308        let packet = Outer {
309            inner: Inner { value: 42 },
310            extra: 12345,
311        };
312
313        let mut buf = Vec::new();
314        packet.encode(&mut buf);
315
316        let mut slice = buf.as_slice();
317        let decoded = Outer::decode(&mut slice).unwrap();
318
319        assert_eq!(decoded, packet);
320    }
321
322    #[test]
323    fn test_large_varint() {
324        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
325        pub struct LargeVarPacket {
326            #[codec(varint32)]
327            pub value: i32,
328        }
329
330        let packet = LargeVarPacket { value: 268435455 };
331
332        let mut buf = Vec::new();
333        packet.encode(&mut buf);
334
335        assert_eq!(buf.len(), 4);
336
337        let mut slice = buf.as_slice();
338        let decoded = LargeVarPacket::decode(&mut slice).unwrap();
339
340        assert_eq!(decoded, packet);
341    }
342
343    #[test]
344    fn test_repr_u8_enum() {
345        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
346        #[repr(u8)]
347        pub enum SimpleEnum {
348            First = 0,
349            Second = 1,
350            Third = 42,
351        }
352
353        for variant in [SimpleEnum::First, SimpleEnum::Second, SimpleEnum::Third] {
354            let mut buf = Vec::new();
355            variant.encode(&mut buf);
356
357            assert_eq!(buf.len(), 1);
358
359            let mut slice = buf.as_slice();
360            let decoded = SimpleEnum::decode(&mut slice).unwrap();
361
362            assert_eq!(decoded, variant);
363            assert_eq!(slice.len(), 0);
364        }
365    }
366
367    #[test]
368    fn test_repr_i32_enum() {
369        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
370        #[repr(i32)]
371        pub enum StatusEnum {
372            Pending = -1,
373            Active = 0,
374            Complete = 1,
375        }
376
377        for variant in [
378            StatusEnum::Pending,
379            StatusEnum::Active,
380            StatusEnum::Complete,
381        ] {
382            let mut buf = Vec::new();
383            variant.encode(&mut buf);
384
385            assert_eq!(buf.len(), 4);
386
387            let mut slice = buf.as_slice();
388            let decoded = StatusEnum::decode(&mut slice).unwrap();
389
390            assert_eq!(decoded, variant);
391            assert_eq!(slice.len(), 0);
392        }
393    }
394
395    #[test]
396    fn test_repr_i32_enum_varint32_compression() {
397        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
398        #[codec(varint32)]
399        #[repr(i32)]
400        pub enum CompressedEnum {
401            Small = 0,
402            Medium = 100,
403            Large = 268435455,
404        }
405
406        let variant = CompressedEnum::Large;
407        let mut buf = Vec::new();
408        variant.encode(&mut buf);
409
410        assert_eq!(buf.len(), 4);
411
412        let mut slice = buf.as_slice();
413        let decoded = CompressedEnum::decode(&mut slice).unwrap();
414
415        assert_eq!(decoded, variant);
416    }
417
418    #[test]
419    fn test_repr_u8_enum_invalid_discriminant() {
420        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
421        #[repr(u8)]
422        pub enum StatusEnum {
423            Active = 1,
424            Inactive = 2,
425        }
426
427        let buf = vec![99u8];
428        match StatusEnum::decode(&mut buf.as_slice()) {
429            Err(DecodeError::InvalidPacketId(None)) => (),
430            other => panic!("Expected InvalidPacketId error, got {:?}", other),
431        }
432    }
433
434    #[test]
435    fn test_repr_i32_enum_varint32() {
436        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
437        #[codec(varint32)]
438        #[repr(i32)]
439        pub enum VarIntEnum {
440            Zero = 0,
441            One = 1,
442            Hundred = 100,
443        }
444
445        let mut buf = Vec::new();
446        VarIntEnum::Hundred.encode(&mut buf);
447
448        assert!(buf.len() < 4);
449
450        let mut slice = buf.as_slice();
451        let decoded = VarIntEnum::decode(&mut slice).unwrap();
452
453        assert_eq!(decoded, VarIntEnum::Hundred);
454    }
455
456    #[test]
457    fn test_fixed_length_vec_literal() {
458        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
459        pub struct FixedLengthLiteral {
460            #[codec(fixed_length = 3)]
461            pub data: Vec<u8>,
462        }
463
464        let original = FixedLengthLiteral {
465            data: vec![1, 2, 3],
466        };
467
468        let mut buf = Vec::new();
469        original.encode(&mut buf);
470
471        let mut slice = buf.as_slice();
472        let decoded = FixedLengthLiteral::decode(&mut slice).unwrap();
473
474        assert_eq!(decoded, original);
475    }
476
477    #[test]
478    fn test_fixed_length_vec_field_reference() {
479        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
480        pub struct FixedLengthFieldRef {
481            pub length: u32,
482            #[codec(fixed_length = length)]
483            pub data: Vec<u8>,
484        }
485
486        let original = FixedLengthFieldRef {
487            length: 5,
488            data: vec![10, 20, 30, 40, 50],
489        };
490
491        let mut buf = Vec::new();
492        original.encode(&mut buf);
493
494        let mut slice = buf.as_slice();
495        let decoded = FixedLengthFieldRef::decode(&mut slice).unwrap();
496
497        assert_eq!(decoded, original);
498    }
499
500    #[test]
501    fn test_fixed_length_vec_arithmetic() {
502        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
503        pub struct FixedLengthArithmetic {
504            pub length: u32,
505            pub factor: u32,
506            #[codec(fixed_length = length * factor)]
507            pub data: Vec<u8>,
508        }
509
510        let original = FixedLengthArithmetic {
511            length: 3,
512            factor: 2,
513            data: vec![1, 2, 3, 4, 5, 6],
514        };
515
516        let mut buf = Vec::new();
517        original.encode(&mut buf);
518
519        let mut slice = buf.as_slice();
520        let decoded = FixedLengthArithmetic::decode(&mut slice).unwrap();
521
522        assert_eq!(decoded, original);
523    }
524
525    #[test]
526    fn test_fixed_length_vec_complex_expression() {
527        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
528        pub struct FixedLengthComplex {
529            pub length: u32,
530            pub factor: u32,
531            #[codec(fixed_length = (length + 5) * factor - 2)]
532            pub data: Vec<u8>,
533        }
534
535        // (4 + 5) * 2 - 2 = 9 * 2 - 2 = 18 - 2 = 16
536        let original = FixedLengthComplex {
537            length: 4,
538            factor: 2,
539            data: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
540        };
541
542        let mut buf = Vec::new();
543        original.encode(&mut buf);
544
545        let mut slice = buf.as_slice();
546        let decoded = FixedLengthComplex::decode(&mut slice).unwrap();
547
548        assert_eq!(decoded, original);
549    }
550
551    #[test]
552    fn test_fixed_length_vec_multiple_fields() {
553        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
554        pub struct MultipleFixedLength {
555            pub length: u32,
556            pub factor: u32,
557            #[codec(fixed_length = length)]
558            pub field_a: Vec<u8>,
559            #[codec(fixed_length = length * factor)]
560            pub field_b: Vec<u8>,
561            #[codec(fixed_length = 2)]
562            pub field_c: Vec<u8>,
563        }
564
565        let original = MultipleFixedLength {
566            length: 3,
567            factor: 2,
568            field_a: vec![1, 2, 3],
569            field_b: vec![4, 5, 6, 7, 8, 9],
570            field_c: vec![10, 11],
571        };
572
573        let mut buf = Vec::new();
574        original.encode(&mut buf);
575
576        let mut slice = buf.as_slice();
577        let decoded = MultipleFixedLength::decode(&mut slice).unwrap();
578
579        assert_eq!(decoded, original);
580    }
581
582    #[test]
583    #[should_panic(expected = "Fixed-length vector length mismatch")]
584    fn test_fixed_length_vec_wrong_length() {
585        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
586        pub struct FixedLengthWrong {
587            #[codec(fixed_length = 3)]
588            pub data: Vec<u8>,
589        }
590
591        let invalid = FixedLengthWrong {
592            data: vec![1, 2], // Wrong: should be 3 items
593        };
594
595        let mut buf = Vec::new();
596        invalid.encode(&mut buf); // Should panic
597    }
598
599    #[test]
600    fn test_fixed_length_no_length_prefix() {
601        // Verify that fixed-length vectors don't encode a length prefix
602        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
603        pub struct FixedLengthNormal {
604            pub length: u32,
605            #[codec(fixed_length = length)]
606            pub data: Vec<u8>,
607        }
608
609        let original = FixedLengthNormal {
610            length: 5,
611            data: vec![10, 20, 30, 40, 50],
612        };
613
614        let mut buf = Vec::new();
615        original.encode(&mut buf);
616
617        // The buffer should contain:
618        // - 4 bytes for u32 length field (big-endian): 0x00, 0x00, 0x00, 0x05
619        // - 5 bytes for the data (no length prefix): 10, 20, 30, 40, 50
620        // Total: 9 bytes (NOT 10 bytes which would include a varint32 length prefix)
621        assert_eq!(
622            buf.len(),
623            9,
624            "Fixed-length vector should not include length prefix"
625        );
626        assert_eq!(buf[0..4], [0, 0, 0, 5]); // The length field
627        assert_eq!(buf[4..9], [10, 20, 30, 40, 50]); // The data without prefix
628    }
629
630    #[test]
631    fn test_fixed_length_vs_normal_vector_size() {
632        // Compare sizes: fixed-length should NOT have varint length prefix, normal vectors should
633        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode)]
634        pub struct WithNormalVector {
635            pub data: Vec<u8>,
636        }
637
638        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode)]
639        pub struct WithFixedLengthVector {
640            pub length: u32,
641            #[codec(fixed_length = length)]
642            pub data: Vec<u8>,
643        }
644
645        let data = vec![1, 2, 3, 4, 5];
646
647        let normal = WithNormalVector { data: data.clone() };
648
649        let fixed = WithFixedLengthVector {
650            length: 5,
651            data: data.clone(),
652        };
653
654        let mut normal_buf = Vec::new();
655        normal.encode(&mut normal_buf);
656
657        let mut fixed_buf = Vec::new();
658        fixed.encode(&mut fixed_buf);
659
660        // Normal vector: 1 byte varint32 length prefix + 5 bytes data = 6 bytes
661        // Fixed vector: 4 bytes length (u32) + 5 bytes data (no prefix) = 9 bytes
662        // Note: fixed is larger because it includes u32 field, but its data section is smaller
663        assert_eq!(
664            normal_buf.len(),
665            6,
666            "Normal vector should include 1-byte varint32 length prefix"
667        );
668        assert_eq!(normal_buf[0], 5); // First byte is the varint32 length
669        assert_eq!(normal_buf[1..], [1, 2, 3, 4, 5]); // Then the data
670
671        assert_eq!(
672            fixed_buf.len(),
673            9,
674            "Fixed-length vector struct includes u32 field"
675        );
676        assert_eq!(fixed_buf[0..4], [0, 0, 0, 5]); // u32 length field (big-endian)
677        assert_eq!(fixed_buf[4..9], [1, 2, 3, 4, 5]); // Data without varint prefix
678    }
679
680    #[test]
681    fn test_fixed_length_decode_from_raw_bytes() {
682        // Verify we can decode fixed-length vectors from manually constructed byte buffers
683        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
684        pub struct FixedLengthManual {
685            pub length: u32,
686            #[codec(fixed_length = length)]
687            pub data: Vec<u8>,
688        }
689
690        // Manually construct the buffer:
691        // - 4 bytes for length (5 in big-endian): 0x00, 0x00, 0x00, 0x05
692        // - 5 bytes of data: 100, 101, 102, 103, 104
693        let buf = vec![0x00, 0x00, 0x00, 0x05, 100, 101, 102, 103, 104];
694
695        let mut slice = buf.as_slice();
696        let decoded = FixedLengthManual::decode(&mut slice).unwrap();
697
698        assert_eq!(decoded.length, 5);
699        assert_eq!(decoded.data, vec![100, 101, 102, 103, 104]);
700        // All bytes should be consumed
701        assert_eq!(slice.len(), 0);
702    }
703
704    #[test]
705    fn test_fixed_length_roundtrip_preserves_format() {
706        // Verify encode -> decode -> encode produces identical bytes
707        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
708        pub struct FixedLengthRoundtrip {
709            pub length: u32,
710            #[codec(fixed_length = length)]
711            pub data: Vec<u8>,
712        }
713
714        let original = FixedLengthRoundtrip {
715            length: 3,
716            data: vec![42, 43, 44],
717        };
718
719        // First encoding
720        let mut buf1 = Vec::new();
721        original.encode(&mut buf1);
722
723        // Decode
724        let mut slice = buf1.as_slice();
725        let decoded = FixedLengthRoundtrip::decode(&mut slice).unwrap();
726
727        // Second encoding
728        let mut buf2 = Vec::new();
729        decoded.encode(&mut buf2);
730
731        // Buffers should be identical
732        assert_eq!(
733            buf1, buf2,
734            "Roundtrip encode/decode should produce identical bytes"
735        );
736    }
737
738    #[test]
739    fn test_fixed_length_multiple_fields_binary_format() {
740        // Verify multiple fixed-length fields don't include prefixes
741        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
742        pub struct MultipleFix {
743            pub len_a: u32,
744            pub len_b: u32,
745            #[codec(fixed_length = len_a)]
746            pub field_a: Vec<u8>,
747            #[codec(fixed_length = len_b)]
748            pub field_b: Vec<u8>,
749        }
750
751        let original = MultipleFix {
752            len_a: 2,
753            len_b: 3,
754            field_a: vec![1, 2],
755            field_b: vec![10, 11, 12],
756        };
757
758        let mut buf = Vec::new();
759        original.encode(&mut buf);
760
761        // Expected format:
762        // - 4 bytes len_a: 0x00, 0x00, 0x00, 0x02
763        // - 4 bytes len_b: 0x00, 0x00, 0x00, 0x03
764        // - 2 bytes field_a: 1, 2 (NO prefix)
765        // - 3 bytes field_b: 10, 11, 12 (NO prefix)
766        // Total: 13 bytes
767        assert_eq!(buf.len(), 13);
768        assert_eq!(buf[0..4], [0, 0, 0, 2]); // len_a
769        assert_eq!(buf[4..8], [0, 0, 0, 3]); // len_b
770        assert_eq!(buf[8..10], [1, 2]); // field_a
771        assert_eq!(buf[10..13], [10, 11, 12]); // field_b
772    }
773
774    #[test]
775    fn test_fixed_length_with_expression_binary() {
776        // Verify fixed-length with arithmetic expression works correctly
777        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
778        pub struct FixedWithExpr {
779            pub base: u32,
780            pub multiplier: u32,
781            #[codec(fixed_length = base * multiplier)]
782            pub data: Vec<u8>,
783        }
784
785        let original = FixedWithExpr {
786            base: 3,
787            multiplier: 2,
788            data: vec![1, 2, 3, 4, 5, 6],
789        };
790
791        let mut buf = Vec::new();
792        original.encode(&mut buf);
793
794        // Expected format:
795        // - 4 bytes base: 0x00, 0x00, 0x00, 0x03
796        // - 4 bytes multiplier: 0x00, 0x00, 0x00, 0x02
797        // - 6 bytes data: 1, 2, 3, 4, 5, 6 (NO prefix)
798        // Total: 14 bytes
799        assert_eq!(buf.len(), 14);
800
801        // Verify roundtrip
802        let mut slice = buf.as_slice();
803        let decoded = FixedWithExpr::decode(&mut slice).unwrap();
804        assert_eq!(decoded, original);
805        assert_eq!(slice.len(), 0);
806    }
807
808    #[test]
809    fn test_fixed_length_vec_u8_large_buffer() {
810        // Verify optimization for Vec<u8> with large buffers
811        // This would be slow if we called u8::decode() 32000 times
812        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
813        pub struct LargeFixedBuffer {
814            pub size: u32,
815            #[codec(fixed_length = size)]
816            pub data: Vec<u8>,
817        }
818
819        // Create a large buffer of 10000 bytes
820        let large_data = vec![42u8; 10000];
821        let original = LargeFixedBuffer {
822            size: 10000,
823            data: large_data.clone(),
824        };
825
826        let mut buf = Vec::new();
827        original.encode(&mut buf);
828
829        // Buffer should be: 4 bytes (u32) + 10000 bytes (data, no prefix)
830        assert_eq!(buf.len(), 10004);
831
832        // Decode should be fast (not calling decode 10000 times)
833        let mut slice = buf.as_slice();
834        let decoded = LargeFixedBuffer::decode(&mut slice).unwrap();
835
836        assert_eq!(decoded.size, 10000);
837        assert_eq!(decoded.data, large_data);
838        assert_eq!(slice.len(), 0);
839    }
840
841    #[test]
842    fn test_fixed_length_vec_u8_optimized_vs_generic() {
843        // Verify Vec<u8> uses optimized path and generic types use generic path
844        #[derive(voidmc_codec_macros::Encode, voidmc_codec_macros::Decode, PartialEq, Debug)]
845        pub struct MixedVectors {
846            pub len: u32,
847            #[codec(fixed_length = len)]
848            pub bytes: Vec<u8>,
849            #[codec(fixed_length = len)]
850            pub numbers: Vec<u16>,
851        }
852
853        let original = MixedVectors {
854            len: 5,
855            bytes: vec![1, 2, 3, 4, 5],
856            numbers: vec![100, 101, 102, 103, 104],
857        };
858
859        let mut buf = Vec::new();
860        original.encode(&mut buf);
861
862        // bytes: 5 bytes (optimized path, no individual decode calls)
863        // numbers: 5 * 2 = 10 bytes (generic path with u16::decode calls)
864        // len: 4 bytes (u32)
865        // Total: 4 + 5 + 10 = 19 bytes
866        assert_eq!(buf.len(), 19);
867
868        let mut slice = buf.as_slice();
869        let decoded = MixedVectors::decode(&mut slice).unwrap();
870
871        assert_eq!(decoded, original);
872        assert_eq!(slice.len(), 0);
873    }
874
875    // Tests for #[codec(remaining)] attribute
876    #[derive(Encode, Decode, Debug, PartialEq)]
877    struct SimpleRemaining {
878        id: u32,
879        #[codec(remaining)]
880        data: Vec<u8>,
881    }
882
883    #[test]
884    fn test_remaining_basic() {
885        let original = SimpleRemaining {
886            id: 42,
887            data: vec![1, 2, 3, 4, 5],
888        };
889
890        let mut buf = Vec::new();
891        original.encode(&mut buf);
892
893        // Verify binary format: 4 bytes for id + 5 bytes for data (no length prefix)
894        assert_eq!(buf.len(), 9);
895
896        let mut slice = buf.as_slice();
897        let decoded = SimpleRemaining::decode(&mut slice).unwrap();
898
899        assert_eq!(decoded, original);
900        assert_eq!(slice.len(), 0); // All bytes consumed
901    }
902
903    #[test]
904    fn test_remaining_empty() {
905        let original = SimpleRemaining {
906            id: 100,
907            data: vec![],
908        };
909
910        let mut buf = Vec::new();
911        original.encode(&mut buf);
912
913        // Only 4 bytes for id, empty data
914        assert_eq!(buf.len(), 4);
915
916        let mut slice = buf.as_slice();
917        let decoded = SimpleRemaining::decode(&mut slice).unwrap();
918
919        assert_eq!(decoded, original);
920        assert_eq!(slice.len(), 0);
921    }
922
923    #[test]
924    fn test_remaining_large_data() {
925        let data = vec![42u8; 10000];
926        let original = SimpleRemaining {
927            id: 999,
928            data: data.clone(),
929        };
930
931        let mut buf = Vec::new();
932        original.encode(&mut buf);
933
934        // 4 bytes for id + 10000 bytes for data (no length prefix)
935        assert_eq!(buf.len(), 10004);
936
937        let mut slice = buf.as_slice();
938        let decoded = SimpleRemaining::decode(&mut slice).unwrap();
939
940        assert_eq!(decoded, original);
941        assert_eq!(slice.len(), 0);
942    }
943
944    #[test]
945    fn test_remaining_consumes_all_bytes() {
946        let original = SimpleRemaining {
947            id: 1,
948            data: vec![10, 20, 30],
949        };
950
951        let mut buf = Vec::new();
952        original.encode(&mut buf);
953
954        // Add some extra garbage after encoding
955        buf.push(255);
956        buf.push(254);
957        buf.push(253);
958
959        let mut slice = buf.as_slice();
960        let decoded = SimpleRemaining::decode(&mut slice).unwrap();
961
962        // After decode, remaining should be empty (remaining attribute consumed garbage too)
963        assert_eq!(slice.len(), 0);
964
965        // The decoded data field should include the garbage
966        assert_eq!(decoded.data, vec![10, 20, 30, 255, 254, 253]);
967    }
968
969    #[test]
970    fn test_remaining_no_length_prefix() {
971        let original = SimpleRemaining {
972            id: 5,
973            data: vec![100, 101, 102],
974        };
975
976        let mut buf = Vec::new();
977        original.encode(&mut buf);
978
979        // Manual verification: no varint32 length prefix before data
980        // id (u32) = 4 bytes (big-endian): [0, 0, 0, 5]
981        // data (3 bytes, no prefix): [100, 101, 102]
982        // Total: 7 bytes
983        assert_eq!(buf[0..4], [0, 0, 0, 5]);
984        assert_eq!(buf[4..7], [100, 101, 102]);
985        assert_eq!(buf.len(), 7);
986    }
987
988    #[test]
989    fn test_remaining_with_string_field() {
990        #[derive(Encode, Decode, Debug, PartialEq)]
991        struct MessageWithData {
992            channel: String,
993            #[codec(remaining)]
994            payload: Vec<u8>,
995        }
996
997        let original = MessageWithData {
998            channel: "test_channel".to_string(),
999            payload: vec![1, 2, 3, 4],
1000        };
1001
1002        let mut buf = Vec::new();
1003        original.encode(&mut buf);
1004
1005        let mut slice = buf.as_slice();
1006        let decoded = MessageWithData::decode(&mut slice).unwrap();
1007
1008        assert_eq!(decoded, original);
1009        assert_eq!(slice.len(), 0);
1010    }
1011
1012    #[test]
1013    fn test_remaining_multiple_u8_fields() {
1014        #[derive(Encode, Decode, Debug, PartialEq)]
1015        struct MultiField {
1016            byte1: u8,
1017            byte2: u8,
1018            #[codec(remaining)]
1019            rest: Vec<u8>,
1020        }
1021
1022        let original = MultiField {
1023            byte1: 10,
1024            byte2: 20,
1025            rest: vec![30, 40, 50, 60],
1026        };
1027
1028        let mut buf = Vec::new();
1029        original.encode(&mut buf);
1030
1031        // 1 + 1 + 4 = 6 bytes (no length prefix on rest)
1032        assert_eq!(buf.len(), 6);
1033
1034        let mut slice = buf.as_slice();
1035        let decoded = MultiField::decode(&mut slice).unwrap();
1036
1037        assert_eq!(decoded, original);
1038        assert_eq!(slice.len(), 0);
1039    }
1040
1041    #[test]
1042    fn test_remaining_preserves_all_bytes() {
1043        let data = b"Plugin message with binary \x00\x01\x02\x03 data".to_vec();
1044        let original = SimpleRemaining {
1045            id: 777,
1046            data: data.clone(),
1047        };
1048
1049        let mut buf = Vec::new();
1050        original.encode(&mut buf);
1051
1052        let mut slice = buf.as_slice();
1053        let decoded = SimpleRemaining::decode(&mut slice).unwrap();
1054
1055        // Verify exact byte preservation (including null bytes)
1056        assert_eq!(decoded.data, data);
1057        assert_eq!(slice.len(), 0);
1058    }
1059
1060    #[test]
1061    fn test_remaining_roundtrip_multiple_times() {
1062        let test_cases = vec![
1063            vec![],
1064            vec![1],
1065            vec![1, 2, 3, 4, 5],
1066            vec![255, 254, 253],
1067            vec![0; 100],
1068        ];
1069
1070        for data in test_cases {
1071            let original = SimpleRemaining {
1072                id: 42,
1073                data: data.clone(),
1074            };
1075
1076            let mut buf = Vec::new();
1077            original.encode(&mut buf);
1078
1079            let mut slice = buf.as_slice();
1080            let decoded = SimpleRemaining::decode(&mut slice).unwrap();
1081
1082            assert_eq!(decoded, original, "Roundtrip failed for data: {:?}", data);
1083            assert_eq!(slice.len(), 0);
1084
1085            // Re-encode and verify same result
1086            let mut buf2 = Vec::new();
1087            decoded.encode(&mut buf2);
1088            assert_eq!(buf, buf2, "Encode changed for data: {:?}", data);
1089        }
1090    }
1091
1092    #[test]
1093    fn test_remaining_vs_fixed_length_size_difference() {
1094        // fixed_length requires length to be pre-known and doesn't store it
1095        // remaining consumes all remaining bytes
1096        // For fixed_length, we need to encode both the length and the data
1097        // For remaining, we only encode the data
1098
1099        #[derive(Encode, Decode, Debug, PartialEq)]
1100        struct WithFixedKnownLen {
1101            #[codec(fixed_length = 4)]
1102            data: Vec<u8>,
1103        }
1104
1105        #[derive(Encode, Decode, Debug, PartialEq)]
1106        struct WithRemaining {
1107            #[codec(remaining)]
1108            data: Vec<u8>,
1109        }
1110
1111        let data = vec![1, 2, 3, 4];
1112
1113        let fixed = WithFixedKnownLen { data: data.clone() };
1114
1115        let remaining = WithRemaining { data: data.clone() };
1116
1117        let mut buf_fixed = Vec::new();
1118        fixed.encode(&mut buf_fixed);
1119
1120        let mut buf_remaining = Vec::new();
1121        remaining.encode(&mut buf_remaining);
1122
1123        // Both should be same size (4 bytes) since fixed_length = 4 means no prefix
1124        // and remaining also has no prefix
1125        assert_eq!(buf_fixed.len(), buf_remaining.len());
1126        assert_eq!(buf_fixed, buf_remaining);
1127    }
1128}