serialization 0.2.12

encode and decode your struct
Documentation
use std::mem::{ManuallyDrop, MaybeUninit};

use concat_idents_bruce0203::concat_idents;

#[cfg_attr(feature = "fast_binary_format", const_trait)]
pub trait CheckPrimitiveTypeSize {
    fn is_sized<T: 'static>() -> bool {
        false
    }
}

pub trait BinaryEncoder {
    fn skip_bytes(&mut self, len: usize);
    fn write_bytes(&mut self, data: &[u8]) -> Result<(), ()>;
}

pub trait BinaryDecoder {
    fn skip_bytes(&mut self, len: usize);
    fn read_bytes(&mut self, len: usize) -> Result<&[u8], ()>;
}

pub trait Encode {
    fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), E::Error>;
}

pub trait Decode: Sized {
    fn decode<D: Decoder>(decoder: &mut D, place: &mut MaybeUninit<Self>) -> Result<(), D::Error>;

    fn decode_placed<D: Decoder>(decoder: &mut D) -> Result<Self, D::Error> {
        let mut place: MaybeUninit<Self> = unsafe { MaybeUninit::uninit().assume_init() };
        Self::decode(decoder, &mut place)?;
        Ok(unsafe { place.assume_init() })
    }
}

pub trait CompositeEncoder: BinaryEncoder {
    type Error;
    fn encode_element<E: Encode>(&mut self, v: &E) -> Result<(), Self::Error>;
    fn end(&mut self) -> Result<(), Self::Error>;
}

macro_rules! encode_value {
    ($($type:ty),*) => {$(
        concat_idents!(fn_name = encode_, $type, {
            fn fn_name(&mut self, v: $type) -> Result<(), Self::Error>;
        });
    )*};
}

macro_rules! decode_value {
    ($($type:ty),*) => {$(
        concat_idents!(fn_name = decode_, $type, {
            fn fn_name(&mut self, place: &mut MaybeUninit<$type>) -> Result<(), Self::Error>;
        });
    )*};
}

macro_rules! declare_encoder_supertrait {
    ($($value:ident),*) => {
        #[cfg_attr(feature = "fast_binary_format", const_trait)]
        pub trait Encoder: Sized + BinaryEncoder $(+ const $value)* {
            type Error: EncodeError;
            type TupleEncoder: CompositeEncoder<Error = Self::Error>;
            type StructEncoder: CompositeEncoder<Error = Self::Error>;
            type SequenceEncoder: CompositeEncoder<Error = Self::Error>;

            encode_value!(
                bool, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64
            );

            fn encode_tuple(&mut self) -> Result<&mut Self::TupleEncoder, Self::Error>;
            fn encode_struct(&mut self) -> Result<&mut Self::StructEncoder, Self::Error>;
            fn encode_seq(&mut self, len: usize) -> Result<&mut Self::SequenceEncoder, Self::Error>;

            fn encode_enum_variant_key(
                &mut self,
                enum_name: &'static str,
                variant_name: &'static str,
                variant_index: usize,
            ) -> Result<(), Self::Error>;

            fn encode_some(&mut self) -> Result<(), Self::Error>;
            fn encode_none(&mut self) -> Result<(), Self::Error>;

            fn encode_str(&mut self, v: &str) -> Result<(), Self::Error>;
            fn encode_bytes(&mut self, v: &[u8]) -> Result<(), Self::Error>;
            fn encode_var_i32(&mut self, v: i32) -> Result<(), Self::Error>;
        }
    };
}
#[cfg(feature = "fast_binary_format")]
declare_encoder_supertrait!(CheckPrimitiveTypeSize);
#[cfg(not(feature = "fast_binary_format"))]
declare_encoder_supertrait!();

pub trait CompositeDecoder: BinaryDecoder + Sized {
    type Error;
    fn decode_element<D: Decode>(&mut self, place: &mut MaybeUninit<D>) -> Result<(), Self::Error>;
    fn end(&mut self) -> Result<(), Self::Error>;
}

pub enum EnumIdentifier {
    Name(&'static str),
    Index(usize),
}

pub trait EncodeError {
    fn not_enough_bytes_in_the_buffer() -> Self;
    fn too_large() -> Self;
    fn custom() -> Self;
}

pub trait DecodeError {
    fn not_enough_bytes_in_the_buffer() -> Self;
    fn too_large() -> Self;
    fn invalid_enum_variant_name() -> Self;
    fn invalid_enum_variant_index() -> Self;
    fn custom() -> Self;
    fn invalid_utf8() -> Self;
    fn nonmax_but_max() -> Self;
    fn nonzero_but_zero() -> Self;
}

macro_rules! declare_decoder_supertrait {
    ($($value:ident),*) => {
        #[cfg_attr(feature = "fast_binary_format", const_trait)]
        pub trait Decoder: Sized + BinaryDecoder $(+ const $value)* {
            type Error: DecodeError;
            type TupleDecoder: CompositeDecoder< Error = Self::Error>;
            type StructDecoder: CompositeDecoder< Error = Self::Error>;
            type SequenceDecoder: CompositeDecoder< Error = Self::Error>;

            decode_value!(bool, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64);

            fn decode_str(&mut self, place: &mut MaybeUninit<& str>) -> Result<(), Self::Error>;
            fn decode_bytes(&mut self) -> Result<&[u8], Self::Error>;
            fn decode_var_i32(&mut self, place: &mut MaybeUninit<i32>) -> Result<(), Self::Error>;

            fn decode_tuple(&mut self) -> Result<&mut Self::TupleDecoder, Self::Error>;
            fn decode_struct(&mut self) -> Result<&mut Self::StructDecoder, Self::Error>;
            fn decode_seq(&mut self) -> Result<&mut Self::SequenceDecoder, Self::Error>;

            fn decode_seq_len(&mut self) -> Result<usize, Self::Error>;
            fn decode_enum(&mut self, enum_name: &'static str) -> Result<EnumIdentifier, Self::Error>;

            fn decode_is_some(&mut self) -> Result<bool, Self::Error>;
        }
    }
}

#[cfg(feature = "fast_binary_format")]
declare_decoder_supertrait!(CheckPrimitiveTypeSize);
#[cfg(not(feature = "fast_binary_format"))]
declare_decoder_supertrait!();