#![no_std]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ZigZagError {
BufferTooSmall {
needed: usize,
actual: usize,
},
}
pub trait ZigZag {
type UInt;
fn zigzag_encode(value: Self) -> Self::UInt;
fn zigzag_decode(value: Self::UInt) -> Self;
fn zigzag_encode_slice(values: &[Self], out: &mut [Self::UInt])
where
Self: Sized + Copy
{
assert!(out.len() >= values.len(), "Output slice must be at least as large as input slice");
for (i, &value) in values.iter().enumerate() {
out[i] = Self::zigzag_encode(value);
}
}
fn zigzag_decode_slice(values: &[Self::UInt], out: &mut [Self])
where
Self: Sized + Copy,
Self::UInt: Copy
{
assert!(out.len() >= values.len(), "Output slice must be at least as large as input slice");
for (i, &value) in values.iter().enumerate() {
out[i] = Self::zigzag_decode(value);
}
}
fn try_zigzag_encode_slice(values: &[Self], out: &mut [Self::UInt]) -> Result<(), ZigZagError>
where
Self: Sized + Copy
{
if out.len() < values.len() {
return Err(ZigZagError::BufferTooSmall {
needed: values.len(),
actual: out.len(),
});
}
for (i, &value) in values.iter().enumerate() {
out[i] = Self::zigzag_encode(value);
}
Ok(())
}
fn try_zigzag_decode_slice(values: &[Self::UInt], out: &mut [Self]) -> Result<(), ZigZagError>
where
Self: Sized + Copy,
Self::UInt: Copy
{
if out.len() < values.len() {
return Err(ZigZagError::BufferTooSmall {
needed: values.len(),
actual: out.len(),
});
}
for (i, &value) in values.iter().enumerate() {
out[i] = Self::zigzag_decode(value);
}
Ok(())
}
}
pub fn zigzag_encode_iter<'a, T, I>(iter: I) -> impl Iterator<Item = T::UInt> + 'a
where
T: ZigZag + Copy + 'a,
I: Iterator<Item = &'a T> + 'a,
{
iter.map(|&value| T::zigzag_encode(value))
}
pub fn zigzag_decode_iter<'a, T, I>(iter: I) -> impl Iterator<Item = T> + 'a
where
T: ZigZag + Copy + 'a,
I: Iterator<Item = &'a T::UInt> + 'a,
T::UInt: Copy + 'a,
{
iter.map(|&value| T::zigzag_decode(value))
}
macro_rules! impl_zigzag {
($signed:ty, $unsigned:ty, $bits:expr) => {
impl ZigZag for $signed {
type UInt = $unsigned;
#[inline]
fn zigzag_encode(value: Self) -> Self::UInt {
((value << 1) ^ (value >> ($bits - 1))) as $unsigned
}
#[inline]
fn zigzag_decode(value: Self::UInt) -> Self {
((value >> 1) as Self) ^ (-((value & 1) as Self))
}
}
};
}
impl_zigzag!(i8, u8, 8);
impl_zigzag!(i16, u16, 16);
impl_zigzag!(i32, u32, 32);
impl_zigzag!(i64, u64, 64);
impl_zigzag!(i128, u128, 128);
#[cfg(test)]
extern crate std;
#[cfg(test)]
mod tests {
use super::*;
#[cfg(test)]
use std::vec::Vec;
#[test]
fn test_encode_decode_i32() {
assert_eq!(i32::zigzag_encode(0), 0u32);
assert_eq!(i32::zigzag_encode(-1), 1u32);
assert_eq!(i32::zigzag_encode(1), 2u32);
assert_eq!(i32::zigzag_encode(-2), 3u32);
assert_eq!(i32::zigzag_encode(i32::MAX), 4294967294u32);
assert_eq!(i32::zigzag_encode(i32::MIN), 4294967295u32);
for i in [-100, -10, -1, 0, 1, 10, 100].iter() {
let encoded = i32::zigzag_encode(*i);
let decoded = i32::zigzag_decode(encoded);
assert_eq!(*i, decoded);
}
}
#[test]
fn test_encode_decode_slice_i32() {
let values = [-100i32, -10, -1, 0, 1, 10, 100];
let mut encoded = [0u32; 7];
let mut decoded = [0i32; 7];
i32::zigzag_encode_slice(&values, &mut encoded);
assert_eq!(encoded[0], i32::zigzag_encode(-100));
assert_eq!(encoded[3], i32::zigzag_encode(0));
assert_eq!(encoded[6], i32::zigzag_encode(100));
i32::zigzag_decode_slice(&encoded, &mut decoded);
assert_eq!(values, decoded);
}
#[test]
fn test_try_encode_decode_slice() {
let values = [-100i32, -10, -1, 0, 1, 10, 100];
let mut encoded = [0u32; 7];
let result = i32::try_zigzag_encode_slice(&values, &mut encoded);
assert!(result.is_ok());
let mut decoded = [0i32; 7];
let result = i32::try_zigzag_decode_slice(&encoded, &mut decoded);
assert!(result.is_ok());
assert_eq!(values, decoded);
let mut small_encoded = [0u32; 3];
let result = i32::try_zigzag_encode_slice(&values, &mut small_encoded);
assert!(result.is_err());
if let Err(ZigZagError::BufferTooSmall { needed, actual }) = result {
assert_eq!(needed, 7);
assert_eq!(actual, 3);
} else {
panic!("Expected BufferTooSmall error");
}
let mut small_decoded = [0i32; 3];
let result = i32::try_zigzag_decode_slice(&encoded, &mut small_decoded);
assert!(result.is_err());
}
#[test]
fn test_encode_decode_i8() {
for i in i8::MIN..=i8::MAX {
let encoded = i8::zigzag_encode(i);
let decoded = i8::zigzag_decode(encoded);
assert_eq!(i, decoded);
}
}
#[test]
fn test_encode_decode_i16() {
for i in [-1000, -100, -1, 0, 1, 100, 1000].iter() {
let encoded = i16::zigzag_encode(*i);
let decoded = i16::zigzag_decode(encoded);
assert_eq!(*i, decoded);
}
}
#[test]
fn test_encode_decode_slice_all_types() {
let i8_values = [-100i8, -10, -1, 0, 1, 10, 100];
let mut i8_encoded = [0u8; 7];
let mut i8_decoded = [0i8; 7];
i8::zigzag_encode_slice(&i8_values, &mut i8_encoded);
i8::zigzag_decode_slice(&i8_encoded, &mut i8_decoded);
assert_eq!(i8_values, i8_decoded);
let i16_values = [-1000i16, -100, -10, 0, 10, 100, 1000];
let mut i16_encoded = [0u16; 7];
let mut i16_decoded = [0i16; 7];
i16::zigzag_encode_slice(&i16_values, &mut i16_encoded);
i16::zigzag_decode_slice(&i16_encoded, &mut i16_decoded);
assert_eq!(i16_values, i16_decoded);
let i64_values = [-1000000i64, -10000, -100, 0, 100, 10000, 1000000];
let mut i64_encoded = [0u64; 7];
let mut i64_decoded = [0i64; 7];
i64::zigzag_encode_slice(&i64_values, &mut i64_encoded);
i64::zigzag_decode_slice(&i64_encoded, &mut i64_decoded);
assert_eq!(i64_values, i64_decoded);
}
#[test]
fn test_zigzag_error() {
let error = ZigZagError::BufferTooSmall { needed: 10, actual: 5 };
assert_eq!(error.needed(), 10);
assert_eq!(error.actual(), 5);
}
#[test]
fn test_zigzag_encode_iter() {
let values = [-100i32, -10, -1, 0, 1, 10, 100];
let expected: Vec<u32> = values.iter()
.map(|&v| i32::zigzag_encode(v))
.collect();
let encoded: Vec<u32> = zigzag_encode_iter::<i32, _>(values.iter()).collect();
assert_eq!(encoded, expected);
let i8_values = [-100i8, -10, -1, 0, 1, 10, 100];
let i8_encoded: Vec<u8> = zigzag_encode_iter::<i8, _>(i8_values.iter()).collect();
for (i, &val) in i8_values.iter().enumerate() {
assert_eq!(i8_encoded[i], i8::zigzag_encode(val));
}
}
#[test]
fn test_zigzag_decode_iter() {
let encoded = [199u32, 19, 1, 0, 2, 20, 200];
let expected = [-100i32, -10, -1, 0, 1, 10, 100];
let decoded: Vec<i32> = zigzag_decode_iter::<i32, _>(encoded.iter()).collect();
assert_eq!(decoded, expected);
let i16_encoded = [1999u16, 199, 19, 1, 0, 2, 20, 200, 2000];
let i16_expected = [-1000i16, -100, -10, -1, 0, 1, 10, 100, 1000];
let i16_decoded: Vec<i16> = zigzag_decode_iter::<i16, _>(i16_encoded.iter()).collect();
assert_eq!(i16_decoded, i16_expected);
}
#[test]
fn test_iterator_based_round_trip() {
let original = [-1000i16, -100, -10, -1, 0, 1, 10, 100, 1000];
let encoded: Vec<u16> = zigzag_encode_iter::<i16, _>(original.iter()).collect();
let decoded: Vec<i16> = zigzag_decode_iter::<i16, _>(encoded.iter()).collect();
assert_eq!(original.to_vec(), decoded);
}
}
impl ZigZagError {
pub fn needed(&self) -> usize {
match self {
ZigZagError::BufferTooSmall { needed, .. } => *needed,
}
}
pub fn actual(&self) -> usize {
match self {
ZigZagError::BufferTooSmall { actual, .. } => *actual,
}
}
}