binary_codec/encoding/
zigzag.rs1pub trait ZigZag {
3 type Unsigned;
4
5 fn to_unsigned(self) -> Self::Unsigned;
7
8 fn to_signed(n: Self::Unsigned) -> Self;
10}
11
12impl ZigZag for i8 {
13 type Unsigned = u8;
14 fn to_unsigned(self) -> u8 {
15 ((self << 1) ^ (self >> 7)) as u8
16 }
17 fn to_signed(n: u8) -> i8 {
18 ((n >> 1) as i8) ^ -((n & 1) as i8)
19 }
20}
21
22impl ZigZag for i16 {
23 type Unsigned = u16;
24 fn to_unsigned(self) -> u16 {
25 ((self << 1) ^ (self >> 15)) as u16
26 }
27 fn to_signed(n: u16) -> i16 {
28 ((n >> 1) as i16) ^ -((n & 1) as i16)
29 }
30}
31
32impl ZigZag for i32 {
33 type Unsigned = u32;
34 fn to_unsigned(self) -> u32 {
35 ((self << 1) ^ (self >> 31)) as u32
36 }
37 fn to_signed(n: u32) -> i32 {
38 ((n >> 1) as i32) ^ -((n & 1) as i32)
39 }
40}
41
42impl ZigZag for i64 {
43 type Unsigned = u64;
44 fn to_unsigned(self) -> u64 {
45 ((self << 1) ^ (self >> 63)) as u64
46 }
47 fn to_signed(n: u64) -> i64 {
48 ((n >> 1) as i64) ^ -((n & 1) as i64)
49 }
50}
51
52impl ZigZag for i128 {
53 type Unsigned = u128;
54 fn to_unsigned(self) -> u128 {
55 ((self << 1) ^ (self >> 127)) as u128
56 }
57 fn to_signed(n: u128) -> i128 {
58 ((n >> 1) as i128) ^ -((n & 1) as i128)
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65 macro_rules! zigzag_test {
66 ($name:ident, $ty:ty, $unsigned:ty, $val:expr, $expected:expr) => {
67 #[test]
68 fn $name() {
69 let val: $ty = $val;
70 let encoded: $unsigned = val.to_unsigned();
71 assert_eq!(encoded, $expected, "ZigZag encoding failed for {}", val);
72 let decoded: $ty = <$ty>::to_signed(encoded);
73 assert_eq!(decoded, val, "ZigZag decoding failed for {}", val);
74 }
75 };
76 }
77
78 zigzag_test!(zigzag_i8_pos, i8, u8, 0b0000_0010, 0b0000_0100);
79 zigzag_test!(zigzag_i8_neg, i8, u8, -0b0000_0010, 0b0000_0011);
80
81 zigzag_test!(
82 zigzag_i16_pos,
83 i16,
84 u16,
85 0b0000_0000_0000_0010,
86 0b0000_0000_0000_0100
87 );
88 zigzag_test!(
89 zigzag_i16_neg,
90 i16,
91 u16,
92 -0b0000_0000_0000_0010,
93 0b0000_0000_0000_0011
94 );
95 zigzag_test!(
96 zigzag_i32_pos,
97 i32,
98 u32,
99 0b0000_0000_0000_0000_0000_0000_0000_0010,
100 0b0000_0000_0000_0000_0000_0000_0000_0100
101 );
102 zigzag_test!(
103 zigzag_i32_neg,
104 i32,
105 u32,
106 -0b0000_0000_0000_0000_0000_0000_0000_0010,
107 0b0000_0000_0000_0000_0000_0000_0000_0011
108 );
109 zigzag_test!(zigzag_i64_pos, i64, u64, 0b10, 0b100);
110 zigzag_test!(zigzag_i64_neg, i64, u64, -0b10, 0b11);
111 zigzag_test!(zigzag_i128_pos, i128, u128, 0b10, 0b100);
112 zigzag_test!(zigzag_i128_neg, i128, u128, -0b10, 0b11);
113
114 #[test]
115 fn we_actually_use_zigzag_encoding() {
116 assert_eq!(39, ZigZag::to_unsigned(-20i8));
117 assert_eq!(-2i8, ZigZag::to_signed(3u8));
118 assert_eq!(0, ZigZag::to_unsigned(0i32));
119 assert_eq!(20i32, ZigZag::to_signed(40u32));
120 }
121}