use alloc::collections::{BTreeMap, BTreeSet};
use alloc::string::String;
use alloc::vec::Vec;
#[cfg(feature = "std")]
use std::collections::{HashMap, HashSet};
#[cfg(feature = "std")]
use std::hash::{BuildHasher, Hash};
use crate::codec::{Decode, Encode, Encoder};
use crate::error::{Result, SerialError};
use crate::traits::{Deserialize, Serialize};
use crate::varint;
impl Serialize for u8 {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_byte(*self)
}
}
impl Deserialize for u8 {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
decoder.read_byte()
}
}
impl Serialize for u16 {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_varint_u64(u64::from(*self))
}
}
impl Deserialize for u16 {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
let value = decoder.read_varint_u64()?;
u16::try_from(value).map_err(|_| SerialError::IntegerOutOfRange)
}
}
impl Serialize for u32 {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_varint_u64(u64::from(*self))
}
}
impl Deserialize for u32 {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
let value = decoder.read_varint_u64()?;
u32::try_from(value).map_err(|_| SerialError::IntegerOutOfRange)
}
}
impl Serialize for u64 {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_varint_u64(*self)
}
}
impl Deserialize for u64 {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
decoder.read_varint_u64()
}
}
impl Serialize for u128 {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_varint_u128(*self)
}
}
impl Deserialize for u128 {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
decoder.read_varint_u128()
}
}
impl Serialize for usize {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_varint_u64(*self as u64)
}
}
impl Deserialize for usize {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
let value = decoder.read_varint_u64()?;
usize::try_from(value).map_err(|_| SerialError::IntegerOutOfRange)
}
}
impl Serialize for i8 {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_byte(*self as u8)
}
}
impl Deserialize for i8 {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
Ok(decoder.read_byte()? as i8)
}
}
impl Serialize for i16 {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_varint_u64(varint::zigzag_encode_i64(i64::from(*self)))
}
}
impl Deserialize for i16 {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
let value = varint::zigzag_decode_i64(decoder.read_varint_u64()?);
i16::try_from(value).map_err(|_| SerialError::IntegerOutOfRange)
}
}
impl Serialize for i32 {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_varint_u64(varint::zigzag_encode_i64(i64::from(*self)))
}
}
impl Deserialize for i32 {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
let value = varint::zigzag_decode_i64(decoder.read_varint_u64()?);
i32::try_from(value).map_err(|_| SerialError::IntegerOutOfRange)
}
}
impl Serialize for i64 {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_varint_u64(varint::zigzag_encode_i64(*self))
}
}
impl Deserialize for i64 {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
Ok(varint::zigzag_decode_i64(decoder.read_varint_u64()?))
}
}
impl Serialize for i128 {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_varint_u128(varint::zigzag_encode_i128(*self))
}
}
impl Deserialize for i128 {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
Ok(varint::zigzag_decode_i128(decoder.read_varint_u128()?))
}
}
impl Serialize for isize {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_varint_u64(varint::zigzag_encode_i64(*self as i64))
}
}
impl Deserialize for isize {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
let value = varint::zigzag_decode_i64(decoder.read_varint_u64()?);
isize::try_from(value).map_err(|_| SerialError::IntegerOutOfRange)
}
}
impl Serialize for bool {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_byte(u8::from(*self))
}
}
impl Deserialize for bool {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
match decoder.read_byte()? {
0x00 => Ok(false),
0x01 => Ok(true),
other => Err(SerialError::InvalidBool { byte: other }),
}
}
}
impl Serialize for f32 {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_bytes(&self.to_bits().to_le_bytes())
}
}
impl Deserialize for f32 {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
let mut buf = [0u8; 4];
decoder.read_into(&mut buf)?;
Ok(f32::from_bits(u32::from_le_bytes(buf)))
}
}
impl Serialize for f64 {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_bytes(&self.to_bits().to_le_bytes())
}
}
impl Deserialize for f64 {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
let mut buf = [0u8; 8];
decoder.read_into(&mut buf)?;
Ok(f64::from_bits(u64::from_le_bytes(buf)))
}
}
impl Serialize for str {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
let bytes = self.as_bytes();
encoder.write_varint_u64(bytes.len() as u64)?;
encoder.write_bytes(bytes)
}
}
impl Serialize for String {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
Serialize::serialize(self.as_str(), encoder)
}
}
impl Deserialize for String {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
let bytes = decoder.read_length_prefixed()?;
String::from_utf8(bytes).map_err(|_| SerialError::InvalidUtf8)
}
}
impl<T: Serialize> Serialize for [T] {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encoder.write_varint_u64(self.len() as u64)?;
for item in self {
item.serialize(encoder)?;
}
Ok(())
}
}
impl<T: Serialize> Serialize for Vec<T> {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
Serialize::serialize(self.as_slice(), encoder)
}
}
impl<T: Deserialize> Deserialize for Vec<T> {
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
let declared = decoder.read_varint_u64()?;
let len = guard_element_count::<T, _>(declared, decoder)?;
let mut out = Vec::with_capacity(initial_capacity(len));
for _ in 0..len {
out.push(T::deserialize(decoder)?);
}
Ok(out)
}
}
impl<T: Serialize, const N: usize> Serialize for [T; N] {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
for item in self {
item.serialize(encoder)?;
}
Ok(())
}
}
impl<T: Deserialize, const N: usize> Deserialize for [T; N] {
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
let mut out: Vec<T> = Vec::with_capacity(N);
for _ in 0..N {
out.push(T::deserialize(decoder)?);
}
out.try_into().map_err(|_| SerialError::IntegerOutOfRange)
}
}
impl Serialize for () {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, _encoder: &mut E) -> Result<()> {
Ok(())
}
}
impl Deserialize for () {
#[inline]
fn deserialize<D: Decode + ?Sized>(_decoder: &mut D) -> Result<Self> {
Ok(())
}
}
macro_rules! impl_tuple {
($($name:ident: $idx:tt),+) => {
impl<$($name: Serialize),+> Serialize for ($($name,)+) {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
$( self.$idx.serialize(encoder)?; )+
Ok(())
}
}
impl<$($name: Deserialize),+> Deserialize for ($($name,)+) {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
Ok(( $( $name::deserialize(decoder)?, )+ ))
}
}
};
}
impl_tuple!(T0: 0);
impl_tuple!(T0: 0, T1: 1);
impl_tuple!(T0: 0, T1: 1, T2: 2);
impl_tuple!(T0: 0, T1: 1, T2: 2, T3: 3);
impl_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4);
impl_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5);
impl_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6);
impl_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7);
impl_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8);
impl_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9);
impl_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10);
impl_tuple!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10, T11: 11);
impl<T: Serialize> Serialize for Option<T> {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
match self {
None => encoder.write_byte(0x00),
Some(value) => {
encoder.write_byte(0x01)?;
value.serialize(encoder)
}
}
}
}
impl<T: Deserialize> Deserialize for Option<T> {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
match decoder.read_byte()? {
0x00 => Ok(None),
0x01 => Ok(Some(T::deserialize(decoder)?)),
tag => Err(SerialError::InvalidTag {
kind: "Option",
tag,
}),
}
}
}
impl<T: Serialize, E: Serialize> Serialize for core::result::Result<T, E> {
#[inline]
fn serialize<Enc: Encode + ?Sized>(&self, encoder: &mut Enc) -> Result<()> {
match self {
Ok(value) => {
encoder.write_byte(0x00)?;
value.serialize(encoder)
}
Err(err) => {
encoder.write_byte(0x01)?;
err.serialize(encoder)
}
}
}
}
impl<T: Deserialize, E: Deserialize> Deserialize for core::result::Result<T, E> {
#[inline]
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
match decoder.read_byte()? {
0x00 => Ok(Ok(T::deserialize(decoder)?)),
0x01 => Ok(Err(E::deserialize(decoder)?)),
tag => Err(SerialError::InvalidTag {
kind: "Result",
tag,
}),
}
}
}
impl<T: Serialize + ?Sized> Serialize for &T {
#[inline]
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
(**self).serialize(encoder)
}
}
fn encode_map_like<K, V, I, E>(count: usize, entries: I, encoder: &mut E) -> Result<()>
where
K: Serialize,
V: Serialize,
I: IntoIterator<Item = (K, V)>,
E: Encode + ?Sized,
{
let mut buffered: Vec<(usize, Vec<u8>)> = Vec::with_capacity(count);
for (k, v) in entries {
let mut tmp = Encoder::new();
k.serialize(&mut tmp)?;
let key_len = tmp.as_bytes().len();
v.serialize(&mut tmp)?;
buffered.push((key_len, tmp.into_inner()));
}
buffered.sort_by(|a, b| {
let ka = &a.1[..a.0];
let kb = &b.1[..b.0];
ka.cmp(kb)
});
encoder.write_varint_u64(count as u64)?;
for (_, bytes) in &buffered {
encoder.write_bytes(bytes)?;
}
Ok(())
}
fn encode_set_like<T, I, E>(count: usize, items: I, encoder: &mut E) -> Result<()>
where
T: Serialize,
I: IntoIterator<Item = T>,
E: Encode + ?Sized,
{
let mut buffered: Vec<Vec<u8>> = Vec::with_capacity(count);
for item in items {
let mut tmp = Encoder::new();
item.serialize(&mut tmp)?;
buffered.push(tmp.into_inner());
}
buffered.sort();
encoder.write_varint_u64(count as u64)?;
for bytes in &buffered {
encoder.write_bytes(bytes)?;
}
Ok(())
}
impl<K, V> Serialize for BTreeMap<K, V>
where
K: Serialize,
V: Serialize,
{
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encode_map_like(self.len(), self.iter(), encoder)
}
}
impl<K, V> Deserialize for BTreeMap<K, V>
where
K: Deserialize + Ord,
V: Deserialize,
{
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
let declared = decoder.read_varint_u64()?;
let len = guard_element_count::<(K, V), _>(declared, decoder)?;
let mut out = BTreeMap::new();
for _ in 0..len {
let k = K::deserialize(decoder)?;
let v = V::deserialize(decoder)?;
let _ = out.insert(k, v);
}
Ok(out)
}
}
impl<T> Serialize for BTreeSet<T>
where
T: Serialize,
{
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encode_set_like(self.len(), self.iter(), encoder)
}
}
impl<T> Deserialize for BTreeSet<T>
where
T: Deserialize + Ord,
{
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
let declared = decoder.read_varint_u64()?;
let len = guard_element_count::<T, _>(declared, decoder)?;
let mut out = BTreeSet::new();
for _ in 0..len {
let _ = out.insert(T::deserialize(decoder)?);
}
Ok(out)
}
}
#[cfg(feature = "std")]
impl<K, V, S> Serialize for HashMap<K, V, S>
where
K: Serialize,
V: Serialize,
{
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encode_map_like(self.len(), self.iter(), encoder)
}
}
#[cfg(feature = "std")]
impl<K, V, S> Deserialize for HashMap<K, V, S>
where
K: Deserialize + Hash + Eq,
V: Deserialize,
S: BuildHasher + Default,
{
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
let declared = decoder.read_varint_u64()?;
let len = guard_element_count::<(K, V), _>(declared, decoder)?;
let mut out = HashMap::with_capacity_and_hasher(initial_capacity(len), S::default());
for _ in 0..len {
let k = K::deserialize(decoder)?;
let v = V::deserialize(decoder)?;
let _ = out.insert(k, v);
}
Ok(out)
}
}
#[cfg(feature = "std")]
impl<T, S> Serialize for HashSet<T, S>
where
T: Serialize,
{
fn serialize<E: Encode + ?Sized>(&self, encoder: &mut E) -> Result<()> {
encode_set_like(self.len(), self.iter(), encoder)
}
}
#[cfg(feature = "std")]
impl<T, S> Deserialize for HashSet<T, S>
where
T: Deserialize + Hash + Eq,
S: BuildHasher + Default,
{
fn deserialize<D: Decode + ?Sized>(decoder: &mut D) -> Result<Self> {
let declared = decoder.read_varint_u64()?;
let len = guard_element_count::<T, _>(declared, decoder)?;
let mut out = HashSet::with_capacity_and_hasher(initial_capacity(len), S::default());
for _ in 0..len {
let _ = out.insert(T::deserialize(decoder)?);
}
Ok(out)
}
}
#[inline]
fn guard_element_count<T, D: Decode + ?Sized>(declared: u64, decoder: &D) -> Result<usize> {
let max = decoder.max_alloc() as u64;
if declared > max {
return Err(SerialError::InvalidLength {
declared,
remaining: 0,
});
}
let _phantom: core::marker::PhantomData<T> = core::marker::PhantomData;
usize::try_from(declared).map_err(|_| SerialError::IntegerOutOfRange)
}
#[inline]
fn initial_capacity(declared: usize) -> usize {
const INITIAL_CAPACITY_CAP: usize = 4096;
declared.min(INITIAL_CAPACITY_CAP)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{decode, encode};
use alloc::vec;
fn round_trip<T>(value: T)
where
T: Serialize + Deserialize + PartialEq + core::fmt::Debug,
{
let bytes = encode(&value).expect("encode");
let back: T = decode(&bytes).expect("decode");
assert_eq!(back, value);
}
#[test]
fn u8_round_trips() {
for v in [0u8, 1, 127, 128, 255] {
round_trip(v);
}
}
#[test]
fn u64_round_trips() {
for v in [0u64, 1, u32::MAX as u64, u64::MAX] {
round_trip(v);
}
}
#[test]
fn i64_round_trips() {
for v in [0i64, -1, 1, i64::MIN, i64::MAX] {
round_trip(v);
}
}
#[test]
fn bool_round_trips() {
round_trip(true);
round_trip(false);
}
#[test]
fn string_round_trips() {
for s in ["", "hello", "a longer string with some content"] {
round_trip(String::from(s));
}
}
#[test]
fn vec_u8_round_trips() {
round_trip::<Vec<u8>>(vec![]);
round_trip::<Vec<u8>>(vec![0u8, 1, 2, 3]);
round_trip::<Vec<u8>>(vec![0xffu8; 1024]);
}
#[test]
fn vec_u32_round_trips() {
round_trip::<Vec<u32>>(vec![]);
round_trip::<Vec<u32>>(vec![1, 2, u32::MAX]);
}
#[test]
fn vec_string_round_trips() {
round_trip(vec![
String::from("hello"),
String::from("world"),
String::new(),
]);
}
#[test]
fn array_round_trips() {
round_trip([1u32, 2, 3, 4]);
round_trip([0u8; 0]);
}
#[test]
fn tuple_round_trips() {
round_trip((1u8, 2u16, 3u32));
round_trip((String::from("a"), 42u64, -3i32));
}
#[test]
fn option_round_trips() {
round_trip::<Option<u64>>(None);
round_trip::<Option<u64>>(Some(42));
round_trip::<Option<String>>(Some(String::from("hi")));
}
#[test]
fn result_round_trips() {
round_trip::<core::result::Result<u64, String>>(Ok(7));
round_trip::<core::result::Result<u64, String>>(Err(String::from("nope")));
}
#[test]
fn invalid_bool_byte_is_rejected() {
let err = decode::<bool>(&[0x7f]).expect_err("0x7f is not a bool");
assert!(matches!(err, SerialError::InvalidBool { byte: 0x7f }));
}
#[test]
fn string_with_invalid_utf8_is_rejected() {
let bytes = [0x02, 0xff, 0xff];
let err = decode::<String>(&bytes).expect_err("invalid UTF-8 should fail");
assert!(matches!(err, SerialError::InvalidUtf8));
}
#[test]
fn option_invalid_tag_is_rejected() {
let err = decode::<Option<u8>>(&[0x02]).expect_err("0x02 is not a valid Option tag");
assert!(matches!(
err,
SerialError::InvalidTag {
kind: "Option",
tag: 0x02
}
));
}
#[test]
fn result_invalid_tag_is_rejected() {
let err =
decode::<core::result::Result<u8, u8>>(&[0x02]).expect_err("0x02 is not a Result tag");
assert!(matches!(
err,
SerialError::InvalidTag {
kind: "Result",
tag: 0x02
}
));
}
#[test]
fn f64_round_trips_including_inf() {
for v in [
0.0f64,
-0.0,
1.0,
-1.0,
f64::MIN,
f64::MAX,
f64::INFINITY,
f64::NEG_INFINITY,
] {
let bytes = encode(&v).unwrap();
let back: f64 = decode(&bytes).unwrap();
assert_eq!(back.to_bits(), v.to_bits());
}
}
#[test]
fn f64_nan_round_trips_bit_for_bit() {
let v = f64::NAN;
let bytes = encode(&v).unwrap();
let back: f64 = decode(&bytes).unwrap();
assert_eq!(back.to_bits(), v.to_bits());
assert!(back.is_nan());
}
#[test]
fn btreemap_round_trips() {
let mut m = BTreeMap::new();
let _ = m.insert(String::from("a"), 1u32);
let _ = m.insert(String::from("b"), 2);
let _ = m.insert(String::from("c"), 3);
round_trip(m);
}
#[test]
fn btreemap_empty_round_trips() {
round_trip(BTreeMap::<u32, u32>::new());
}
#[test]
fn btreeset_round_trips() {
let mut s = BTreeSet::new();
let _ = s.insert(1u32);
let _ = s.insert(2);
let _ = s.insert(3);
round_trip(s);
}
#[cfg(feature = "std")]
#[test]
fn hashmap_round_trips() {
let mut m: HashMap<String, u32> = HashMap::new();
let _ = m.insert(String::from("alpha"), 1);
let _ = m.insert(String::from("beta"), 2);
round_trip(m);
}
#[cfg(feature = "std")]
#[test]
fn hashset_round_trips() {
let mut s: HashSet<u32> = HashSet::new();
let _ = s.insert(1);
let _ = s.insert(7);
let _ = s.insert(42);
round_trip(s);
}
#[cfg(feature = "std")]
#[test]
fn hashmap_and_btreemap_encode_identically_for_same_data() {
let mut h: HashMap<String, u32> = HashMap::new();
let mut b: BTreeMap<String, u32> = BTreeMap::new();
for (k, v) in [("zeta", 5u32), ("alpha", 1), ("delta", 4), ("beta", 2)] {
let _ = h.insert(k.into(), v);
let _ = b.insert(k.into(), v);
}
assert_eq!(encode(&h).unwrap(), encode(&b).unwrap());
}
#[cfg(feature = "std")]
#[test]
fn hashmap_insertion_order_independent() {
let mut a: HashMap<u32, u32> = HashMap::new();
let _ = a.insert(1, 10);
let _ = a.insert(2, 20);
let _ = a.insert(3, 30);
let mut b: HashMap<u32, u32> = HashMap::new();
let _ = b.insert(3, 30);
let _ = b.insert(1, 10);
let _ = b.insert(2, 20);
assert_eq!(encode(&a).unwrap(), encode(&b).unwrap());
}
#[test]
fn collection_with_hostile_element_count_is_rejected() {
let bytes: [u8; 10] = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01];
let err = decode::<Vec<u32>>(&bytes).expect_err("hostile count");
assert!(matches!(err, SerialError::InvalidLength { .. }));
}
}