1use crate::error::Result;
29use crate::value::Value;
30use std::collections::{BTreeMap, HashMap};
31
32pub trait Crous: Sized {
77 fn to_crous_value(&self) -> Value;
79
80 fn from_crous_value(value: &Value) -> Result<Self>;
82
83 fn schema_fingerprint() -> u64;
86
87 fn type_name() -> &'static str;
89
90 fn to_crous_bytes(&self) -> Result<Vec<u8>> {
95 let val = self.to_crous_value();
96 let mut enc = crate::encoder::Encoder::new();
97 enc.encode_value(&val)?;
98 enc.finish()
99 }
100
101 fn from_crous_bytes(data: &[u8]) -> Result<Self> {
103 let mut dec = crate::decoder::Decoder::new(data);
104 let val = dec.decode_next()?.to_owned_value();
105 Self::from_crous_value(&val)
106 }
107
108 fn from_crous_bytes_with_limits(data: &[u8], limits: crate::limits::Limits) -> Result<Self> {
113 let mut dec = crate::decoder::Decoder::with_limits(data, limits);
114 let val = dec.decode_next()?.to_owned_value();
115 Self::from_crous_value(&val)
116 }
117}
118
119impl Crous for bool {
126 fn to_crous_value(&self) -> Value {
127 Value::Bool(*self)
128 }
129
130 fn from_crous_value(value: &Value) -> Result<Self> {
131 match value {
132 Value::Bool(b) => Ok(*b),
133 _ => Err(crate::error::CrousError::SchemaMismatch(
134 "expected bool".into(),
135 )),
136 }
137 }
138
139 fn schema_fingerprint() -> u64 {
140 0x0004
141 }
142 fn type_name() -> &'static str {
143 "bool"
144 }
145}
146
147macro_rules! impl_crous_uint {
151 ($($ty:ty => $fp:expr, $name:expr);+ $(;)?) => { $(
152 impl Crous for $ty {
153 fn to_crous_value(&self) -> Value {
154 Value::UInt(*self as u64)
155 }
156
157 fn from_crous_value(value: &Value) -> Result<Self> {
158 match value {
159 Value::UInt(n) => {
160 <$ty>::try_from(*n).map_err(|_| crate::error::CrousError::SchemaMismatch(
161 format!("uint {} out of range for {}", n, $name)
162 ))
163 }
164 _ => Err(crate::error::CrousError::SchemaMismatch(
165 format!("expected uint for {}", $name)
166 )),
167 }
168 }
169
170 fn schema_fingerprint() -> u64 { $fp }
171 fn type_name() -> &'static str { $name }
172 }
173 )+ };
174}
175
176impl_crous_uint! {
177 u8 => 0x0002_0001, "u8";
178 u16 => 0x0002_0002, "u16";
179 u32 => 0x0002_0003, "u32";
180 u64 => 0x0002, "u64";
181}
182
183impl Crous for usize {
185 fn to_crous_value(&self) -> Value {
186 Value::UInt(*self as u64)
187 }
188
189 fn from_crous_value(value: &Value) -> Result<Self> {
190 match value {
191 Value::UInt(n) => {
192 usize::try_from(*n).map_err(|_| {
193 crate::error::CrousError::SchemaMismatch(format!(
194 "uint {n} out of range for usize"
195 ))
196 })
197 }
198 _ => Err(crate::error::CrousError::SchemaMismatch(
199 "expected uint for usize".into(),
200 )),
201 }
202 }
203
204 fn schema_fingerprint() -> u64 {
205 0x0002_0005
206 }
207 fn type_name() -> &'static str {
208 "usize"
209 }
210}
211
212impl Crous for u128 {
214 fn to_crous_value(&self) -> Value {
215 Value::UInt(u64::try_from(*self).expect("u128 value exceeds u64::MAX for Crous encoding"))
216 }
217
218 fn from_crous_value(value: &Value) -> Result<Self> {
219 match value {
220 Value::UInt(n) => Ok(u128::from(*n)),
221 _ => Err(crate::error::CrousError::SchemaMismatch(
222 "expected uint for u128".into(),
223 )),
224 }
225 }
226
227 fn schema_fingerprint() -> u64 {
228 0x0002_0006
229 }
230 fn type_name() -> &'static str {
231 "u128"
232 }
233}
234
235macro_rules! impl_crous_int {
239 ($($ty:ty => $fp:expr, $name:expr);+ $(;)?) => { $(
240 impl Crous for $ty {
241 fn to_crous_value(&self) -> Value {
242 Value::Int(i64::from(*self))
243 }
244
245 fn from_crous_value(value: &Value) -> Result<Self> {
246 match value {
247 Value::Int(n) => {
248 <$ty>::try_from(*n).map_err(|_| crate::error::CrousError::SchemaMismatch(
249 format!("int {} out of range for {}", n, $name)
250 ))
251 }
252 Value::UInt(n) => {
254 let as_i64 = i64::try_from(*n).map_err(|_| {
255 crate::error::CrousError::SchemaMismatch(
256 format!("uint {} out of range for {}", n, $name)
257 )
258 })?;
259 <$ty>::try_from(as_i64).map_err(|_| {
260 crate::error::CrousError::SchemaMismatch(
261 format!("uint {} out of range for {}", n, $name)
262 )
263 })
264 }
265 _ => Err(crate::error::CrousError::SchemaMismatch(
266 format!("expected int for {}", $name)
267 )),
268 }
269 }
270
271 fn schema_fingerprint() -> u64 { $fp }
272 fn type_name() -> &'static str { $name }
273 }
274 )+ };
275}
276
277impl_crous_int! {
278 i8 => 0x0003_0001, "i8";
279 i16 => 0x0003_0002, "i16";
280 i32 => 0x0003_0003, "i32";
281 i64 => 0x0003, "i64";
282}
283
284impl Crous for isize {
286 fn to_crous_value(&self) -> Value {
287 Value::Int(*self as i64)
288 }
289
290 fn from_crous_value(value: &Value) -> Result<Self> {
291 match value {
292 Value::Int(n) => {
293 isize::try_from(*n).map_err(|_| {
294 crate::error::CrousError::SchemaMismatch(format!(
295 "int {n} out of range for isize"
296 ))
297 })
298 }
299 Value::UInt(n) => {
300 let as_i64 = i64::try_from(*n).map_err(|_| {
301 crate::error::CrousError::SchemaMismatch(format!(
302 "uint {n} out of range for isize"
303 ))
304 })?;
305 isize::try_from(as_i64).map_err(|_| {
306 crate::error::CrousError::SchemaMismatch(format!(
307 "int {as_i64} out of range for isize"
308 ))
309 })
310 }
311 _ => Err(crate::error::CrousError::SchemaMismatch(
312 "expected int for isize".into(),
313 )),
314 }
315 }
316
317 fn schema_fingerprint() -> u64 {
318 0x0003_0005
319 }
320 fn type_name() -> &'static str {
321 "isize"
322 }
323}
324
325impl Crous for i128 {
327 fn to_crous_value(&self) -> Value {
328 Value::Int(i64::try_from(*self).expect("i128 value exceeds i64 range for Crous encoding"))
329 }
330
331 fn from_crous_value(value: &Value) -> Result<Self> {
332 match value {
333 Value::Int(n) => Ok(i128::from(*n)),
334 Value::UInt(n) => Ok(i128::from(*n)),
335 _ => Err(crate::error::CrousError::SchemaMismatch(
336 "expected int for i128".into(),
337 )),
338 }
339 }
340
341 fn schema_fingerprint() -> u64 {
342 0x0003_0006
343 }
344 fn type_name() -> &'static str {
345 "i128"
346 }
347}
348
349impl Crous for f64 {
352 fn to_crous_value(&self) -> Value {
353 Value::Float(*self)
354 }
355
356 fn from_crous_value(value: &Value) -> Result<Self> {
357 match value {
358 Value::Float(f) => Ok(*f),
359 _ => Err(crate::error::CrousError::SchemaMismatch(
360 "expected float".into(),
361 )),
362 }
363 }
364
365 fn schema_fingerprint() -> u64 {
366 0x0005
367 }
368 fn type_name() -> &'static str {
369 "f64"
370 }
371}
372
373impl Crous for f32 {
374 fn to_crous_value(&self) -> Value {
375 Value::Float(f64::from(*self))
376 }
377
378 fn from_crous_value(value: &Value) -> Result<Self> {
379 match value {
380 Value::Float(f) => Ok(*f as f32),
381 _ => Err(crate::error::CrousError::SchemaMismatch(
382 "expected float for f32".into(),
383 )),
384 }
385 }
386
387 fn schema_fingerprint() -> u64 {
388 0x0005_0001
389 }
390 fn type_name() -> &'static str {
391 "f32"
392 }
393}
394
395impl Crous for String {
398 fn to_crous_value(&self) -> Value {
399 Value::Str(self.clone())
400 }
401
402 fn from_crous_value(value: &Value) -> Result<Self> {
403 match value {
404 Value::Str(s) => Ok(s.clone()),
405 _ => Err(crate::error::CrousError::SchemaMismatch(
406 "expected string".into(),
407 )),
408 }
409 }
410
411 fn schema_fingerprint() -> u64 {
412 0x0001
413 }
414 fn type_name() -> &'static str {
415 "String"
416 }
417}
418
419impl Crous for Box<str> {
420 fn to_crous_value(&self) -> Value {
421 Value::Str(self.to_string())
422 }
423
424 fn from_crous_value(value: &Value) -> Result<Self> {
425 match value {
426 Value::Str(s) => Ok(s.clone().into_boxed_str()),
427 _ => Err(crate::error::CrousError::SchemaMismatch(
428 "expected string for Box<str>".into(),
429 )),
430 }
431 }
432
433 fn schema_fingerprint() -> u64 {
434 0x0001_0001
435 }
436 fn type_name() -> &'static str {
437 "Box<str>"
438 }
439}
440
441#[derive(Debug, Clone, PartialEq, Eq, Hash)]
461pub struct CrousBytes(pub Vec<u8>);
462
463impl CrousBytes {
464 pub fn new(bytes: Vec<u8>) -> Self {
466 Self(bytes)
467 }
468
469 pub fn into_inner(self) -> Vec<u8> {
471 self.0
472 }
473
474 pub fn as_bytes(&self) -> &[u8] {
476 &self.0
477 }
478}
479
480impl From<Vec<u8>> for CrousBytes {
481 fn from(v: Vec<u8>) -> Self {
482 Self(v)
483 }
484}
485
486impl From<CrousBytes> for Vec<u8> {
487 fn from(b: CrousBytes) -> Self {
488 b.0
489 }
490}
491
492impl AsRef<[u8]> for CrousBytes {
493 fn as_ref(&self) -> &[u8] {
494 &self.0
495 }
496}
497
498impl Crous for CrousBytes {
499 fn to_crous_value(&self) -> Value {
500 Value::Bytes(self.0.clone())
501 }
502
503 fn from_crous_value(value: &Value) -> Result<Self> {
504 match value {
505 Value::Bytes(b) => Ok(CrousBytes(b.clone())),
506 _ => Err(crate::error::CrousError::SchemaMismatch(
507 "expected bytes".into(),
508 )),
509 }
510 }
511
512 fn schema_fingerprint() -> u64 {
513 0x0006
514 }
515 fn type_name() -> &'static str {
516 "CrousBytes"
517 }
518}
519
520impl<T: Crous> Crous for Vec<T> {
523 fn to_crous_value(&self) -> Value {
524 Value::Array(self.iter().map(|item| item.to_crous_value()).collect())
525 }
526
527 fn from_crous_value(value: &Value) -> Result<Self> {
528 match value {
529 Value::Array(items) => items.iter().map(T::from_crous_value).collect(),
530 _ => Err(crate::error::CrousError::SchemaMismatch(
531 "expected array".into(),
532 )),
533 }
534 }
535
536 fn schema_fingerprint() -> u64 {
537 T::schema_fingerprint()
538 .wrapping_mul(31)
539 .wrapping_add(0x0010)
540 }
541
542 fn type_name() -> &'static str {
543 "Vec"
544 }
545}
546
547impl<T: Crous> Crous for Option<T> {
548 fn to_crous_value(&self) -> Value {
549 match self {
550 Some(v) => v.to_crous_value(),
551 None => Value::Null,
552 }
553 }
554
555 fn from_crous_value(value: &Value) -> Result<Self> {
556 match value {
557 Value::Null => Ok(None),
558 other => Ok(Some(T::from_crous_value(other)?)),
559 }
560 }
561
562 fn schema_fingerprint() -> u64 {
563 T::schema_fingerprint()
564 .wrapping_mul(37)
565 .wrapping_add(0x0020)
566 }
567
568 fn type_name() -> &'static str {
569 "Option"
570 }
571}
572
573impl<T: Crous> Crous for Box<T> {
574 fn to_crous_value(&self) -> Value {
575 (**self).to_crous_value()
576 }
577
578 fn from_crous_value(value: &Value) -> Result<Self> {
579 T::from_crous_value(value).map(Box::new)
580 }
581
582 fn schema_fingerprint() -> u64 {
583 T::schema_fingerprint()
584 }
585
586 fn type_name() -> &'static str {
587 T::type_name()
588 }
589}
590
591impl<T: Crous> Crous for HashMap<String, T> {
594 fn to_crous_value(&self) -> Value {
595 Value::Object(
596 self.iter()
597 .map(|(k, v)| (k.clone(), v.to_crous_value()))
598 .collect(),
599 )
600 }
601
602 fn from_crous_value(value: &Value) -> Result<Self> {
603 match value {
604 Value::Object(entries) => {
605 let mut map = HashMap::with_capacity(entries.len());
606 for (k, v) in entries {
607 map.insert(k.clone(), T::from_crous_value(v)?);
608 }
609 Ok(map)
610 }
611 _ => Err(crate::error::CrousError::SchemaMismatch(
612 "expected object for HashMap".into(),
613 )),
614 }
615 }
616
617 fn schema_fingerprint() -> u64 {
618 T::schema_fingerprint()
619 .wrapping_mul(41)
620 .wrapping_add(0x0030)
621 }
622
623 fn type_name() -> &'static str {
624 "HashMap"
625 }
626}
627
628impl<T: Crous> Crous for BTreeMap<String, T> {
629 fn to_crous_value(&self) -> Value {
630 Value::Object(
631 self.iter()
632 .map(|(k, v)| (k.clone(), v.to_crous_value()))
633 .collect(),
634 )
635 }
636
637 fn from_crous_value(value: &Value) -> Result<Self> {
638 match value {
639 Value::Object(entries) => {
640 let mut map = BTreeMap::new();
641 for (k, v) in entries {
642 map.insert(k.clone(), T::from_crous_value(v)?);
643 }
644 Ok(map)
645 }
646 _ => Err(crate::error::CrousError::SchemaMismatch(
647 "expected object for BTreeMap".into(),
648 )),
649 }
650 }
651
652 fn schema_fingerprint() -> u64 {
653 T::schema_fingerprint()
654 .wrapping_mul(43)
655 .wrapping_add(0x0031)
656 }
657
658 fn type_name() -> &'static str {
659 "BTreeMap"
660 }
661}
662
663macro_rules! impl_crous_tuple {
666 ($fp:expr, $($idx:tt : $T:ident),+) => {
667 impl<$($T: Crous),+> Crous for ($($T,)+) {
668 fn to_crous_value(&self) -> Value {
669 Value::Array(vec![
670 $(self.$idx.to_crous_value()),+
671 ])
672 }
673
674 fn from_crous_value(value: &Value) -> Result<Self> {
675 match value {
676 Value::Array(items) => {
677 let mut iter = items.iter();
678 Ok(($(
679 $T::from_crous_value(
680 iter.next().ok_or_else(|| {
681 crate::error::CrousError::SchemaMismatch(
682 "tuple: not enough array elements".into()
683 )
684 })?
685 )?,
686 )+))
687 }
688 _ => Err(crate::error::CrousError::SchemaMismatch(
689 "expected array for tuple".into(),
690 )),
691 }
692 }
693
694 fn schema_fingerprint() -> u64 { $fp }
695 fn type_name() -> &'static str { "tuple" }
696 }
697 };
698}
699
700impl_crous_tuple!(0x0040_0001, 0: A);
701impl_crous_tuple!(0x0040_0002, 0: A, 1: B);
702impl_crous_tuple!(0x0040_0003, 0: A, 1: B, 2: C);
703impl_crous_tuple!(0x0040_0004, 0: A, 1: B, 2: C, 3: D);
704impl_crous_tuple!(0x0040_0005, 0: A, 1: B, 2: C, 3: D, 4: E);
705impl_crous_tuple!(0x0040_0006, 0: A, 1: B, 2: C, 3: D, 4: E, 5: F);
706
707impl Crous for () {
710 fn to_crous_value(&self) -> Value {
711 Value::Null
712 }
713
714 fn from_crous_value(value: &Value) -> Result<Self> {
715 match value {
716 Value::Null => Ok(()),
717 _ => Err(crate::error::CrousError::SchemaMismatch(
718 "expected null for ()".into(),
719 )),
720 }
721 }
722
723 fn schema_fingerprint() -> u64 {
724 0x0000
725 }
726 fn type_name() -> &'static str {
727 "()"
728 }
729}
730
731#[cfg(test)]
736mod tests {
737 use super::*;
738
739 #[test]
740 fn u8_roundtrip() {
741 let v: u8 = 200;
742 let val = v.to_crous_value();
743 assert_eq!(val, Value::UInt(200));
744 assert_eq!(u8::from_crous_value(&val).unwrap(), 200);
745 }
746
747 #[test]
748 fn u8_overflow() {
749 let val = Value::UInt(256);
750 assert!(u8::from_crous_value(&val).is_err());
751 }
752
753 #[test]
754 fn u16_roundtrip() {
755 let v: u16 = 60000;
756 let val = v.to_crous_value();
757 assert_eq!(u16::from_crous_value(&val).unwrap(), 60000);
758 }
759
760 #[test]
761 fn u32_roundtrip() {
762 let v: u32 = u32::MAX;
763 let val = v.to_crous_value();
764 assert_eq!(u32::from_crous_value(&val).unwrap(), u32::MAX);
765 }
766
767 #[test]
768 fn i8_roundtrip() {
769 let v: i8 = -42;
770 let val = v.to_crous_value();
771 assert_eq!(val, Value::Int(-42));
772 assert_eq!(i8::from_crous_value(&val).unwrap(), -42);
773 }
774
775 #[test]
776 fn i8_overflow() {
777 let val = Value::Int(200);
778 assert!(i8::from_crous_value(&val).is_err());
779 }
780
781 #[test]
782 fn i16_roundtrip() {
783 let v: i16 = -30000;
784 let val = v.to_crous_value();
785 assert_eq!(i16::from_crous_value(&val).unwrap(), -30000);
786 }
787
788 #[test]
789 fn i32_roundtrip() {
790 let v: i32 = i32::MIN;
791 let val = v.to_crous_value();
792 assert_eq!(i32::from_crous_value(&val).unwrap(), i32::MIN);
793 }
794
795 #[test]
796 fn i32_from_uint_compat() {
797 let val = Value::UInt(42);
799 assert_eq!(i32::from_crous_value(&val).unwrap(), 42);
800 }
801
802 #[test]
803 fn f32_roundtrip() {
804 let v: f32 = 2.78;
805 let val = v.to_crous_value();
806 assert!(matches!(val, Value::Float(_)));
807 let back = f32::from_crous_value(&val).unwrap();
808 assert!((back - 2.78).abs() < 1e-5);
809 }
810
811 #[test]
812 fn vec_u8_is_array() {
813 let v: Vec<u8> = vec![1, 2, 3];
814 let val = v.to_crous_value();
815 assert!(matches!(val, Value::Array(_)));
817 let back = Vec::<u8>::from_crous_value(&val).unwrap();
818 assert_eq!(back, vec![1, 2, 3]);
819 }
820
821 #[test]
822 fn crous_bytes_is_bytes() {
823 let blob = CrousBytes(vec![0xDE, 0xAD, 0xBE, 0xEF]);
824 let val = blob.to_crous_value();
825 assert!(matches!(val, Value::Bytes(_)));
826 let back = CrousBytes::from_crous_value(&val).unwrap();
827 assert_eq!(back.0, vec![0xDE, 0xAD, 0xBE, 0xEF]);
828 }
829
830 #[test]
831 fn box_str_roundtrip() {
832 let s: Box<str> = "hello".into();
833 let val = s.to_crous_value();
834 assert_eq!(val, Value::Str("hello".into()));
835 let back = Box::<str>::from_crous_value(&val).unwrap();
836 assert_eq!(&*back, "hello");
837 }
838
839 #[test]
840 fn box_t_roundtrip() {
841 let v: Box<u32> = Box::new(42);
842 let val = v.to_crous_value();
843 assert_eq!(val, Value::UInt(42));
844 let back = Box::<u32>::from_crous_value(&val).unwrap();
845 assert_eq!(*back, 42);
846 }
847
848 #[test]
849 fn hashmap_roundtrip() {
850 let mut map = HashMap::new();
851 map.insert("x".to_string(), 10u64);
852 map.insert("y".to_string(), 20u64);
853
854 let val = map.to_crous_value();
855 assert!(matches!(val, Value::Object(_)));
856
857 let back = HashMap::<String, u64>::from_crous_value(&val).unwrap();
858 assert_eq!(back.get("x"), Some(&10));
859 assert_eq!(back.get("y"), Some(&20));
860 }
861
862 #[test]
863 fn btreemap_roundtrip() {
864 let mut map = BTreeMap::new();
865 map.insert("a".to_string(), Value::Bool(true));
866 map.insert("b".to_string(), Value::UInt(7));
867
868 let mut m2 = BTreeMap::new();
871 m2.insert("flag".to_string(), true);
872 m2.insert("enabled".to_string(), false);
873 let val = m2.to_crous_value();
874 let back = BTreeMap::<String, bool>::from_crous_value(&val).unwrap();
875 assert_eq!(back.get("flag"), Some(&true));
876 assert_eq!(back.get("enabled"), Some(&false));
877 }
878
879 #[test]
880 fn tuple2_roundtrip() {
881 let t = (42u32, "hello".to_string());
882 let val = t.to_crous_value();
883 assert!(matches!(val, Value::Array(_)));
884 let back = <(u32, String)>::from_crous_value(&val).unwrap();
885 assert_eq!(back, (42, "hello".to_string()));
886 }
887
888 #[test]
889 fn tuple3_roundtrip() {
890 let t = (true, -5i16, 2.78f64);
891 let val = t.to_crous_value();
892 let back = <(bool, i16, f64)>::from_crous_value(&val).unwrap();
893 assert!(back.0);
894 assert_eq!(back.1, -5);
895 assert!((back.2 - 2.78).abs() < 1e-10);
896 }
897
898 #[test]
899 fn unit_roundtrip() {
900 let val = ().to_crous_value();
901 assert_eq!(val, Value::Null);
902 assert_eq!(<()>::from_crous_value(&val).unwrap(), ());
903 }
904
905 #[test]
906 fn usize_roundtrip() {
907 let v: usize = 999;
908 let val = v.to_crous_value();
909 assert_eq!(usize::from_crous_value(&val).unwrap(), 999);
910 }
911
912 #[test]
913 fn isize_roundtrip() {
914 let v: isize = -999;
915 let val = v.to_crous_value();
916 assert_eq!(isize::from_crous_value(&val).unwrap(), -999);
917 }
918
919 #[test]
920 fn u128_small_roundtrip() {
921 let v: u128 = 123456;
922 let val = v.to_crous_value();
923 assert_eq!(u128::from_crous_value(&val).unwrap(), 123456);
924 }
925
926 #[test]
927 fn i128_small_roundtrip() {
928 let v: i128 = -123456;
929 let val = v.to_crous_value();
930 assert_eq!(i128::from_crous_value(&val).unwrap(), -123456);
931 }
932
933 #[test]
934 fn nested_option_vec() {
935 let v: Option<Vec<u8>> = Some(vec![10, 20, 30]);
936 let val = v.to_crous_value();
937 let back = Option::<Vec<u8>>::from_crous_value(&val).unwrap();
938 assert_eq!(back, Some(vec![10, 20, 30]));
939 }
940
941 #[test]
942 fn option_none() {
943 let v: Option<u8> = None;
944 let val = v.to_crous_value();
945 assert_eq!(val, Value::Null);
946 let back = Option::<u8>::from_crous_value(&val).unwrap();
947 assert_eq!(back, None);
948 }
949
950 #[test]
951 fn full_binary_roundtrip_u8() {
952 let v: u8 = 42;
954 let bytes = v.to_crous_bytes().unwrap();
955 let back = u8::from_crous_bytes(&bytes).unwrap();
956 assert_eq!(back, 42);
957 }
958
959 #[test]
960 fn full_binary_roundtrip_crous_bytes() {
961 let blob = CrousBytes(vec![1, 2, 3, 4]);
962 let bytes = blob.to_crous_bytes().unwrap();
963 let back = CrousBytes::from_crous_bytes(&bytes).unwrap();
964 assert_eq!(back.0, vec![1, 2, 3, 4]);
965 }
966
967 #[test]
968 fn full_binary_roundtrip_tuple() {
969 let t = (100u16, "world".to_string(), false);
970 let bytes = t.to_crous_bytes().unwrap();
971 let back = <(u16, String, bool)>::from_crous_bytes(&bytes).unwrap();
972 assert_eq!(back, (100, "world".to_string(), false));
973 }
974
975 #[test]
976 fn full_binary_roundtrip_hashmap() {
977 let mut m = HashMap::new();
978 m.insert("key".to_string(), 99u32);
979 let bytes = m.to_crous_bytes().unwrap();
980 let back = HashMap::<String, u32>::from_crous_bytes(&bytes).unwrap();
981 assert_eq!(back.get("key"), Some(&99));
982 }
983}