use core::marker::PhantomData;
use crate::{
DecodePolicy,
Leb128Codec,
Leb128DecodeError,
NonStrict,
};
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct ZigZagCodec<T, P = NonStrict> {
marker: PhantomData<fn() -> (T, P)>,
}
macro_rules! impl_zig_zag_codec {
($signed:ty, $unsigned:ty, $shift:expr) => {
impl<P> ZigZagCodec<$signed, P>
where
P: DecodePolicy,
{
pub const REQUIRED_MIN_BUFFER_LEN: usize = Leb128Codec::<$unsigned, NonStrict>::REQUIRED_MIN_BUFFER_LEN;
#[inline(always)]
pub unsafe fn read_unchecked(input: &[u8], index: usize) -> Result<($signed, usize), Leb128DecodeError> {
let (encoded, consumed) = unsafe { Leb128Codec::<$unsigned, P>::read_unchecked(input, index)? };
let value = ((encoded >> 1) as $signed) ^ (-((encoded & 1) as $signed));
Ok((value, consumed))
}
#[inline(always)]
pub(crate) unsafe fn read_available_unchecked(
input: &[u8],
index: usize,
available: usize,
) -> Result<Option<($signed, usize)>, (Leb128DecodeError, usize)> {
let result = unsafe { Leb128Codec::<$unsigned, P>::read_available_unchecked(input, index, available)? };
Ok(result.map(|(encoded, consumed)| {
let value = ((encoded >> 1) as $signed) ^ (-((encoded & 1) as $signed));
(value, consumed)
}))
}
#[inline(always)]
pub unsafe fn write_unchecked(output: &mut [u8], index: usize, value: $signed) -> usize {
let encoded = ((value as $unsigned) << 1) ^ ((value >> $shift) as $unsigned);
unsafe { Leb128Codec::<$unsigned, NonStrict>::write_unchecked(output, index, encoded) }
}
}
};
}
impl_zig_zag_codec!(i8, u8, 7);
impl_zig_zag_codec!(i16, u16, 15);
impl_zig_zag_codec!(i32, u32, 31);
impl_zig_zag_codec!(i64, u64, 63);
impl_zig_zag_codec!(i128, u128, 127);
impl_zig_zag_codec!(isize, usize, isize::BITS - 1);