lilliput-core 0.1.0

Low-level implementation of encoding/decoding logic for lilliput format
Documentation
use crate::{
    sealed::Sealed,
    value::{SignedIntValue, UnsignedIntValue},
};

pub trait ToZigZag: Sized + Sealed {
    type ZigZag: Sized;

    fn to_zig_zag(self) -> Self::ZigZag;
}

pub trait FromZigZag: Sized + Sealed {
    type ZigZag: Sized;

    fn from_zig_zag(zig_zag: Self::ZigZag) -> Self;
}

macro_rules! impl_zig_zag {
    (signed: $s:ty, unsigned: $u:ty) => {
        impl ToZigZag for $s {
            type ZigZag = $u;

            fn to_zig_zag(self) -> Self::ZigZag {
                (self >> (Self::BITS as usize) - 1) as Self::ZigZag ^ (self << 1) as Self::ZigZag
            }
        }

        impl FromZigZag for $s {
            type ZigZag = $u;

            fn from_zig_zag(zig_zag: Self::ZigZag) -> Self {
                (zig_zag >> 1) as Self ^ -((zig_zag & 1) as Self)
            }
        }
    };
}

impl_zig_zag!(signed: i8, unsigned: u8);
impl_zig_zag!(signed: i16, unsigned: u16);
impl_zig_zag!(signed: i32, unsigned: u32);
impl_zig_zag!(signed: i64, unsigned: u64);
impl_zig_zag!(signed: isize, unsigned: usize);

impl ToZigZag for SignedIntValue {
    type ZigZag = UnsignedIntValue;

    fn to_zig_zag(self) -> Self::ZigZag {
        match self {
            Self::I8(signed) => UnsignedIntValue::U8(signed.to_zig_zag()),
            Self::I16(signed) => UnsignedIntValue::U16(signed.to_zig_zag()),
            Self::I32(signed) => UnsignedIntValue::U32(signed.to_zig_zag()),
            Self::I64(signed) => UnsignedIntValue::U64(signed.to_zig_zag()),
        }
    }
}

impl FromZigZag for SignedIntValue {
    type ZigZag = UnsignedIntValue;

    fn from_zig_zag(zig_zag: Self::ZigZag) -> Self {
        match zig_zag {
            UnsignedIntValue::U8(unsigned) => Self::I8(i8::from_zig_zag(unsigned)),
            UnsignedIntValue::U16(unsigned) => Self::I16(i16::from_zig_zag(unsigned)),
            UnsignedIntValue::U32(unsigned) => Self::I32(i32::from_zig_zag(unsigned)),
            UnsignedIntValue::U64(unsigned) => Self::I64(i64::from_zig_zag(unsigned)),
        }
    }
}

#[cfg(test)]
mod tests {
    use proptest::prelude::*;
    use test_log::test;

    use super::*;

    proptest! {
        #[test]
        fn zig_zag_roundtrip(before in i8::MIN..=i8::MAX) {
            let zig_zag = before.to_zig_zag();
            let after = i8::from_zig_zag(zig_zag);

            prop_assert_eq!(&before, &after);
        }
    }
}