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
120
//! # Zende
//!
//! Zende is a minimal library for the ***z***igzag ***en***coding and
//! ***de***coding of integers.

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

use core::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);
}