elvwf

8 commits
Updated 2026-06-13 11:19:44
src
src/scalar.rs
use crate::raw;

pub use crate::error::ScalarError as Error;

impl From<core::num::TryFromIntError> for Error {
    fn from(_: core::num::TryFromIntError) -> Self {
        Error::VLETooBig
    }
}

pub struct Le;
pub struct Be;
pub struct Ne;
pub struct VLE;

pub fn len<T: Wired, C: Codec<T>>(this: T) -> usize {
    C::len(this)
}

pub fn decode<T: Wired, C: Codec<T>>(buf: &mut &[u8]) -> Result<T, Error> {
    C::read(buf)
}

pub fn encode<T: Wired, C: Codec<T>>(buf: &mut &mut [u8], this: T) -> Result<(), Error> {
    C::write(buf, this)
}

pub mod opt {
    use super::*;

    pub fn len<T: Wired, C: Codec<T>>(this: Option<T>) -> usize {
        if let Some(this) = this {
            C::len(this)
        } else {
            0
        }
    }

    pub fn decode<T: Wired, C: Codec<T>>(buf: &mut &[u8], cond: bool) -> Result<Option<T>, Error> {
        if cond {
            Ok(Some(C::read(buf)?))
        } else {
            Ok(None)
        }
    }

    pub fn encode<T: Wired, C: Codec<T>>(
        buf: &mut &mut [u8],
        this: Option<T>,
    ) -> Result<(), Error> {
        if let Some(this) = this {
            C::write(buf, this)?;
        }

        Ok(())
    }
}

pub mod cond {
    use super::*;

    pub fn len<T: Wired + PartialEq, C: Codec<T>>(this: T, skip_if: T) -> usize {
        if this != skip_if { C::len(this) } else { 0 }
    }

    pub fn encode<T: Wired + PartialEq, C: Codec<T>>(
        buf: &mut &mut [u8],
        this: T,
        skip_if: T,
    ) -> Result<(), Error> {
        if this != skip_if {
            C::write(buf, this)?;
        }

        Ok(())
    }

    pub fn decode<T: Wired, C: Codec<T>>(
        buf: &mut &[u8],
        cond: bool,
        skip_if: T,
    ) -> Result<T, Error> {
        if cond { Ok(C::read(buf)?) } else { Ok(skip_if) }
    }
}

pub(crate) use inner::{Codec, Wired};
pub(crate) mod inner {
    use super::*;

    pub trait Wired {}

    pub trait Codec<T>: Sized
    where
        T: Wired,
    {
        fn len(value: T) -> usize;
        fn read(buf: &mut &[u8]) -> Result<T, Error>;
        fn write(buf: &mut &mut [u8], value: T) -> Result<(), Error>;
    }

    impl VLE {
        const MAX: usize = Self::len(u64::MAX);

        const fn len(x: u64) -> usize {
            let bits = (u64::BITS - x.leading_zeros()) as usize;
            let n = (bits.saturating_sub(1) / 7) + 1;
            if n > 9 { 9 } else { n }
        }
    }

    impl Codec<u64> for VLE {
        fn len(value: u64) -> usize {
            VLE::len(value)
        }

        fn read(buf: &mut &[u8]) -> Result<u64, Error> {
            let mut v = 0;
            for i in 0..VLE::MAX {
                let b = raw::decode_single(buf)?;
                let shift = 7 * i;
                if i == VLE::MAX - 1 || (b & 0x80) == 0 {
                    v |= (b as u64) << shift;
                    return Ok(v);
                }
                v |= ((b & 0x7f) as u64) << shift;
            }
            unreachable!()
        }

        fn write(buf: &mut &mut [u8], mut value: u64) -> Result<(), Error> {
            raw::encode_with(buf, VLE::len(value), |out| {
                let mut len = 0;
                while value > 0x7f && len < VLE::MAX - 1 {
                    out[len] = (value as u8) | 0x80;
                    value >>= 7;
                    len += 1;
                }
                out[len] = value as u8;
                len + 1
            })?;

            Ok(())
        }
    }

    macro_rules! codec {
        (impl Codec<$int:ty> for $codec:ident { [$to:ident] [$from:ident] }) => {
            impl Codec<$int> for $codec {
                fn len(_: $int) -> usize {
                    core::mem::size_of::<$int>()
                }

                fn read(buf: &mut &[u8]) -> Result<$int, Error> {
                    Ok(<$int>::$from(
                        raw::decode(buf, core::mem::size_of::<$int>())?
                            .try_into()
                            .expect("Conversion from &[u8] failed even with correct size!"),
                    ))
                }

                fn write(buf: &mut &mut [u8], value: $int) -> Result<(), Error> { raw::encode(buf, &value.$to()).map_err(Error::from).map(|_| ()) }
            }
        };

        (belene: [$($v:ty)+]) => {
            $(
                codec!(impl Codec<$v> for Be { [to_be_bytes] [from_be_bytes] });
                codec!(impl Codec<$v> for Le { [to_le_bytes] [from_le_bytes] });
                codec!(impl Codec<$v> for Ne { [to_ne_bytes] [from_ne_bytes] });
            )+
        };

        (tag: [$($v:ty)+]) => {
            $(
                impl Wired for $v {}
            )+
        };

        (uints: [$($uint:ty)+], sints: [$($sint:ty)+], floats: [$($float:ty)+]) => {
            $(
                impl Codec<$uint> for VLE {
                    fn len(value: $uint) -> usize { <VLE as Codec<u64>>::len(value as u64) }
                    fn read(buf: &mut &[u8]) -> Result<$uint, Error> { <VLE as Codec<u64>>::read(buf).map(<$uint>::try_from).map(|ok| ok.map_err(Error::from)).flatten() }
                    fn write(buf: &mut &mut [u8], value: $uint) -> Result<(), Error> { <VLE as Codec<u64>>::write(buf, value as u64, ) }
                }
            )+

            codec!(belene: [$($uint)+ u64 $($sint)+ $($float)+]);
            codec!(tag: [$($uint)+ u64 $($sint)+ $($float)+]);
        };
    }

    codec!(uints: [u8 u16 u32 usize], sints: [i8 i16 i32 i64 isize], floats: [f32 f64]);

    impl Wired for () {}

    impl Codec<()> for Be {
        fn len(_: ()) -> usize {
            0
        }

        fn read(_: &mut &[u8]) -> Result<(), Error> {
            Ok(())
        }
        fn write(_: &mut &mut [u8], _: ()) -> Result<(), Error> {
            Ok(())
        }
    }

    impl Codec<()> for Le {
        fn len(_: ()) -> usize {
            0
        }
        fn read(_: &mut &[u8]) -> Result<(), Error> {
            Ok(())
        }
        fn write(_: &mut &mut [u8], _: ()) -> Result<(), Error> {
            Ok(())
        }
    }

    impl Codec<()> for Ne {
        fn len(_: ()) -> usize {
            0
        }
        fn read(_: &mut &[u8]) -> Result<(), Error> {
            Ok(())
        }
        fn write(_: &mut &mut [u8], _: ()) -> Result<(), Error> {
            Ok(())
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn encoded<T: Wired + Copy, C: Codec<T>>(value: T) -> Vec<u8> {
        let mut storage = vec![0u8; C::len(value)];
        let mut buf: &mut [u8] = &mut storage;
        C::write(&mut buf, value).unwrap();
        assert!(buf.is_empty());
        storage
    }

    fn roundtrip<T, C>(value: T)
    where
        T: Wired + Copy + core::fmt::Debug + PartialEq,
        C: Codec<T>,
    {
        let bytes = encoded::<T, C>(value);
        assert_eq!(bytes.len(), C::len(value),);

        let mut slice: &[u8] = &bytes;
        let decoded = C::read(&mut slice).unwrap();
        assert_eq!(decoded, value);
        assert!(slice.is_empty());
    }

    macro_rules! fixed_roundtrip_tests {
        ($($name:ident: $ty:ty = [$($val:expr),+ $(,)?]),* $(,)?) => {
            $(
                mod $name {
                    use super::*;

                    #[test]
                    fn be_roundtrip() {
                        for v in [$($val as $ty),+] { roundtrip::<$ty, Be>(v); }
                    }

                    #[test]
                    fn le_roundtrip() {
                        for v in [$($val as $ty),+] { roundtrip::<$ty, Le>(v); }
                    }

                    #[test]
                    fn ne_roundtrip() {
                        for v in [$($val as $ty),+] { roundtrip::<$ty, Ne>(v); }
                    }
                }
            )*
        };
    }

    fixed_roundtrip_tests! {
        t_u8:    u8    = [0, 1, 0x7F, 0xFF],
        t_u16:   u16   = [0, 1, 0x1234, u16::MAX],
        t_u32:   u32   = [0, 0xDEAD_BEEF, u32::MAX],
        t_u64:   u64   = [0, 0x0123_4567_89AB_CDEF, u64::MAX],
        t_usize: usize = [0, 42, usize::MAX],
        t_i8:    i8    = [i8::MIN, -1, 0, 1, i8::MAX],
        t_i16:   i16   = [i16::MIN, -1, 0, 1, i16::MAX],
        t_i32:   i32   = [i32::MIN, -1, 0, 1, i32::MAX],
        t_i64:   i64   = [i64::MIN, -1, 0, 1, i64::MAX],
        t_isize: isize = [isize::MIN, -1, 0, 1, isize::MAX],
        t_f32:   f32   = [0.0, 1.5, -3.25, f32::MIN, f32::MAX],
        t_f64:   f64   = [0.0, 1.5, -3.25, f64::MIN, f64::MAX],
    }

    #[test]
    fn be_and_le_produce_reversed_bytes() {
        let value: u32 = 0x1122_3344;
        let be = encoded::<u32, Be>(value);
        let le = encoded::<u32, Le>(value);

        assert_eq!(be, [0x11, 0x22, 0x33, 0x44]);
        assert_eq!(le, [0x44, 0x33, 0x22, 0x11]);
    }

    #[test]
    fn fixed_decode_fails_on_short_buffer() {
        let bytes = [0u8; 2];
        let mut slice: &[u8] = &bytes;
        let res = <Be as Codec<u32>>::read(&mut slice);
        assert!(matches!(res, Err(Error::SourceTooSmall)));
    }

    #[test]
    fn fixed_encode_fails_on_short_buffer() {
        let mut storage = [0u8; 2];
        let mut buf: &mut [u8] = &mut storage;
        let res = <Be as Codec<u32>>::write(&mut buf, 0xDEAD_BEEF);
        assert!(matches!(res, Err(Error::PayloadTooBig)));
    }

    #[test]
    fn vle_len_follows_7_bit_groups() {
        assert_eq!(<VLE as Codec<u64>>::len(0), 1);
        assert_eq!(<VLE as Codec<u64>>::len(0x7F), 1);
        assert_eq!(<VLE as Codec<u64>>::len(0x80), 2);
        assert_eq!(<VLE as Codec<u64>>::len(0x3FFF), 2);
        assert_eq!(<VLE as Codec<u64>>::len(0x4000), 3);
        assert_eq!(<VLE as Codec<u64>>::len(u64::MAX), 9);
    }

    #[test]
    fn vle_encodes_small_value_in_one_byte() {
        assert_eq!(encoded::<u64, VLE>(0), vec![0b0000_0000]);
        assert_eq!(encoded::<u64, VLE>(1), vec![0b0000_0001]);
        assert_eq!(encoded::<u64, VLE>(0x7F), vec![0b0111_1111]);
    }

    #[test]
    fn vle_encodes_with_continuation_bit() {
        assert_eq!(encoded::<u64, VLE>(0x80), vec![0x80, 0x01]);
        assert_eq!(encoded::<u64, VLE>(0x3FFF), vec![0xFF, 0x7F]);
    }

    #[test]
    fn vle_roundtrip_boundary_values() {
        for v in [
            0u64,
            1,
            0x7F,
            0x80,
            0x3FFF,
            0x4000,
            u32::MAX as u64,
            u64::MAX,
        ] {
            roundtrip::<u64, VLE>(v);
        }
    }

    macro_rules! vle_uint_tests {
        ($($name:ident: $ty:ty),* $(,)?) => {
            $(
                #[test]
                fn $name() {
                    for v in [0 as $ty, 1, <$ty>::MAX / 2, <$ty>::MAX] {
                        roundtrip::<$ty, VLE>(v);
                    }
                }
            )*
        };
    }

    vle_uint_tests! {
        vle_roundtrip_u8: u8,
        vle_roundtrip_u16: u16,
        vle_roundtrip_u32: u32,
        vle_roundtrip_usize: usize,
    }

    #[test]
    fn vle_decode_fails_on_empty() {
        let mut slice: &[u8] = &[];
        let res = <VLE as Codec<u64>>::read(&mut slice);
        assert!(matches!(res, Err(Error::SourceTooSmall)));
    }

    #[test]
    fn vle_decode_fails_when_value_too_big_for_target() {
        let bytes = encoded::<u64, VLE>(u64::MAX);
        let mut slice: &[u8] = &bytes;
        let res = <VLE as Codec<u8>>::read(&mut slice);
        assert!(matches!(res, Err(Error::VLETooBig)));
    }

    #[test]
    fn vle_encode_fails_on_short_buffer() {
        let mut storage = [0u8; 1];
        let mut buf: &mut [u8] = &mut storage;

        let res = <VLE as Codec<u64>>::write(&mut buf, 0x80);
        assert!(matches!(res, Err(Error::RequestTooBig)));
    }

    #[test]
    fn unit_codec_is_zero_length() {
        assert_eq!(<Be as Codec<()>>::len(()), 0);
        assert_eq!(<Le as Codec<()>>::len(()), 0);
        assert_eq!(<Ne as Codec<()>>::len(()), 0);

        let mut storage = [0u8; 0];
        let mut buf: &mut [u8] = &mut storage;
        <Be as Codec<()>>::write(&mut buf, ()).unwrap();

        let mut slice: &[u8] = &[];
        <Be as Codec<()>>::read(&mut slice).unwrap();
    }

    #[test]
    fn opt_len_some_matches_codec_len() {
        let value: u32 = 0xDEAD_BEEF;
        assert_eq!(
            opt::len::<u32, Be>(Some(value)),
            <Be as Codec<u32>>::len(value)
        );
    }

    #[test]
    fn opt_len_none_is_zero() {
        assert_eq!(opt::len::<u32, Be>(None), 0);
        assert_eq!(opt::len::<u64, Le>(None), 0);
        assert_eq!(opt::len::<u64, VLE>(None), 0);
    }

    #[test]
    fn opt_encode_some_writes_bytes() {
        let value: u32 = 0x1122_3344;
        let mut storage = vec![0u8; opt::len::<u32, Be>(Some(value))];
        let mut buf: &mut [u8] = &mut storage;
        opt::encode::<u32, Be>(&mut buf, Some(value)).unwrap();
        assert!(buf.is_empty());
        assert_eq!(storage, [0x11, 0x22, 0x33, 0x44]);
    }

    #[test]
    fn opt_encode_none_writes_nothing() {
        let mut storage = [0u8; 0];
        let mut buf: &mut [u8] = &mut storage;
        opt::encode::<u32, Be>(&mut buf, None).unwrap();
        assert!(buf.is_empty());
    }

    #[test]
    fn opt_decode_cond_true_reads_value() {
        let value: u32 = 0xCAFE_BABE;
        let bytes = encoded::<u32, Be>(value);
        let mut slice: &[u8] = &bytes;
        let decoded = opt::decode::<u32, Be>(&mut slice, true).unwrap();
        assert_eq!(decoded, Some(value));
        assert!(slice.is_empty());
    }

    #[test]
    fn opt_decode_cond_false_returns_none_without_consuming() {
        let bytes = [0xAA, 0xBB, 0xCC, 0xDD];
        let mut slice: &[u8] = &bytes;
        let decoded = opt::decode::<u32, Be>(&mut slice, false).unwrap();
        assert_eq!(decoded, None);
        assert_eq!(slice.len(), 4);
    }

    #[test]
    fn opt_roundtrip_some() {
        let value: u64 = 0x0123_4567_89AB_CDEF;
        let mut storage = vec![0u8; opt::len::<u64, Le>(Some(value))];
        let mut buf: &mut [u8] = &mut storage;
        opt::encode::<u64, Le>(&mut buf, Some(value)).unwrap();
        assert!(buf.is_empty());

        let mut slice: &[u8] = &storage;
        let decoded = opt::decode::<u64, Le>(&mut slice, true).unwrap();
        assert_eq!(decoded, Some(value));
        assert!(slice.is_empty());
    }

    #[test]
    fn opt_roundtrip_none() {
        let storage: Vec<u8> = vec![];
        assert_eq!(opt::len::<u64, Le>(None), 0);

        let mut slice: &[u8] = &storage;
        let decoded = opt::decode::<u64, Le>(&mut slice, false).unwrap();
        assert_eq!(decoded, None);
    }

    #[test]
    fn opt_decode_fails_when_cond_true_but_buffer_empty() {
        let mut slice: &[u8] = &[];
        let res = opt::decode::<u32, Be>(&mut slice, true);
        assert!(matches!(res, Err(Error::SourceTooSmall)));
    }

    #[test]
    fn opt_vle_some_roundtrip() {
        let value: u64 = 0x4000;
        let mut storage = vec![0u8; opt::len::<u64, VLE>(Some(value))];
        let mut buf: &mut [u8] = &mut storage;
        opt::encode::<u64, VLE>(&mut buf, Some(value)).unwrap();

        let mut slice: &[u8] = &storage;
        let decoded = opt::decode::<u64, VLE>(&mut slice, true).unwrap();
        assert_eq!(decoded, Some(value));
    }

    #[test]
    fn cond_len_skips_when_equal_to_skip_if() {
        assert_eq!(cond::len::<u32, Be>(0, 0), 0);
        assert_eq!(cond::len::<u64, Le>(42, 42), 0);
    }

    #[test]
    fn cond_len_returns_codec_len_when_different() {
        assert_eq!(
            cond::len::<u32, Be>(0xDEAD_BEEF, 0),
            <Be as Codec<u32>>::len(0xDEAD_BEEF)
        );
        assert_eq!(
            cond::len::<u64, VLE>(0x4000, 0),
            <VLE as Codec<u64>>::len(0x4000)
        );
    }

    #[test]
    fn cond_encode_writes_when_different_from_skip_if() {
        let value: u32 = 0x1122_3344;
        let mut storage = vec![0u8; cond::len::<u32, Be>(value, 0)];
        let mut buf: &mut [u8] = &mut storage;
        cond::encode::<u32, Be>(&mut buf, value, 0).unwrap();
        assert!(buf.is_empty());
        assert_eq!(storage, [0x11, 0x22, 0x33, 0x44]);
    }

    #[test]
    fn cond_encode_skips_when_equal_to_skip_if() {
        let mut storage = [0u8; 0];
        let mut buf: &mut [u8] = &mut storage;
        cond::encode::<u32, Be>(&mut buf, 7, 7).unwrap();
        assert!(buf.is_empty());
    }

    #[test]
    fn cond_decode_cond_true_reads_value() {
        let value: u32 = 0xCAFE_BABE;
        let bytes = encoded::<u32, Be>(value);
        let mut slice: &[u8] = &bytes;
        let decoded = cond::decode::<u32, Be>(&mut slice, true, 0).unwrap();
        assert_eq!(decoded, value);
        assert!(slice.is_empty());
    }

    #[test]
    fn cond_decode_cond_false_returns_skip_if_without_consuming() {
        let bytes = [0xAA, 0xBB, 0xCC, 0xDD];
        let mut slice: &[u8] = &bytes;
        let decoded = cond::decode::<u32, Be>(&mut slice, false, 0xDEAD).unwrap();
        assert_eq!(decoded, 0xDEAD);
        assert_eq!(slice.len(), 4);
    }

    #[test]
    fn cond_roundtrip_when_value_differs() {
        let value: u64 = 0x0123_4567_89AB_CDEF;
        let skip_if: u64 = 0;
        let len = cond::len::<u64, Le>(value, skip_if);
        let mut storage = vec![0u8; len];
        let mut buf: &mut [u8] = &mut storage;
        cond::encode::<u64, Le>(&mut buf, value, skip_if).unwrap();
        assert!(buf.is_empty());

        let mut slice: &[u8] = &storage;
        let decoded = cond::decode::<u64, Le>(&mut slice, true, skip_if).unwrap();
        assert_eq!(decoded, value);
        assert!(slice.is_empty());
    }

    #[test]
    fn cond_roundtrip_when_value_equals_skip_if() {
        let value: u64 = 42;
        let skip_if: u64 = 42;
        let len = cond::len::<u64, Le>(value, skip_if);
        assert_eq!(len, 0);

        let mut storage = vec![0u8; len];
        let mut buf: &mut [u8] = &mut storage;
        cond::encode::<u64, Le>(&mut buf, value, skip_if).unwrap();
        assert!(buf.is_empty());

        let mut slice: &[u8] = &storage;
        let decoded = cond::decode::<u64, Le>(&mut slice, false, skip_if).unwrap();
        assert_eq!(decoded, skip_if);
    }

    #[test]
    fn cond_decode_fails_when_cond_true_but_buffer_empty() {
        let mut slice: &[u8] = &[];
        let res = cond::decode::<u32, Be>(&mut slice, true, 0);
        assert!(matches!(res, Err(Error::SourceTooSmall)));
    }

    #[test]
    fn cond_vle_roundtrip_when_differs() {
        let value: u64 = 0x4000;
        let skip_if: u64 = 0;
        let len = cond::len::<u64, VLE>(value, skip_if);
        let mut storage = vec![0u8; len];
        let mut buf: &mut [u8] = &mut storage;
        cond::encode::<u64, VLE>(&mut buf, value, skip_if).unwrap();

        let mut slice: &[u8] = &storage;
        let decoded = cond::decode::<u64, VLE>(&mut slice, true, skip_if).unwrap();
        assert_eq!(decoded, value);
    }

    #[test]
    fn cond_encode_skips_with_nonzero_skip_if() {
        let mut storage = [0u8; 0];
        let mut buf: &mut [u8] = &mut storage;
        cond::encode::<u32, Be>(&mut buf, 0xFFFF_FFFF, 0xFFFF_FFFF).unwrap();
        assert!(buf.is_empty());
    }
}