bilrost 0.1014.2

A compact protobuf-like serializer and deserializer for the Rust Language.
Documentation
use bytes::{Buf, BufMut};

use crate::buf::ReverseBuf;
use crate::encoding::{
    delegate_value_encoding, encoding_implemented_via_value_encoding,
    encoding_uses_base_empty_state, Canonicity, Capped, DecodeContext, DistinguishedValueDecoder,
    RestrictedDecodeContext, ValueDecoder, ValueEncoder, WireType, Wiretyped,
};
use crate::DecodeError;
use crate::DecodeErrorKind::{InvalidValue, Truncated};

pub struct Fixed;

encoding_uses_base_empty_state!(Fixed);
encoding_implemented_via_value_encoding!(Fixed);

/// Macros which emit implementations for fixed width numeric encoding.
macro_rules! fixed_width_common {
    (
        $ty:ty,
        $wire_type:ident,
        $put:ident,
        $prepend:ident,
        $get:ident,
        get_value($value:ident) { $value_expr:expr },
        set_value($gotten_value:ident) $set_value_body:block
    ) => {
        impl Wiretyped<Fixed, $ty> for () {
            const WIRE_TYPE: WireType = WireType::$wire_type;
        }

        impl ValueEncoder<Fixed, $ty> for () {
            #[inline(always)]
            fn encode_value<B: BufMut + ?Sized>($value: &$ty, buf: &mut B) {
                buf.$put($value_expr);
            }

            #[inline(always)]
            fn prepend_value<B: ReverseBuf + ?Sized>($value: &$ty, buf: &mut B) {
                buf.$prepend($value_expr);
            }

            #[inline(always)]
            fn value_encoded_len(_value: &$ty) -> usize {
                WireType::$wire_type.fixed_size().unwrap()
            }
        }

        impl ValueDecoder<Fixed, $ty> for () {
            #[inline(always)]
            fn decode_value<B: Buf + ?Sized>(
                $value: &mut $ty,
                mut buf: Capped<B>,
                _ctx: DecodeContext,
            ) -> Result<(), DecodeError> {
                if buf.remaining_before_cap() < WireType::$wire_type.fixed_size().unwrap() {
                    return Err(DecodeError::new(Truncated));
                }
                let $gotten_value = buf.$get();
                $set_value_body
                Ok(())
            }
        }
    };
}

macro_rules! fixed_width_int {
    (
        $test_name:ident,
        $ty:ty,
        $wire_type:ident,
        $put:ident,
        $prepend:ident,
        $get:ident,
        get_value($value:ident) { $value_expr:expr },
        set_value($gotten_value:ident) $set_value_body:block
        $(, $($avoid_no_empty_state:tt)*)?
    ) => {
        fixed_width_common!(
            $ty,
            $wire_type,
            $put,
            $prepend,
            $get,
            get_value($value) { $value_expr },
            set_value($gotten_value) $set_value_body
        );
        delegate_value_encoding!(
            encoding (Fixed) borrows type ($ty) as owned including distinguished
        );

        impl DistinguishedValueDecoder<Fixed, $ty> for () {
            const CHECKS_EMPTY: bool = false;

            #[inline(always)]
            fn decode_value_distinguished<const ALLOW_EMPTY: bool>(
                value: &mut $ty,
                buf: Capped<impl Buf + ?Sized>,
                ctx: RestrictedDecodeContext,
            ) -> Result<Canonicity, DecodeError> {
                <() as ValueDecoder<Fixed, _>>::decode_value(value, buf, ctx.into_inner())?;
                Ok(Canonicity::Canonical)
            }
        }

        #[cfg(test)]
        mod $test_name {
            use crate::encoding::Fixed;

            crate::encoding::test::check_type_test!(
                Fixed,
                relaxed,
                $ty,
                WireType::$wire_type
                $(, $($avoid_no_empty_state)*)?
            );
            crate::encoding::test::check_type_test!(
                Fixed,
                distinguished,
                $ty,
                WireType::$wire_type
                $(, $($avoid_no_empty_state)*)?
            );
        }
    };
    (
        $test_name:ident,
        $ty:ty,
        $wire_type:ident,
        $put:ident,
        $prepend:ident,
        $get:ident
    ) => {
        fixed_width_int!(
            $test_name,
            $ty,
            $wire_type,
            $put,
            $prepend,
            $get,
            get_value(value) { *value },
            set_value(gotten_value) { *value = gotten_value; }
        );
    };
}

macro_rules! fixed_width_float {
    (
        $test_name:ident,
        $ty:ty,
        $wire_type:ident,
        $put:ident,
        $prepend:ident,
        $get:ident
    ) => {
        fixed_width_common!(
            $ty,
            $wire_type,
            $put,
            $prepend,
            $get,
            get_value(value) { *value },
            set_value(gotten_value) { *value = gotten_value; }
        );
        delegate_value_encoding!(encoding (Fixed) borrows type ($ty) as owned);

        #[cfg(test)]
        mod $test_name {
            use crate::encoding::Fixed;
            crate::encoding::test::check_type_test!(Fixed, relaxed, $ty, WireType::$wire_type);

            mod delegated_from_general {
                use crate::encoding::General;
                crate::encoding::test::check_type_test!(
                    General,
                    relaxed,
                    $ty,
                    WireType::$wire_type
                );
            }
        }
    };
}

macro_rules! fixed_width_array {
    ($test_name:ident, $N:literal, $wire_type:ident) => {
        delegate_value_encoding!(
            encoding (Fixed) borrows type ([u8; $N]) as owned including distinguished
        );

        impl Wiretyped<Fixed, [u8; $N]> for () {
            const WIRE_TYPE: WireType = WireType::$wire_type;
        }

        impl ValueEncoder<Fixed, [u8; $N]> for () {
            #[inline(always)]
            fn encode_value<B: BufMut + ?Sized>(value: &[u8; $N], mut buf: &mut B) {
                (&mut buf).put(value.as_slice());
            }

            #[inline(always)]
            fn prepend_value<B: ReverseBuf + ?Sized>(value: &[u8; $N], buf: &mut B) {
                buf.prepend_slice(value.as_slice());
            }

            #[inline(always)]
            fn value_encoded_len(_value: &[u8; $N]) -> usize {
                $N
            }
        }

        impl ValueDecoder<Fixed, [u8; $N]> for () {
            #[inline(always)]
            fn decode_value<B: Buf + ?Sized>(
                value: &mut [u8; $N],
                mut buf: Capped<B>,
                _ctx: DecodeContext,
            ) -> Result<(), DecodeError> {
                if buf.remaining() < $N {
                    return Err(DecodeError::new(Truncated));
                }
                buf.copy_to_slice(value.as_mut_slice());
                Ok(())
            }
        }

        impl DistinguishedValueDecoder<Fixed, [u8; $N]> for () {
            const CHECKS_EMPTY: bool = false;

            #[inline(always)]
            fn decode_value_distinguished<const ALLOW_EMPTY: bool>(
                value: &mut [u8; $N],
                buf: Capped<impl Buf + ?Sized>,
                ctx: RestrictedDecodeContext,
            ) -> Result<Canonicity, DecodeError> {
                <() as ValueDecoder<Fixed, _>>::decode_value(value, buf, ctx.into_inner())?;
                Ok(Canonicity::Canonical)
            }
        }

        #[cfg(test)]
        mod $test_name {
            use crate::encoding::Fixed;
            crate::encoding::test::check_type_test!(Fixed, relaxed, [u8; $N], WireType::$wire_type);
            crate::encoding::test::check_type_test!(
                Fixed,
                distinguished,
                [u8; $N],
                WireType::$wire_type
            );
        }
    };
}

fixed_width_float!(
    f32,
    f32,
    ThirtyTwoBit,
    put_f32_le,
    prepend_f32_le,
    get_f32_le
);
fixed_width_float!(
    f64,
    f64,
    SixtyFourBit,
    put_f64_le,
    prepend_f64_le,
    get_f64_le
);
fixed_width_int!(
    fixed_u32,
    u32,
    ThirtyTwoBit,
    put_u32_le,
    prepend_u32_le,
    get_u32_le
);
fixed_width_int!(
    fixed_nonzerou32,
    core::num::NonZeroU32,
    ThirtyTwoBit,
    put_u32_le,
    prepend_u32_le,
    get_u32_le,
    get_value(value) { value.get() },
    set_value(gotten_value) {
        *value = core::num::NonZeroU32::new(gotten_value)
            .ok_or_else(|| DecodeError::new(InvalidValue))?;
    },
    has no empty state
);
fixed_width_int!(
    fixed_u64,
    u64,
    SixtyFourBit,
    put_u64_le,
    prepend_u64_le,
    get_u64_le
);
fixed_width_int!(
    fixed_nonzerou64,
    core::num::NonZeroU64,
    SixtyFourBit,
    put_u64_le,
    prepend_u64_le,
    get_u64_le,
    get_value(value) { value.get() },
    set_value(gotten_value) {
        *value = core::num::NonZeroU64::new(gotten_value)
            .ok_or_else(|| DecodeError::new(InvalidValue))?;
    },
    has no empty state
);
fixed_width_int!(
    fixed_i32,
    i32,
    ThirtyTwoBit,
    put_i32_le,
    prepend_i32_le,
    get_i32_le
);
fixed_width_int!(
    fixed_nonzeroi32,
    core::num::NonZeroI32,
    ThirtyTwoBit,
    put_i32_le,
    prepend_i32_le,
    get_i32_le,
    get_value(value) { value.get() },
    set_value(gotten_value) {
        *value = core::num::NonZeroI32::new(gotten_value)
            .ok_or_else(|| DecodeError::new(InvalidValue))?;
    },
    has no empty state
);
fixed_width_int!(
    fixed_i64,
    i64,
    SixtyFourBit,
    put_i64_le,
    prepend_i64_le,
    get_i64_le
);
fixed_width_int!(
    fixed_nonzeroi64,
    core::num::NonZeroI64,
    SixtyFourBit,
    put_i64_le,
    prepend_i64_le,
    get_i64_le,
    get_value(value) { value.get() },
    set_value(gotten_value) {
        *value = core::num::NonZeroI64::new(gotten_value)
            .ok_or_else(|| DecodeError::new(InvalidValue))?;
    },
    has no empty state
);
fixed_width_array!(u8_4, 4, ThirtyTwoBit);
fixed_width_array!(u8_8, 8, SixtyFourBit);