tiny_varint/zigzag.rs
1use crate::error::Error;
2use crate::traits::VarInt;
3use crate::encoding::{encode, decode};
4
5/// Trait for ZigZag encoding
6pub trait ZigZag: Copy {
7 /// Associated unsigned type
8 type Unsigned: VarInt;
9
10 /// Encode to unsigned integer using ZigZag
11 fn zigzag_encode(self) -> Self::Unsigned;
12
13 /// Decode from unsigned integer encoded with ZigZag
14 fn zigzag_decode(value: Self::Unsigned) -> Self;
15}
16
17// Implement ZigZag for all signed integer types
18macro_rules! impl_zigzag {
19 ($signed:ty, $unsigned:ty, $bits:expr) => {
20 impl ZigZag for $signed {
21 type Unsigned = $unsigned;
22
23 #[inline]
24 fn zigzag_encode(self) -> Self::Unsigned {
25 ((self << 1) ^ (self >> ($bits - 1))) as $unsigned
26 }
27
28 #[inline]
29 fn zigzag_decode(value: Self::Unsigned) -> Self {
30 ((value >> 1) as Self) ^ (-((value & 1) as Self))
31 }
32 }
33 };
34}
35
36// Implement for all signed integer types
37impl_zigzag!(i8, u8, 8);
38impl_zigzag!(i16, u16, 16);
39impl_zigzag!(i32, u32, 32);
40impl_zigzag!(i64, u64, 64);
41impl_zigzag!(i128, u128, 128);
42
43/// Encode a signed integer using ZigZag, then encode it as a varint
44///
45/// Returns the number of bytes written
46///
47/// # Arguments
48/// * `value` - The signed integer to encode
49/// * `buf` - The output buffer to write to
50///
51/// # Errors
52/// * Returns `Error::BufferTooSmall` if the buffer is too small
53pub fn encode_zigzag<T: ZigZag>(value: T, buf: &mut [u8]) -> Result<usize, Error> {
54 let zigzag = value.zigzag_encode();
55 encode(zigzag, buf)
56}
57
58/// Decode a signed integer from a varint-encoded zigzag value
59///
60/// Returns the decoded value and the number of bytes read
61///
62/// # Arguments
63/// * `buf` - The input buffer containing the zigzag varint encoded value
64///
65/// # Errors
66/// * Returns `Error::InputTooShort` if the input buffer is insufficient
67/// * Returns `Error::InvalidEncoding` if the varint encoding is invalid
68/// * Returns `Error::Overflow` if an overflow occurs during decoding
69pub fn decode_zigzag<T: ZigZag>(buf: &[u8]) -> Result<(T, usize), Error> {
70 let (unsigned, bytes_read) = decode::<T::Unsigned>(buf)?;
71 Ok((T::zigzag_decode(unsigned), bytes_read))
72}