1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//! # Zende
//!
//! Zende is a minimal library for the ***z***igzag ***en***coding and
//! ***de***coding of integers.

#![doc(html_root_url = "https://docs.rs/zende/0.1.3")]

use std::mem;

const BITS_PER_BYTE: usize = 8;

/// An extension trait implemented for all Rust integers to encode and decode
/// between signed and unsigned variants using
/// [zigzag encoding][wiki].
///
/// # Examples
///
/// Encoding a signed integer:
///
/// ```
/// use zende::Zigzag;
///
/// assert_eq!(0i8.zigzag(), 0u8);
/// assert_eq!((-1i8).zigzag(), 1u8);
/// assert_eq!(1i8.zigzag(), 2u8);
///
/// assert_eq!(i8::MIN.zigzag(), u8::MAX);
/// assert_eq!(i16::MIN.zigzag(), u16::MAX);
/// assert_eq!(i32::MIN.zigzag(), u32::MAX);
/// assert_eq!(i64::MIN.zigzag(), u64::MAX);
/// assert_eq!(i128::MIN.zigzag(), u128::MAX);
///
/// assert_eq!(isize::MIN.zigzag(), usize::MAX);
/// ```
///
/// Decoding an unsigned integer:
///
/// ```
/// use zende::Zigzag;
///
/// assert_eq!(0u8.zigzag(), 0i8);
/// assert_eq!(1u8.zigzag(), -1i8);
/// assert_eq!(2u8.zigzag(), 1i8);
///
/// assert_eq!(u8::MAX.zigzag(), i8::MIN);
/// assert_eq!(u16::MAX.zigzag(), i16::MIN);
/// assert_eq!(u32::MAX.zigzag(), i32::MIN);
/// assert_eq!(u64::MAX.zigzag(), i64::MIN);
/// assert_eq!(u128::MAX.zigzag(), i128::MIN);
///
/// assert_eq!(usize::MAX.zigzag(), isize::MIN);
/// ```
///
/// [wiki]: https://en.wikipedia.org/wiki/Variable-length_quantity#Zigzag_encoding
pub trait Zigzag<T>: private::Sealed {
    /// Converts signed integers to unsigned integers and vice versa using
    /// [zigzag encoding][wiki].
    ///
    /// # Examples
    ///
    /// ```
    /// use zende::Zigzag;
    ///
    /// assert_eq!(0i8.zigzag(), 0u8);
    /// assert_eq!((-1i8).zigzag(), 1u8);
    /// assert_eq!(1i8.zigzag(), 2u8);
    ///
    /// assert_eq!(0u8.zigzag(), 0i8);
    /// assert_eq!(1u8.zigzag(), -1i8);
    /// assert_eq!(2u8.zigzag(), 1i8);
    /// ```
    ///
    /// [wiki]: https://en.wikipedia.org/wiki/Variable-length_quantity#Zigzag_encoding
    fn zigzag(self) -> T;
}

macro_rules! impl_zigzag {
    ($(($signed:ty, $unsigned:ty)),*) => {
        $(
            impl Zigzag<$unsigned> for $signed {
                #[inline]
                fn zigzag(self) -> $unsigned {
                    const TYPE_BITS: usize = mem::size_of::<$unsigned>() * BITS_PER_BYTE;
                    (self >> TYPE_BITS - 1) as $unsigned ^ (self << 1) as $unsigned
                }
            }

            impl Zigzag<$signed> for $unsigned {
                #[inline]
                fn zigzag(self) -> $signed {
                    (self >> 1) as $signed ^ -((self & 1) as $signed)
                }
            }
        )*
    }
}

impl_zigzag!(
    (i8, u8),
    (i16, u16),
    (i32, u32),
    (i64, u64),
    (i128, u128),
    (isize, usize)
);

mod private {
    pub trait Sealed {}

    macro_rules! impl_sealed {
        ($($t:ty),*) => {
            $(
                impl Sealed for $t {}
            )*
        }
    }

    impl_sealed!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize);
}