varint_rs/
zigzag.rs

1//! Zigzag encoding is an alternative way of encoding negative numbers.
2//! 
3//! In zigzag encoding, the least-significant bit is used to represent the sign.
4//! Counting up alternates between non-negative and negative numbers as the LSB
5//! switches between `0` and `1`.
6//! 
7//! ## Example
8//! ```
9//! // to allow the use of the `Zigzag::zigzag` function
10//! use varint_rs::zigzag::Zigzag;
11//! 
12//! // create an i32 set to `300`
13//! let number: i32 = 300;
14//! // encode the i32 into a u32
15//! let encoded: u32 = number.zigzag();
16//! // decode the u32 into an i32
17//! let decoded: i32 = encoded.zigzag();
18//! ```
19
20/// The `Zigzag` trait enables zigzag encoding for a type.
21/// 
22/// This is pre-implemented on the primitive signed and unsigned integer types.
23pub trait Zigzag<T> {
24  fn zigzag(&self) -> T;
25}
26
27impl Zigzag<u8> for i8 {
28  /// Encodes an i8 as a zigzagged u8.
29  #[inline]
30  fn zigzag(&self) -> u8 {
31    ((self << 1) ^ (self >> 7)) as u8
32  }
33}
34
35impl Zigzag<i8> for u8 {
36  /// Decodes a u8 as a zigzagged i8.
37  #[inline]
38  fn zigzag(&self) -> i8 {
39    ((self >> 1) as i8) ^ (-((self & 1) as i8))
40  }
41}
42
43impl Zigzag<u16> for i16 {
44  /// Encodes an i16 as a zigzagged u16.
45  #[inline]
46  fn zigzag(&self) -> u16 {
47    ((self << 1) ^ (self >> 15)) as u16
48  }
49}
50
51impl Zigzag<i16> for u16 {
52  /// Decodes a u16 as a zigzagged i16.
53  #[inline]
54  fn zigzag(&self) -> i16 {
55    ((self >> 1) as i16) ^ (-((self & 1) as i16))
56  }
57}
58
59impl Zigzag<u32> for i32 {
60  /// Encodes an i32 as a zigzagged u32.
61  #[inline]
62  fn zigzag(&self) -> u32 {
63    ((self << 1) ^ (self >> 31)) as u32
64  }
65}
66
67impl Zigzag<i32> for u32 {
68  /// Decodes a u32 as a zigzagged i32.
69  #[inline]
70  fn zigzag(&self) -> i32 {
71    ((self >> 1) as i32) ^ (-((self & 1) as i32))
72  }
73}
74
75impl Zigzag<u64> for i64 {
76  /// Encodes an i64 as a zigzagged u64.
77  #[inline]
78  fn zigzag(&self) -> u64 {
79    ((self << 1) ^ (self >> 63)) as u64
80  }
81}
82
83impl Zigzag<i64> for u64 {
84  /// Decodes a u64 as a zigzagged i64.
85  #[inline]
86  fn zigzag(&self) -> i64 {
87    ((self >> 1) as i64) ^ (-((self & 1) as i64))
88  }
89}
90
91impl Zigzag<u128> for i128 {
92  /// Encodes an i128 as a zigzagged u128.
93  #[inline]
94  fn zigzag(&self) -> u128 {
95    ((self << 1) ^ (self >> 127)) as u128
96  }
97}
98
99impl Zigzag<i128> for u128 {
100  /// Decodes a u128 as a zigzagged i128.
101  #[inline]
102  fn zigzag(&self) -> i128 {
103    ((self >> 1) as i128) ^ (-((self & 1) as i128))
104  }
105}
106
107impl Zigzag<usize> for isize {
108  /// Encodes an isize as a zigzagged usize.
109  #[inline]
110  fn zigzag(&self) -> usize {
111    ((self << 1) ^ (self >> std::mem::size_of::<usize>()-1)) as usize
112  }
113}
114
115impl Zigzag<isize> for usize {
116  /// Decodes a usize as a zigzagged isize.
117  #[inline]
118  fn zigzag(&self) -> isize {
119    ((self >> 1) as isize) ^ (-((self & 1) as isize))
120  }
121}