1use std::{char, fmt::Display, str};
19
20use serde::{
21 Serialize,
22 de::{
23 self, DeserializeOwned, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess,
24 SeqAccess, VariantAccess, Visitor,
25 },
26 ser::{
27 self, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
28 SerializeTupleStruct, SerializeTupleVariant,
29 },
30};
31use thiserror::Error;
32
33const MAGIC: [u8; 4] = *b"NESC";
34const VERSION: u8 = 1;
35const HEADER_LEN: usize = MAGIC.len() + 1;
36const MAX_COLLECTION_COUNT: usize = 1_048_576;
37
38pub fn encode_to_vec<T: Serialize>(value: &T) -> Result<Vec<u8>, CodecError> {
48 let mut encoder = Encoder { out: Vec::new() };
49 encoder.out.extend_from_slice(&MAGIC);
50 encoder.out.push(VERSION);
51 value.serialize(&mut encoder)?;
52 Ok(encoder.out)
53}
54
55pub fn decode_from_slice<T: DeserializeOwned>(bytes: &[u8]) -> Result<T, CodecError> {
65 let mut decoder = Decoder {
66 input: bytes,
67 pos: 0,
68 };
69 decoder.read_header()?;
70 let value = T::deserialize(&mut decoder)?;
71 if decoder.pos != decoder.input.len() {
72 return Err(CodecError::TrailingBytes(decoder.input.len() - decoder.pos));
73 }
74 Ok(value)
75}
76
77#[derive(Debug, Error)]
79#[non_exhaustive]
80pub enum CodecError {
81 #[error("unexpected end of codec input: needed {needed} more byte(s)")]
83 UnexpectedEof {
84 needed: usize,
86 },
87 #[error("bad codec magic: input is not a nautilus event-store codec frame")]
89 BadMagic,
90 #[error("unsupported codec version: {0}")]
92 UnsupportedVersion(u8),
93 #[error("encoded length {claimed} exceeds remaining input {remaining}")]
95 LengthOverflow {
96 claimed: u64,
103 remaining: usize,
105 },
106 #[error("encoded collection count {claimed} exceeds maximum {max}")]
108 CountOverflow {
109 claimed: u64,
111 max: usize,
113 },
114 #[error("invalid utf-8 in encoded string")]
116 InvalidUtf8,
117 #[error("invalid bool discriminant: {0:#04x}")]
119 InvalidBool(u8),
120 #[error("invalid option discriminant: {0:#04x}")]
122 InvalidOption(u8),
123 #[error("invalid char scalar value: {0:#010x}")]
125 InvalidChar(u32),
126 #[error("unknown enum variant index: {0}")]
128 UnknownVariant(u32),
129 #[error("sequence length was not provided by the serializer")]
131 MissingLen,
132 #[error("{0} unconsumed trailing byte(s) after decode")]
134 TrailingBytes(usize),
135 #[error("self-describing deserialization is not supported by this format")]
137 SelfDescribing,
138 #[error("{0}")]
140 Message(String),
141}
142
143impl ser::Error for CodecError {
144 fn custom<T: Display>(msg: T) -> Self {
145 Self::Message(msg.to_string())
146 }
147}
148
149impl de::Error for CodecError {
150 fn custom<T: Display>(msg: T) -> Self {
151 Self::Message(msg.to_string())
152 }
153}
154
155#[derive(Debug)]
156struct Encoder {
157 out: Vec<u8>,
158}
159
160impl Encoder {
161 fn write_len(&mut self, len: usize) {
162 self.out.extend_from_slice(&(len as u64).to_le_bytes());
163 }
164
165 fn write_count(&mut self, count: usize) -> Result<(), CodecError> {
166 if count > MAX_COLLECTION_COUNT {
167 return Err(CodecError::CountOverflow {
168 claimed: count as u64,
169 max: MAX_COLLECTION_COUNT,
170 });
171 }
172
173 self.write_len(count);
174 Ok(())
175 }
176
177 fn write_variant(&mut self, variant_index: u32) {
178 self.out.extend_from_slice(&variant_index.to_le_bytes());
179 }
180}
181
182impl ser::Serializer for &mut Encoder {
183 type Ok = ();
184 type Error = CodecError;
185 type SerializeSeq = Self;
186 type SerializeTuple = Self;
187 type SerializeTupleStruct = Self;
188 type SerializeTupleVariant = Self;
189 type SerializeMap = Self;
190 type SerializeStruct = Self;
191 type SerializeStructVariant = Self;
192
193 fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
194 self.out.push(u8::from(v));
195 Ok(())
196 }
197
198 fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
199 self.out.extend_from_slice(&v.to_le_bytes());
200 Ok(())
201 }
202
203 fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
204 self.out.extend_from_slice(&v.to_le_bytes());
205 Ok(())
206 }
207
208 fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
209 self.out.extend_from_slice(&v.to_le_bytes());
210 Ok(())
211 }
212
213 fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
214 self.out.extend_from_slice(&v.to_le_bytes());
215 Ok(())
216 }
217
218 fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
219 self.out.push(v);
220 Ok(())
221 }
222
223 fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
224 self.out.extend_from_slice(&v.to_le_bytes());
225 Ok(())
226 }
227
228 fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
229 self.out.extend_from_slice(&v.to_le_bytes());
230 Ok(())
231 }
232
233 fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
234 self.out.extend_from_slice(&v.to_le_bytes());
235 Ok(())
236 }
237
238 fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
239 self.out.extend_from_slice(&v.to_le_bytes());
240 Ok(())
241 }
242
243 fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
244 self.out.extend_from_slice(&v.to_le_bytes());
245 Ok(())
246 }
247
248 fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error> {
249 self.out.extend_from_slice(&(v as u32).to_le_bytes());
250 Ok(())
251 }
252
253 fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
254 self.write_len(v.len());
255 self.out.extend_from_slice(v.as_bytes());
256 Ok(())
257 }
258
259 fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> {
260 self.write_len(v.len());
261 self.out.extend_from_slice(v);
262 Ok(())
263 }
264
265 fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
266 self.out.push(0);
267 Ok(())
268 }
269
270 fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
271 where
272 T: ?Sized + Serialize,
273 {
274 self.out.push(1);
275 value.serialize(self)
276 }
277
278 fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
279 Ok(())
280 }
281
282 fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
283 Ok(())
284 }
285
286 fn serialize_unit_variant(
287 self,
288 _name: &'static str,
289 variant_index: u32,
290 _variant: &'static str,
291 ) -> Result<Self::Ok, Self::Error> {
292 self.write_variant(variant_index);
293 Ok(())
294 }
295
296 fn serialize_newtype_struct<T>(
297 self,
298 _name: &'static str,
299 value: &T,
300 ) -> Result<Self::Ok, Self::Error>
301 where
302 T: ?Sized + Serialize,
303 {
304 value.serialize(self)
305 }
306
307 fn serialize_newtype_variant<T>(
308 self,
309 _name: &'static str,
310 variant_index: u32,
311 _variant: &'static str,
312 value: &T,
313 ) -> Result<Self::Ok, Self::Error>
314 where
315 T: ?Sized + Serialize,
316 {
317 self.write_variant(variant_index);
318 value.serialize(self)
319 }
320
321 fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
322 let len = len.ok_or(CodecError::MissingLen)?;
323 self.write_count(len)?;
324 Ok(self)
325 }
326
327 fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
328 Ok(self)
329 }
330
331 fn serialize_tuple_struct(
332 self,
333 _name: &'static str,
334 _len: usize,
335 ) -> Result<Self::SerializeTupleStruct, Self::Error> {
336 Ok(self)
337 }
338
339 fn serialize_tuple_variant(
340 self,
341 _name: &'static str,
342 variant_index: u32,
343 _variant: &'static str,
344 _len: usize,
345 ) -> Result<Self::SerializeTupleVariant, Self::Error> {
346 self.write_variant(variant_index);
347 Ok(self)
348 }
349
350 fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
351 let len = len.ok_or(CodecError::MissingLen)?;
352 self.write_count(len)?;
353 Ok(self)
354 }
355
356 fn serialize_struct(
357 self,
358 _name: &'static str,
359 _len: usize,
360 ) -> Result<Self::SerializeStruct, Self::Error> {
361 Ok(self)
362 }
363
364 fn serialize_struct_variant(
365 self,
366 _name: &'static str,
367 variant_index: u32,
368 _variant: &'static str,
369 _len: usize,
370 ) -> Result<Self::SerializeStructVariant, Self::Error> {
371 self.write_variant(variant_index);
372 Ok(self)
373 }
374
375 fn is_human_readable(&self) -> bool {
376 false
377 }
378}
379
380impl SerializeSeq for &mut Encoder {
381 type Ok = ();
382 type Error = CodecError;
383
384 fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
385 where
386 T: ?Sized + Serialize,
387 {
388 value.serialize(&mut **self)
389 }
390
391 fn end(self) -> Result<Self::Ok, Self::Error> {
392 Ok(())
393 }
394}
395
396impl SerializeTuple for &mut Encoder {
397 type Ok = ();
398 type Error = CodecError;
399
400 fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
401 where
402 T: ?Sized + Serialize,
403 {
404 value.serialize(&mut **self)
405 }
406
407 fn end(self) -> Result<Self::Ok, Self::Error> {
408 Ok(())
409 }
410}
411
412impl SerializeTupleStruct for &mut Encoder {
413 type Ok = ();
414 type Error = CodecError;
415
416 fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
417 where
418 T: ?Sized + Serialize,
419 {
420 value.serialize(&mut **self)
421 }
422
423 fn end(self) -> Result<Self::Ok, Self::Error> {
424 Ok(())
425 }
426}
427
428impl SerializeTupleVariant for &mut Encoder {
429 type Ok = ();
430 type Error = CodecError;
431
432 fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
433 where
434 T: ?Sized + Serialize,
435 {
436 value.serialize(&mut **self)
437 }
438
439 fn end(self) -> Result<Self::Ok, Self::Error> {
440 Ok(())
441 }
442}
443
444impl SerializeMap for &mut Encoder {
445 type Ok = ();
446 type Error = CodecError;
447
448 fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
449 where
450 T: ?Sized + Serialize,
451 {
452 key.serialize(&mut **self)
453 }
454
455 fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
456 where
457 T: ?Sized + Serialize,
458 {
459 value.serialize(&mut **self)
460 }
461
462 fn end(self) -> Result<Self::Ok, Self::Error> {
463 Ok(())
464 }
465}
466
467impl SerializeStruct for &mut Encoder {
468 type Ok = ();
469 type Error = CodecError;
470
471 fn serialize_field<T>(&mut self, _key: &'static str, value: &T) -> Result<(), Self::Error>
472 where
473 T: ?Sized + Serialize,
474 {
475 value.serialize(&mut **self)
476 }
477
478 fn end(self) -> Result<Self::Ok, Self::Error> {
479 Ok(())
480 }
481}
482
483impl SerializeStructVariant for &mut Encoder {
484 type Ok = ();
485 type Error = CodecError;
486
487 fn serialize_field<T>(&mut self, _key: &'static str, value: &T) -> Result<(), Self::Error>
488 where
489 T: ?Sized + Serialize,
490 {
491 value.serialize(&mut **self)
492 }
493
494 fn end(self) -> Result<Self::Ok, Self::Error> {
495 Ok(())
496 }
497}
498
499#[derive(Debug)]
500struct Decoder<'de> {
501 input: &'de [u8],
502 pos: usize,
503}
504
505impl<'de> Decoder<'de> {
506 fn read_header(&mut self) -> Result<(), CodecError> {
507 if self.input.len() < HEADER_LEN {
508 return Err(CodecError::UnexpectedEof { needed: HEADER_LEN });
509 }
510
511 let magic = self.take(MAGIC.len())?;
512 if magic != MAGIC {
513 return Err(CodecError::BadMagic);
514 }
515
516 let version = self.take(1)?[0];
517 if version != VERSION {
518 return Err(CodecError::UnsupportedVersion(version));
519 }
520
521 Ok(())
522 }
523
524 fn remaining(&self) -> usize {
525 self.input.len() - self.pos
526 }
527
528 fn take(&mut self, n: usize) -> Result<&'de [u8], CodecError> {
529 let end = self
530 .pos
531 .checked_add(n)
532 .ok_or(CodecError::UnexpectedEof { needed: n })?;
533 let slice = self
534 .input
535 .get(self.pos..end)
536 .ok_or(CodecError::UnexpectedEof { needed: n })?;
537 self.pos = end;
538 Ok(slice)
539 }
540
541 fn read_byte_len(&mut self) -> Result<usize, CodecError> {
542 let raw = self.read_u64()?;
543 let remaining = self.remaining();
544 match usize::try_from(raw) {
548 Ok(claimed) if claimed <= remaining => Ok(claimed),
549 _ => Err(CodecError::LengthOverflow {
550 claimed: raw,
551 remaining,
552 }),
553 }
554 }
555
556 fn read_count(&mut self) -> Result<usize, CodecError> {
557 let raw = self.read_u64()?;
558 match usize::try_from(raw) {
559 Ok(count) if count <= MAX_COLLECTION_COUNT => Ok(count),
560 _ => Err(CodecError::CountOverflow {
561 claimed: raw,
562 max: MAX_COLLECTION_COUNT,
563 }),
564 }
565 }
566
567 fn read_u16(&mut self) -> Result<u16, CodecError> {
568 let bytes: [u8; 2] = self
569 .take(2)?
570 .try_into()
571 .expect("take returned the exact requested width");
572 Ok(u16::from_le_bytes(bytes))
573 }
574
575 fn read_u32(&mut self) -> Result<u32, CodecError> {
576 let bytes: [u8; 4] = self
577 .take(4)?
578 .try_into()
579 .expect("take returned the exact requested width");
580 Ok(u32::from_le_bytes(bytes))
581 }
582
583 fn read_u64(&mut self) -> Result<u64, CodecError> {
584 let bytes: [u8; 8] = self
585 .take(8)?
586 .try_into()
587 .expect("take returned the exact requested width");
588 Ok(u64::from_le_bytes(bytes))
589 }
590}
591
592macro_rules! deserialize_integer {
593 ($method:ident, $visit:ident, $ty:ty, $width:literal) => {
594 fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
595 where
596 V: Visitor<'de>,
597 {
598 let bytes: [u8; $width] = self
599 .take($width)?
600 .try_into()
601 .expect("take returned the exact requested width");
602 visitor.$visit(<$ty>::from_le_bytes(bytes))
603 }
604 };
605}
606
607impl<'de> de::Deserializer<'de> for &mut Decoder<'de> {
608 type Error = CodecError;
609
610 fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
611 where
612 V: Visitor<'de>,
613 {
614 Err(CodecError::SelfDescribing)
615 }
616
617 fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
618 where
619 V: Visitor<'de>,
620 {
621 match self.take(1)?[0] {
622 0 => visitor.visit_bool(false),
623 1 => visitor.visit_bool(true),
624 other => Err(CodecError::InvalidBool(other)),
625 }
626 }
627
628 fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
629 where
630 V: Visitor<'de>,
631 {
632 let bytes: [u8; 1] = self
633 .take(1)?
634 .try_into()
635 .expect("take returned the exact requested width");
636 visitor.visit_i8(i8::from_le_bytes(bytes))
637 }
638
639 deserialize_integer!(deserialize_i16, visit_i16, i16, 2);
640 deserialize_integer!(deserialize_i32, visit_i32, i32, 4);
641 deserialize_integer!(deserialize_i64, visit_i64, i64, 8);
642
643 fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
644 where
645 V: Visitor<'de>,
646 {
647 visitor.visit_u8(self.take(1)?[0])
648 }
649
650 fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
651 where
652 V: Visitor<'de>,
653 {
654 visitor.visit_u16(self.read_u16()?)
655 }
656
657 fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
658 where
659 V: Visitor<'de>,
660 {
661 visitor.visit_u32(self.read_u32()?)
662 }
663
664 fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
665 where
666 V: Visitor<'de>,
667 {
668 visitor.visit_u64(self.read_u64()?)
669 }
670
671 fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
672 where
673 V: Visitor<'de>,
674 {
675 let bytes: [u8; 4] = self
676 .take(4)?
677 .try_into()
678 .expect("take returned the exact requested width");
679 visitor.visit_f32(f32::from_le_bytes(bytes))
680 }
681
682 fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
683 where
684 V: Visitor<'de>,
685 {
686 let bytes: [u8; 8] = self
687 .take(8)?
688 .try_into()
689 .expect("take returned the exact requested width");
690 visitor.visit_f64(f64::from_le_bytes(bytes))
691 }
692
693 fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
694 where
695 V: Visitor<'de>,
696 {
697 let raw = self.read_u32()?;
698 let value = char::from_u32(raw).ok_or(CodecError::InvalidChar(raw))?;
699 visitor.visit_char(value)
700 }
701
702 fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
703 where
704 V: Visitor<'de>,
705 {
706 let len = self.read_byte_len()?;
707 let bytes = self.take(len)?;
708 let value = str::from_utf8(bytes).map_err(|_| CodecError::InvalidUtf8)?;
709 visitor.visit_borrowed_str(value)
710 }
711
712 fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
713 where
714 V: Visitor<'de>,
715 {
716 self.deserialize_str(visitor)
717 }
718
719 fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
720 where
721 V: Visitor<'de>,
722 {
723 let len = self.read_byte_len()?;
724 let bytes = self.take(len)?;
725 visitor.visit_borrowed_bytes(bytes)
726 }
727
728 fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
729 where
730 V: Visitor<'de>,
731 {
732 self.deserialize_bytes(visitor)
733 }
734
735 fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
736 where
737 V: Visitor<'de>,
738 {
739 match self.take(1)?[0] {
740 0 => visitor.visit_none(),
741 1 => visitor.visit_some(self),
742 other => Err(CodecError::InvalidOption(other)),
743 }
744 }
745
746 fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
747 where
748 V: Visitor<'de>,
749 {
750 visitor.visit_unit()
751 }
752
753 fn deserialize_unit_struct<V>(
754 self,
755 _name: &'static str,
756 visitor: V,
757 ) -> Result<V::Value, Self::Error>
758 where
759 V: Visitor<'de>,
760 {
761 visitor.visit_unit()
762 }
763
764 fn deserialize_newtype_struct<V>(
765 self,
766 _name: &'static str,
767 visitor: V,
768 ) -> Result<V::Value, Self::Error>
769 where
770 V: Visitor<'de>,
771 {
772 visitor.visit_newtype_struct(self)
773 }
774
775 fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
776 where
777 V: Visitor<'de>,
778 {
779 let remaining = self.read_count()?;
780 visitor.visit_seq(SeqReader {
781 dec: self,
782 remaining,
783 })
784 }
785
786 fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
787 where
788 V: Visitor<'de>,
789 {
790 visitor.visit_seq(SeqReader {
791 dec: self,
792 remaining: len,
793 })
794 }
795
796 fn deserialize_tuple_struct<V>(
797 self,
798 _name: &'static str,
799 len: usize,
800 visitor: V,
801 ) -> Result<V::Value, Self::Error>
802 where
803 V: Visitor<'de>,
804 {
805 self.deserialize_tuple(len, visitor)
806 }
807
808 fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
809 where
810 V: Visitor<'de>,
811 {
812 let remaining = self.read_count()?;
813 visitor.visit_map(MapReader {
814 dec: self,
815 remaining,
816 })
817 }
818
819 fn deserialize_struct<V>(
820 self,
821 _name: &'static str,
822 fields: &'static [&'static str],
823 visitor: V,
824 ) -> Result<V::Value, Self::Error>
825 where
826 V: Visitor<'de>,
827 {
828 visitor.visit_seq(SeqReader {
829 dec: self,
830 remaining: fields.len(),
831 })
832 }
833
834 fn deserialize_enum<V>(
835 self,
836 _name: &'static str,
837 variants: &'static [&'static str],
838 visitor: V,
839 ) -> Result<V::Value, Self::Error>
840 where
841 V: Visitor<'de>,
842 {
843 let index = self.read_u32()?;
844 if index as usize >= variants.len() {
845 return Err(CodecError::UnknownVariant(index));
846 }
847 visitor.visit_enum(EnumReader { dec: self, index })
848 }
849
850 fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
851 where
852 V: Visitor<'de>,
853 {
854 self.deserialize_u32(visitor)
855 }
856
857 fn deserialize_ignored_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
858 where
859 V: Visitor<'de>,
860 {
861 Err(CodecError::SelfDescribing)
862 }
863
864 fn is_human_readable(&self) -> bool {
865 false
866 }
867}
868
869#[derive(Debug)]
870struct SeqReader<'a, 'de> {
871 dec: &'a mut Decoder<'de>,
872 remaining: usize,
873}
874
875impl<'de> SeqAccess<'de> for SeqReader<'_, 'de> {
876 type Error = CodecError;
877
878 fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
879 where
880 T: DeserializeSeed<'de>,
881 {
882 if self.remaining == 0 {
883 return Ok(None);
884 }
885
886 self.remaining -= 1;
887 seed.deserialize(&mut *self.dec).map(Some)
888 }
889
890 fn size_hint(&self) -> Option<usize> {
891 Some(self.remaining)
892 }
893}
894
895#[derive(Debug)]
896struct MapReader<'a, 'de> {
897 dec: &'a mut Decoder<'de>,
898 remaining: usize,
899}
900
901impl<'de> MapAccess<'de> for MapReader<'_, 'de> {
902 type Error = CodecError;
903
904 fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
905 where
906 K: DeserializeSeed<'de>,
907 {
908 if self.remaining == 0 {
909 return Ok(None);
910 }
911
912 self.remaining -= 1;
913 seed.deserialize(&mut *self.dec).map(Some)
914 }
915
916 fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
917 where
918 V: DeserializeSeed<'de>,
919 {
920 seed.deserialize(&mut *self.dec)
921 }
922
923 fn size_hint(&self) -> Option<usize> {
924 Some(self.remaining)
925 }
926}
927
928#[derive(Debug)]
929struct EnumReader<'a, 'de> {
930 dec: &'a mut Decoder<'de>,
931 index: u32,
932}
933
934impl<'de> EnumAccess<'de> for EnumReader<'_, 'de> {
935 type Error = CodecError;
936 type Variant = Self;
937
938 fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
939 where
940 V: DeserializeSeed<'de>,
941 {
942 let value = seed.deserialize(self.index.into_deserializer())?;
943 Ok((value, self))
944 }
945}
946
947impl<'de> VariantAccess<'de> for EnumReader<'_, 'de> {
948 type Error = CodecError;
949
950 fn unit_variant(self) -> Result<(), Self::Error> {
951 Ok(())
952 }
953
954 fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
955 where
956 T: DeserializeSeed<'de>,
957 {
958 seed.deserialize(self.dec)
959 }
960
961 fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
962 where
963 V: Visitor<'de>,
964 {
965 visitor.visit_seq(SeqReader {
966 dec: self.dec,
967 remaining: len,
968 })
969 }
970
971 fn struct_variant<V>(
972 self,
973 fields: &'static [&'static str],
974 visitor: V,
975 ) -> Result<V::Value, Self::Error>
976 where
977 V: Visitor<'de>,
978 {
979 visitor.visit_seq(SeqReader {
980 dec: self.dec,
981 remaining: fields.len(),
982 })
983 }
984}
985
986#[cfg(test)]
987mod tests {
988 use std::array;
989
990 use bytes::Bytes;
991 use indexmap::IndexMap;
992 use nautilus_core::{UUID4, UnixNanos};
993 use nautilus_model::data::DataType;
994 use nautilus_system::RegisteredComponents;
995 use proptest::{prelude::*, test_runner::Config as ProptestConfig};
996 use rstest::rstest;
997 use serde::{Deserialize, Serializer};
998 use ustr::Ustr;
999
1000 use super::*;
1001 use crate::{
1002 EventStoreEntry, Headers, RunManifest, RunStatus, SnapshotAnchor,
1003 hash::{EntryHash, compute_entry_hash},
1004 markers::{
1005 DataClass, DataCursorSnapshot, HiFiMarker, MarkerGap, MarkerGapReason, StreamCursor,
1006 StreamDictEntry,
1007 },
1008 };
1009
1010 #[derive(Debug, Serialize, Deserialize)]
1011 struct ScalarProbe {
1012 b: bool,
1013 i8s: [i8; 3],
1014 i16s: [i16; 3],
1015 i32s: [i32; 3],
1016 i64s: [i64; 3],
1017 u16: u16,
1018 f32s: [f32; 3],
1019 f64s: [f64; 3],
1020 ch: char,
1021 }
1022
1023 impl PartialEq for ScalarProbe {
1024 fn eq(&self, other: &Self) -> bool {
1025 self.b == other.b
1026 && self.i8s == other.i8s
1027 && self.i16s == other.i16s
1028 && self.i32s == other.i32s
1029 && self.i64s == other.i64s
1030 && self.u16 == other.u16
1031 && self
1032 .f32s
1033 .iter()
1034 .zip(other.f32s)
1035 .all(|(left, right)| left.to_bits() == right.to_bits())
1036 && self
1037 .f64s
1038 .iter()
1039 .zip(other.f64s)
1040 .all(|(left, right)| left.to_bits() == right.to_bits())
1041 && self.ch == other.ch
1042 }
1043 }
1044
1045 #[derive(Debug, PartialEq, Serialize, Deserialize)]
1046 struct BoolProbe {
1047 b: bool,
1048 }
1049
1050 struct TooManySeq;
1051
1052 impl Serialize for TooManySeq {
1053 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1054 where
1055 S: Serializer,
1056 {
1057 let seq = serializer.serialize_seq(Some(MAX_COLLECTION_COUNT + 1))?;
1058 SerializeSeq::end(seq)
1059 }
1060 }
1061
1062 fn roundtrip<T>(value: &T) -> T
1063 where
1064 T: Serialize + DeserializeOwned,
1065 {
1066 decode_from_slice(&encode_to_vec(value).expect("encode")).expect("decode")
1067 }
1068
1069 fn headers_populated() -> Headers {
1070 Headers {
1071 correlation_id: Some(UUID4::from_bytes([1; 16])),
1072 causation_id: Some(UUID4::from_bytes([2; 16])),
1073 }
1074 }
1075
1076 fn entry(headers: Headers) -> EventStoreEntry {
1077 let topic = "exec.command".into();
1078 let payload_type = Ustr::from("SubmitOrder");
1079 let payload = Bytes::from_static(b"\x01\x02\x03\x04");
1080 let seq = 42;
1081 let ts_init = UnixNanos::from(1_700_000_000_000_000_000);
1082 let ts_publish = UnixNanos::from(1_700_000_000_000_000_001);
1083 let entry_hash = compute_entry_hash(
1084 seq,
1085 ts_init,
1086 ts_publish,
1087 "exec.command",
1088 payload_type.as_str(),
1089 &payload,
1090 &headers,
1091 );
1092
1093 EventStoreEntry::new(
1094 entry_hash,
1095 seq,
1096 headers,
1097 topic,
1098 payload_type,
1099 payload,
1100 ts_init,
1101 ts_publish,
1102 )
1103 }
1104
1105 fn registered_components() -> RegisteredComponents {
1106 let mut components = RegisteredComponents::default();
1107 components
1108 .actors
1109 .insert("actor-1".to_string(), "hash-a".to_string());
1110 components
1111 .strategies
1112 .insert("strategy-1".to_string(), "hash-s".to_string());
1113 components
1114 .algorithms
1115 .insert("algo-1".to_string(), "hash-g".to_string());
1116 components.subscriptions.push("data.quotes".to_string());
1117 components.endpoints.push("exec.command".to_string());
1118 components
1119 }
1120
1121 fn running_manifest() -> RunManifest {
1122 RunManifest {
1123 run_id: "1700000000-abcd1234".to_string(),
1124 parent_run_id: None,
1125 instance_id: "trader-001".to_string(),
1126 binary_hash: "deadbeef".to_string(),
1127 schema_version: 1,
1128 crate_versions: "feedface".to_string(),
1129 feature_flags: Vec::new(),
1130 adapter_versions: IndexMap::new(),
1131 config_hash: "cafebabe".to_string(),
1132 registered_components: RegisteredComponents::default(),
1133 seed: None,
1134 start_ts_init: UnixNanos::from(10),
1135 end_ts_init: None,
1136 high_watermark: 0,
1137 status: RunStatus::Running,
1138 }
1139 }
1140
1141 fn sealed_manifest() -> RunManifest {
1142 let mut adapter_versions = IndexMap::new();
1143 adapter_versions.insert("binance".to_string(), "1.2.3".to_string());
1144 adapter_versions.insert("okx".to_string(), "2.3.4".to_string());
1145
1146 RunManifest {
1147 run_id: "1700000010-cafe1234".to_string(),
1148 parent_run_id: Some("1700000000-abcd1234".to_string()),
1149 instance_id: "trader-001".to_string(),
1150 binary_hash: "deadbeef".to_string(),
1151 schema_version: 2,
1152 crate_versions: "feedface".to_string(),
1153 feature_flags: vec!["live".to_string(), "persistence".to_string()],
1154 adapter_versions,
1155 config_hash: "cafebabe".to_string(),
1156 registered_components: registered_components(),
1157 seed: Some(7),
1158 start_ts_init: UnixNanos::from(10),
1159 end_ts_init: Some(UnixNanos::from(20)),
1160 high_watermark: 99,
1161 status: RunStatus::Ended,
1162 }
1163 }
1164
1165 fn snapshot_with_cursors() -> DataCursorSnapshot {
1166 DataCursorSnapshot {
1167 marker_seq: 7,
1168 event_seq_before: 42,
1169 ts_init: UnixNanos::from(100),
1170 advanced: vec![
1171 StreamCursor {
1172 slot: 1,
1173 ts_init_hi: UnixNanos::from(101),
1174 count: 10,
1175 },
1176 StreamCursor {
1177 slot: 2,
1178 ts_init_hi: UnixNanos::from(102),
1179 count: 11,
1180 },
1181 ],
1182 }
1183 }
1184
1185 fn hifi_marker() -> HiFiMarker {
1186 HiFiMarker {
1187 marker_seq: 1,
1188 event_seq_before: 42,
1189 slot: 3,
1190 ts_event: UnixNanos::from(1000),
1191 ts_init: UnixNanos::from(1001),
1192 same_ts_ordinal: 2,
1193 record_fingerprint: array::from_fn(|idx| {
1194 u8::try_from(idx).expect("fingerprint index is in 0..32")
1195 }),
1196 }
1197 }
1198
1199 #[rstest]
1200 #[case::empty(Headers::empty())]
1201 #[case::populated(headers_populated())]
1202 fn roundtrip_event_store_entry(#[case] headers: Headers) {
1203 let decoded = roundtrip(&entry(headers));
1204
1205 assert_eq!(decoded.recompute_hash(), decoded.entry_hash);
1206 }
1207
1208 #[rstest]
1209 #[case::running(running_manifest())]
1210 #[case::sealed(sealed_manifest())]
1211 fn roundtrip_run_manifest(#[case] manifest: RunManifest) {
1212 assert_eq!(roundtrip(&manifest), manifest);
1213 }
1214
1215 #[rstest]
1216 fn roundtrip_registered_components() {
1217 let components = registered_components();
1218
1219 assert_eq!(roundtrip(&components), components);
1220 }
1221
1222 #[rstest]
1223 fn roundtrip_snapshot_anchor() {
1224 let anchor = SnapshotAnchor::new(10, "cache://run/10", "blake3:abcd");
1225
1226 assert_eq!(roundtrip(&anchor), anchor);
1227 }
1228
1229 #[rstest]
1230 #[case::advanced(snapshot_with_cursors())]
1231 #[case::empty(DataCursorSnapshot {
1232 marker_seq: 8,
1233 event_seq_before: 43,
1234 ts_init: UnixNanos::from(101),
1235 advanced: Vec::new(),
1236 })]
1237 fn roundtrip_data_cursor_snapshot(#[case] snapshot: DataCursorSnapshot) {
1238 assert_eq!(roundtrip(&snapshot), snapshot);
1239 }
1240
1241 #[rstest]
1242 fn roundtrip_hifi_marker() {
1243 let marker = hifi_marker();
1244
1245 assert_eq!(roundtrip(&marker), marker);
1246 }
1247
1248 #[rstest]
1249 #[case(MarkerGapReason::Overflow)]
1250 #[case(MarkerGapReason::WriterClosed)]
1251 fn roundtrip_marker_gap(#[case] reason: MarkerGapReason) {
1252 let gap = MarkerGap {
1253 from_marker_seq: 1,
1254 to_marker_seq: 2,
1255 reason,
1256 };
1257
1258 assert_eq!(roundtrip(&gap), gap);
1259 }
1260
1261 #[rstest]
1262 fn roundtrip_stream_dict_entry() {
1263 let entry = StreamDictEntry {
1264 slot: 3,
1265 data_cls: DataClass::Quote,
1266 identifier: "ETHUSDT.BINANCE".to_string(),
1267 };
1268
1269 assert_eq!(roundtrip(&entry), entry);
1270 }
1271
1272 #[rstest]
1273 #[case(RunStatus::Running)]
1274 #[case(RunStatus::Ended)]
1275 #[case(RunStatus::CrashedRecovered)]
1276 #[case(RunStatus::Quarantined)]
1277 fn roundtrip_run_status_all_variants(#[case] status: RunStatus) {
1278 assert_eq!(roundtrip(&status), status);
1279 }
1280
1281 #[rstest]
1282 #[case(DataClass::BookDeltas)]
1283 #[case(DataClass::BookDepth10)]
1284 #[case(DataClass::Quote)]
1285 #[case(DataClass::Trade)]
1286 #[case(DataClass::Bar)]
1287 fn roundtrip_data_class_all_variants(#[case] data_class: DataClass) {
1288 assert_eq!(roundtrip(&data_class), data_class);
1289 }
1290
1291 #[rstest]
1292 #[case(MarkerGapReason::Overflow)]
1293 #[case(MarkerGapReason::WriterClosed)]
1294 fn roundtrip_marker_gap_reason_all_variants(#[case] reason: MarkerGapReason) {
1295 assert_eq!(roundtrip(&reason), reason);
1296 }
1297
1298 #[rstest]
1299 #[case::false_value(false)]
1300 #[case::true_value(true)]
1301 fn roundtrip_scalars(#[case] value: bool) {
1302 let probe = ScalarProbe {
1303 b: value,
1304 i8s: [i8::MIN, -1, i8::MAX],
1305 i16s: [i16::MIN, -2, i16::MAX],
1306 i32s: [i32::MIN, -3, i32::MAX],
1307 i64s: [i64::MIN, -4, i64::MAX],
1308 u16: u16::MAX,
1309 f32s: [0.0, 1.25, f32::NAN],
1310 f64s: [0.0, f64::INFINITY, f64::NAN],
1311 ch: '∞',
1312 };
1313
1314 assert_eq!(roundtrip(&probe), probe);
1315 }
1316
1317 #[rstest]
1318 fn roundtrip_zero_width_sequence() {
1319 let value = vec![(); 10];
1320
1321 assert_eq!(roundtrip(&value), value);
1322 }
1323
1324 #[rstest]
1325 fn encode_is_deterministic() {
1326 let entry = entry(headers_populated());
1327 let manifest = sealed_manifest();
1328
1329 assert_eq!(
1330 encode_to_vec(&entry).unwrap(),
1331 encode_to_vec(&entry).unwrap()
1332 );
1333 assert_eq!(
1334 encode_to_vec(&manifest).unwrap(),
1335 encode_to_vec(&manifest).unwrap()
1336 );
1337 }
1338
1339 #[rstest]
1340 fn data_type_roundtrip_preserves_fields_and_repairs_hash() {
1341 let expected = DataType::new("ExampleType", None, Some("catalog/path".to_string()));
1346 let expected_hash = expected.precomputed_hash();
1347 let mut bytes = encode_to_vec(&expected).unwrap();
1348
1349 let hash_offset = HEADER_LEN
1350 + size_of::<u64>()
1351 + expected.type_name().len()
1352 + size_of::<u8>()
1353 + size_of::<u64>()
1354 + expected.topic().len();
1355 bytes[hash_offset..hash_offset + size_of::<u64>()]
1356 .copy_from_slice(&(expected_hash ^ u64::MAX).to_le_bytes());
1357
1358 let roundtripped: DataType = decode_from_slice(&bytes).unwrap();
1359
1360 assert_eq!(roundtripped.type_name(), expected.type_name());
1361 assert_eq!(roundtripped.metadata(), expected.metadata());
1362 assert_eq!(roundtripped.topic(), expected.topic());
1363 assert_eq!(roundtripped.identifier(), expected.identifier());
1364 assert_eq!(roundtripped.precomputed_hash(), expected_hash);
1365 }
1366
1367 #[rstest]
1368 fn header_present_and_correct() {
1369 let bytes = encode_to_vec(&RunStatus::Running).unwrap();
1370
1371 assert_eq!(&bytes[..4], b"NESC");
1372 assert_eq!(bytes[4], 1);
1373 }
1374
1375 #[rstest]
1376 fn header_bad_magic_rejected() {
1377 let mut bytes = encode_to_vec(&entry(Headers::empty())).unwrap();
1378 bytes[0] ^= 0xFF;
1379
1380 assert!(matches!(
1381 decode_from_slice::<EventStoreEntry>(&bytes),
1382 Err(CodecError::BadMagic)
1383 ));
1384 }
1385
1386 #[rstest]
1387 fn header_unsupported_version_rejected() {
1388 let mut bytes = encode_to_vec(&entry(Headers::empty())).unwrap();
1389 bytes[4] = 2;
1390
1391 assert!(matches!(
1392 decode_from_slice::<EventStoreEntry>(&bytes),
1393 Err(CodecError::UnsupportedVersion(2))
1394 ));
1395 }
1396
1397 #[rstest]
1398 fn header_truncated_rejected() {
1399 let bytes = encode_to_vec(&entry(Headers::empty())).unwrap();
1400
1401 assert!(matches!(
1402 decode_from_slice::<EventStoreEntry>(&bytes[..3]),
1403 Err(CodecError::UnexpectedEof { .. })
1404 ));
1405 }
1406
1407 #[rstest]
1408 fn decodes_a_bincode_blob_as_bad_magic() {
1409 const OLD_BINCODE_STRING: &[u8] = b"\x0aold-format";
1412
1413 assert!(matches!(
1414 decode_from_slice::<String>(OLD_BINCODE_STRING),
1415 Err(CodecError::BadMagic)
1416 ));
1417 }
1418
1419 #[rstest]
1420 fn truncated_body_rejected() {
1421 let bytes = encode_to_vec(&entry(Headers::empty())).unwrap();
1422
1423 assert!(decode_from_slice::<EventStoreEntry>(&bytes[..bytes.len() - 1]).is_err());
1424 }
1425
1426 #[rstest]
1427 fn forged_length_prefix_rejected() {
1428 let mut bytes = encode_to_vec(&"ok".to_string()).unwrap();
1429 bytes[HEADER_LEN..HEADER_LEN + 8].copy_from_slice(&u64::MAX.to_le_bytes());
1430
1431 assert!(matches!(
1432 decode_from_slice::<String>(&bytes),
1433 Err(CodecError::LengthOverflow { .. })
1434 ));
1435 }
1436
1437 #[rstest]
1438 fn forged_sequence_count_rejected_on_eof() {
1439 let mut bytes = encode_to_vec(&vec![1_u8, 2, 3]).unwrap();
1440 bytes[HEADER_LEN..HEADER_LEN + 8].copy_from_slice(&99_u64.to_le_bytes());
1441
1442 assert!(matches!(
1443 decode_from_slice::<Vec<u8>>(&bytes),
1444 Err(CodecError::UnexpectedEof { .. })
1445 ));
1446 }
1447
1448 #[rstest]
1449 fn collection_count_overflow_rejected() {
1450 let mut bytes = encode_to_vec(&vec![1_u8, 2, 3]).unwrap();
1451 let too_many = (MAX_COLLECTION_COUNT as u64) + 1;
1452 bytes[HEADER_LEN..HEADER_LEN + 8].copy_from_slice(&too_many.to_le_bytes());
1453
1454 assert!(matches!(
1455 decode_from_slice::<Vec<u8>>(&bytes),
1456 Err(CodecError::CountOverflow {
1457 claimed,
1458 max: MAX_COLLECTION_COUNT
1459 }) if claimed == too_many
1460 ));
1461 }
1462
1463 #[rstest]
1464 fn collection_count_overflow_rejected_on_encode() {
1465 assert!(matches!(
1466 encode_to_vec(&TooManySeq),
1467 Err(CodecError::CountOverflow {
1468 claimed,
1469 max: MAX_COLLECTION_COUNT
1470 }) if claimed == (MAX_COLLECTION_COUNT as u64) + 1
1471 ));
1472 }
1473
1474 #[rstest]
1475 fn bad_bool_discriminant_rejected() {
1476 let mut bytes = encode_to_vec(&BoolProbe { b: false }).unwrap();
1477 bytes[HEADER_LEN] = 2;
1478
1479 assert!(matches!(
1480 decode_from_slice::<BoolProbe>(&bytes),
1481 Err(CodecError::InvalidBool(2))
1482 ));
1483 }
1484
1485 #[rstest]
1486 fn bad_option_discriminant_rejected() {
1487 let mut bytes = encode_to_vec(&Headers::empty()).unwrap();
1488 bytes[HEADER_LEN] = 2;
1489
1490 assert!(matches!(
1491 decode_from_slice::<Headers>(&bytes),
1492 Err(CodecError::InvalidOption(2))
1493 ));
1494 }
1495
1496 #[rstest]
1497 fn invalid_utf8_rejected() {
1498 let mut bytes = encode_to_vec(&"ok".to_string()).unwrap();
1499 bytes[HEADER_LEN + 8] = 0xFF;
1500
1501 assert!(matches!(
1502 decode_from_slice::<String>(&bytes),
1503 Err(CodecError::InvalidUtf8)
1504 ));
1505 }
1506
1507 #[rstest]
1508 fn unknown_enum_variant_rejected() {
1509 let mut bytes = encode_to_vec(&RunStatus::Running).unwrap();
1510 bytes[HEADER_LEN..HEADER_LEN + 4].copy_from_slice(&99_u32.to_le_bytes());
1511
1512 assert!(matches!(
1513 decode_from_slice::<RunStatus>(&bytes),
1514 Err(CodecError::UnknownVariant(99))
1515 ));
1516 }
1517
1518 #[rstest]
1519 fn trailing_bytes_rejected() {
1520 let mut bytes = encode_to_vec(&RunStatus::Running).unwrap();
1521 bytes.push(0xFF);
1522
1523 assert!(matches!(
1524 decode_from_slice::<RunStatus>(&bytes),
1525 Err(CodecError::TrailingBytes(1))
1526 ));
1527 }
1528
1529 #[rstest]
1530 fn rejects_self_describing() {
1531 #[allow(dead_code)]
1532 #[derive(Debug, Deserialize)]
1533 #[serde(untagged)]
1534 enum Probe {
1535 A(u64),
1536 B(String),
1537 }
1538
1539 let bytes = encode_to_vec(&1_u64).unwrap();
1540 let err = decode_from_slice::<Probe>(&bytes).expect_err("untagged enum must reject any");
1541 assert!(matches!(err, CodecError::SelfDescribing));
1542 }
1543
1544 #[rstest]
1545 fn serialize_without_known_len_is_rejected() {
1546 let mut encoder = Encoder { out: Vec::new() };
1547 assert!(matches!(
1548 ser::Serializer::serialize_seq(&mut encoder, None),
1549 Err(CodecError::MissingLen)
1550 ));
1551
1552 let mut encoder = Encoder { out: Vec::new() };
1553 assert!(matches!(
1554 ser::Serializer::serialize_map(&mut encoder, None),
1555 Err(CodecError::MissingLen)
1556 ));
1557 }
1558
1559 struct U32Visitor;
1560
1561 impl Visitor<'_> for U32Visitor {
1562 type Value = u32;
1563
1564 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1565 formatter.write_str("a little-endian u32 identifier")
1566 }
1567
1568 fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
1569 where
1570 E: de::Error,
1571 {
1572 Ok(value)
1573 }
1574 }
1575
1576 #[rstest]
1577 fn deserialize_identifier_reads_u32() {
1578 let body = 7_u32.to_le_bytes();
1583 let mut decoder = Decoder {
1584 input: &body,
1585 pos: 0,
1586 };
1587
1588 let value = de::Deserializer::deserialize_identifier(&mut decoder, U32Visitor)
1589 .expect("identifier decodes as a u32");
1590
1591 assert_eq!(value, 7);
1592 assert_eq!(decoder.pos, body.len());
1593 }
1594
1595 #[rstest]
1596 fn deserialize_ignored_any_rejected() {
1597 let mut decoder = Decoder { input: &[], pos: 0 };
1603
1604 let err = de::IgnoredAny::deserialize(&mut decoder)
1605 .expect_err("ignored_any must reject as self-describing");
1606
1607 assert!(matches!(err, CodecError::SelfDescribing));
1608 }
1609
1610 #[rstest]
1611 fn entry_hash_newtype_roundtrips() {
1612 let hash = EntryHash(array::from_fn(|idx| {
1613 u8::try_from(idx).expect("hash index is in 0..32")
1614 }));
1615
1616 assert_eq!(roundtrip(&hash), hash);
1617 }
1618
1619 proptest! {
1620 #![proptest_config(ProptestConfig { cases: 64, ..ProptestConfig::default() })]
1621
1622 #[rstest]
1623 fn prop_roundtrip_data_cursor_snapshot(
1624 marker_seq in any::<u64>(),
1625 event_seq_before in any::<u64>(),
1626 ts_init in any::<u64>(),
1627 cursors in proptest::collection::vec((any::<u32>(), any::<u64>(), any::<u64>()), 0..8),
1628 ) {
1629 let snap = DataCursorSnapshot {
1630 marker_seq,
1631 event_seq_before,
1632 ts_init: UnixNanos::from(ts_init),
1633 advanced: cursors
1634 .into_iter()
1635 .map(|(slot, hi, count)| StreamCursor {
1636 slot,
1637 ts_init_hi: UnixNanos::from(hi),
1638 count,
1639 })
1640 .collect(),
1641 };
1642
1643 let bytes = encode_to_vec(&snap).expect("encode");
1644 let decoded: DataCursorSnapshot = decode_from_slice(&bytes).expect("decode");
1645 prop_assert_eq!(snap, decoded);
1646 }
1647
1648 #[rstest]
1649 fn prop_roundtrip_hifi_marker(
1650 marker_seq in any::<u64>(),
1651 event_seq_before in any::<u64>(),
1652 slot in any::<u32>(),
1653 ts_event in any::<u64>(),
1654 ts_init in any::<u64>(),
1655 same_ts_ordinal in any::<u32>(),
1656 fingerprint in proptest::array::uniform32(any::<u8>()),
1657 ) {
1658 let marker = HiFiMarker {
1659 marker_seq,
1660 event_seq_before,
1661 slot,
1662 ts_event: UnixNanos::from(ts_event),
1663 ts_init: UnixNanos::from(ts_init),
1664 same_ts_ordinal,
1665 record_fingerprint: fingerprint,
1666 };
1667
1668 let bytes = encode_to_vec(&marker).expect("encode");
1669 let decoded: HiFiMarker = decode_from_slice(&bytes).expect("decode");
1670 prop_assert_eq!(marker, decoded);
1671 }
1672 }
1673}