serial_traits 1.1.2

A trait that allows you to serialize to and parse from Vec<u8> buffers. Comes with implementations for primitive types, String and generic collection types (if the item type implements the trait too.)
Documentation
#[cfg(test)]
mod tests {
    use crate::Serializable;
    use rand;
    use rand::Rng;

    macro_rules! test_primitive_value {
        ($name:tt, $primitive:ty) => {
            #[test]
            fn $name() {
                let value = rand::rng().random::<$primitive>();

                let mut buffer = value.serialize();
                let result = <$primitive>::parse(&mut buffer);

                match result {
                    Some(outcome) => assert_eq!(value, outcome),
                    None => panic!(),
                }
            }
        };
    }

    // test_type!(test_f16, f16); // halfs in rust are unstable, uncomment when they're stable
    test_primitive_value!(test_f32, f32);
    test_primitive_value!(test_f64, f64);
    // test_type!(test_f128, f128); // quadruples in rust are unstable, uncomment when they're stable

    test_primitive_value!(test_u8, u8);
    test_primitive_value!(test_u16, u16);
    test_primitive_value!(test_u32, u32);
    test_primitive_value!(test_u64, u64);
    test_primitive_value!(test_u128, u128);

    test_primitive_value!(test_i8, i8);
    test_primitive_value!(test_i16, i16);
    test_primitive_value!(test_i32, i32);
    test_primitive_value!(test_i64, i64);
    test_primitive_value!(test_i128, i128);

    test_primitive_value!(test_char, char);
    test_primitive_value!(test_bool, bool);

    macro_rules! test_primitive_size {
        ($name:tt, $primitive:ty, $rng_type:ty) => {
            #[test]
            fn $name() {
                let value = rand::rng().random::<$rng_type>() as $primitive;

                let mut buffer = value.serialize();
                let result = <$primitive>::parse(&mut buffer);

                match result {
                    Some(outcome) => assert_eq!(value, outcome),
                    None => panic!(),
                }
            }
        };
    }

    test_primitive_size!(test_usize_16, usize, u8);
    test_primitive_size!(test_isize_16, isize, u8);
    test_primitive_size!(test_usize_64, usize, u64);
    test_primitive_size!(test_isize_64, isize, u64);
    test_primitive_size!(test_usize_128, usize, u128);
    test_primitive_size!(test_isize_128, isize, u128);

    macro_rules! test_primitive_array {
        ($name:tt, $primitive:ty, $count:expr) => {
            #[test]
            fn $name() {
                let mut value = [<$primitive>::MAX; $count];
                let mut rng = rand::rng();
                for i in 0..$count {
                    value[i] = rng.random::<$primitive>();
                }

                let mut buffer = value.serialize();
                let result = <[$primitive; $count]>::parse(&mut buffer);

                match result {
                    Some(outcome) => assert_eq!(value, outcome),
                    None => panic!(),
                }
            }
        };
    }

    test_primitive_array!(test_i64_89, i64, 89);
    test_primitive_array!(test_i64_3, i64, 3);

    test_primitive_array!(test_f32_89, f32, 89);
    test_primitive_array!(test_f32_3, f32, 3);

    test_primitive_array!(test_u16_89, u16, 89);
    test_primitive_array!(test_u16_3, u16, 3);

    macro_rules! test_primitive_array_jagged {
        ($name:tt, $primitive:ty, $count_inner:expr, $count_outer:expr) => {
            #[test]
            fn $name() {
                let mut value = [[<$primitive>::MAX; $count_inner]; $count_outer];
                let mut rng = rand::rng();
                for i in 0..$count_outer {
                    for j in 0..$count_inner {
                        value[i][j] = rng.random::<$primitive>();
                    }
                }

                let mut buffer = value.serialize();
                let result = <[[$primitive; $count_inner]; $count_outer]>::parse(&mut buffer);

                match result {
                    Some(outcome) => assert_eq!(value, outcome),
                    None => panic!(),
                }
            }
        };
    }

    test_primitive_array_jagged!(test_i64_12_32, i64, 12, 32);
    test_primitive_array_jagged!(test_i64_6_4, i64, 6, 4);

    test_primitive_array_jagged!(test_f32_12_32, f32, 12, 32);
    test_primitive_array_jagged!(test_f32_6_4, f32, 6, 4);

    test_primitive_array_jagged!(test_u16_12_32, u16, 12, 32);
    test_primitive_array_jagged!(test_u16_6_4, u16, 6, 4);

    macro_rules! test_tuple {
		($name:ident, $( $ntyp:ty, )* ) => {
            #[test]
            fn $name() {
                let mut rng = rand::rng();

                let value = ( $( rng.random::<$ntyp>() ),* );
                let mut buffer = value.serialize();
				let result = <( $( $ntyp ),* )>::parse(&mut buffer);

                match result {
                    Some(outcome) => assert_eq!(value, outcome),
                    None => panic!(),
                }
            }
		};
	}

    test_tuple!(
        test_tuple_12,
        char,
        u8,
        u16,
        u32,
        u64,
        u128,
        i8,
        i16,
        i32,
        i64,
        i128,
        bool,
    );
    test_tuple!(test_tuple_8, char, u8, u16, f32, f64, u128, i8, i16,);
    test_tuple!(test_tuple_4, i32, u8, u16, u32,);
    test_tuple!(test_tuple_2, f32, u8,);
}