binary_codec/
fixed_int.rs

1use crate::{
2    DeserializationError, SerializationError, SerializerConfig,
3    utils::{ensure_size, slice},
4};
5
6pub fn write_zigzag<T, const S: usize, U: Clone>(
7    val: T,
8    bytes: &mut Vec<u8>,
9    config: &mut SerializerConfig<U>,
10) -> Result<(), SerializationError>
11where
12    T: ZigZag,
13    T::Unsigned: FixedInt<S>,
14{
15    let encoded = val.to_unsigned();
16    encoded.write(bytes, config)
17}
18
19pub fn read_zigzag<T, const S: usize, U: Clone>(
20    bytes: &[u8],
21    config: &mut SerializerConfig<U>,
22) -> Result<T, DeserializationError>
23where
24    T: ZigZag,
25    T::Unsigned: FixedInt<S>,
26{
27    let raw = T::Unsigned::read(bytes, config)?;
28    Ok(T::to_signed(raw))
29}
30
31// Fixed int implementations
32pub trait FixedInt<const S: usize>: Sized {
33    fn serialize(self) -> [u8; S];
34    fn deserialize(bytes: &[u8]) -> Self;
35
36    fn write<U: Clone>(
37        self,
38        bytes: &mut Vec<u8>,
39        config: &mut SerializerConfig<U>,
40    ) -> Result<(), SerializationError> {
41        config.reset_bits(false);
42        bytes.extend_from_slice(&self.serialize());
43
44        // If first byte and only byte to write, don't increment pos counter but set bits to 8
45        // TODO: we might need to investigate this edge case further
46        if config.pos == 0 && S == 1 {
47            config.bits = 8;
48        } else {
49            config.pos += S;
50        }
51
52        Ok(())
53    }
54
55    fn read<U: Clone>(
56        bytes: &[u8],
57        config: &mut SerializerConfig<U>,
58    ) -> Result<Self, DeserializationError> {
59        config.reset_bits(true);
60        ensure_size(config, bytes, S)?;
61        Ok(Self::deserialize(slice(config, bytes, S, true)?))
62    }
63}
64
65impl FixedInt<1> for u8 {
66    fn serialize(self) -> [u8; 1] {
67        self.to_be_bytes()
68    }
69
70    fn deserialize(bytes: &[u8]) -> Self {
71        u8::from_be_bytes(bytes.try_into().unwrap())
72            .try_into()
73            .unwrap()
74    }
75}
76
77impl FixedInt<2> for u16 {
78    fn serialize(self) -> [u8; 2] {
79        self.to_be_bytes()
80    }
81
82    fn deserialize(bytes: &[u8]) -> Self {
83        u16::from_be_bytes(bytes.try_into().unwrap())
84            .try_into()
85            .unwrap()
86    }
87}
88
89impl FixedInt<4> for u32 {
90    fn serialize(self) -> [u8; 4] {
91        self.to_be_bytes()
92    }
93
94    fn deserialize(bytes: &[u8]) -> Self {
95        u32::from_be_bytes(bytes.try_into().unwrap())
96            .try_into()
97            .unwrap()
98    }
99}
100
101impl FixedInt<8> for u64 {
102    fn serialize(self) -> [u8; 8] {
103        self.to_be_bytes()
104    }
105
106    fn deserialize(bytes: &[u8]) -> Self {
107        u64::from_be_bytes(bytes.try_into().unwrap())
108            .try_into()
109            .unwrap()
110    }
111}
112
113impl FixedInt<16> for u128 {
114    fn serialize(self) -> [u8; 16] {
115        self.to_be_bytes()
116    }
117
118    fn deserialize(bytes: &[u8]) -> Self {
119        u128::from_be_bytes(bytes.try_into().unwrap())
120            .try_into()
121            .unwrap()
122    }
123}
124
125// ZigZag implementations
126pub trait ZigZag {
127    type Unsigned;
128
129    fn to_unsigned(self) -> Self::Unsigned;
130    fn to_signed(n: Self::Unsigned) -> Self;
131}
132
133impl ZigZag for i8 {
134    type Unsigned = u8;
135    fn to_unsigned(self) -> u8 {
136        ((self << 1) ^ (self >> 7)) as u8
137    }
138    fn to_signed(n: u8) -> i8 {
139        ((n >> 1) as i8) ^ -((n & 1) as i8)
140    }
141}
142
143impl ZigZag for i16 {
144    type Unsigned = u16;
145    fn to_unsigned(self) -> u16 {
146        ((self << 1) ^ (self >> 15)) as u16
147    }
148    fn to_signed(n: u16) -> i16 {
149        ((n >> 1) as i16) ^ -((n & 1) as i16)
150    }
151}
152
153impl ZigZag for i32 {
154    type Unsigned = u32;
155    fn to_unsigned(self) -> u32 {
156        ((self << 1) ^ (self >> 31)) as u32
157    }
158    fn to_signed(n: u32) -> i32 {
159        ((n >> 1) as i32) ^ -((n & 1) as i32)
160    }
161}
162
163impl ZigZag for i64 {
164    type Unsigned = u64;
165    fn to_unsigned(self) -> u64 {
166        ((self << 1) ^ (self >> 63)) as u64
167    }
168    fn to_signed(n: u64) -> i64 {
169        ((n >> 1) as i64) ^ -((n & 1) as i64)
170    }
171}
172
173impl ZigZag for i128 {
174    type Unsigned = u128;
175    fn to_unsigned(self) -> u128 {
176        ((self << 1) ^ (self >> 127)) as u128
177    }
178    fn to_signed(n: u128) -> i128 {
179        ((n >> 1) as i128) ^ -((n & 1) as i128)
180    }
181}
182
183#[cfg(test)]
184mod tests {
185    use super::*;
186    macro_rules! zigzag_test {
187        ($name:ident, $ty:ty, $unsigned:ty, $val:expr, $expected:expr) => {
188            #[test]
189            fn $name() {
190                let val: $ty = $val;
191                let encoded: $unsigned = val.to_unsigned();
192                assert_eq!(encoded, $expected, "ZigZag encoding failed for {}", val);
193                let decoded: $ty = <$ty>::to_signed(encoded);
194                assert_eq!(decoded, val, "ZigZag decoding failed for {}", val);
195            }
196        };
197    }
198
199    zigzag_test!(
200        zigzag_i16_pos,
201        i16,
202        u16,
203        0b0000_0000_0000_0010,
204        0b0000_0000_0000_0100
205    );
206    zigzag_test!(
207        zigzag_i16_neg,
208        i16,
209        u16,
210        -0b0000_0000_0000_0010,
211        0b0000_0000_0000_0011
212    );
213    zigzag_test!(
214        zigzag_i32_pos,
215        i32,
216        u32,
217        0b0000_0000_0000_0000_0000_0000_0000_0010,
218        0b0000_0000_0000_0000_0000_0000_0000_0100
219    );
220    zigzag_test!(
221        zigzag_i32_neg,
222        i32,
223        u32,
224        -0b0000_0000_0000_0000_0000_0000_0000_0010,
225        0b0000_0000_0000_0000_0000_0000_0000_0011
226    );
227    zigzag_test!(zigzag_i64_pos, i64, u64, 0b10, 0b100);
228    zigzag_test!(zigzag_i64_neg, i64, u64, -0b10, 0b11);
229    zigzag_test!(zigzag_i128_pos, i128, u128, 0b10, 0b100);
230    zigzag_test!(zigzag_i128_neg, i128, u128, -0b10, 0b11);
231
232    macro_rules! fixedint_test {
233        ($name:ident, $ty:ty, $val:expr, $bytes:expr) => {
234            #[test]
235            fn $name() {
236                let val: $ty = $val;
237                let serialized = val.serialize();
238                assert_eq!(serialized, $bytes, "FixedInt serialize failed for {}", val);
239                let deserialized = <$ty>::deserialize(&serialized);
240                assert_eq!(
241                    deserialized, val,
242                    "FixedInt deserialize failed for {:?}",
243                    serialized
244                );
245            }
246        };
247    }
248
249    fixedint_test!(fixedint_u16, u16, 0b1010_1010_1010_1010, [0b1010_1010; 2]);
250    fixedint_test!(
251        fixedint_u32,
252        u32,
253        0b1010_1010_1010_1010_1010_1010_1010_1010,
254        [0b1010_1010; 4]
255    );
256    fixedint_test!(
257        fixedint_u64,
258        u64,
259        0b1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010,
260        [0b1010_1010; 8]
261    );
262    fixedint_test!(fixedint_u128, u128, 0b1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010, [0b1010_1010; 16]);
263
264    #[test]
265    fn test_write_read_zigzag_i32() {
266        let mut bytes = Vec::new();
267        let mut config = SerializerConfig::new(None);
268        let val: i32 = -123;
269        write_zigzag::<i32, 4, ()>(val, &mut bytes, &mut config).unwrap();
270        let mut config = SerializerConfig::new(None);
271        let decoded = read_zigzag::<i32, 4, ()>(&bytes, &mut config).unwrap();
272        assert_eq!(decoded, val);
273    }
274
275    #[test]
276    fn test_write_read_zigzag_i64() {
277        let mut bytes = Vec::new();
278        let mut config = SerializerConfig::new(None);
279        let val: i64 = 456789;
280        write_zigzag::<i64, 8, ()>(val, &mut bytes, &mut config).unwrap();
281        let mut config = SerializerConfig::new(None);
282        let decoded = read_zigzag::<i64, 8, ()>(&bytes, &mut config).unwrap();
283        assert_eq!(decoded, val);
284    }
285
286    #[test]
287    fn test_write_read_fixedint_u32() {
288        let mut bytes = Vec::new();
289        let mut config = SerializerConfig::<()>::new(None);
290        let val: u32 = 0b1010_1010_1010_1010_1010_1010_1010_1010;
291        val.write(&mut bytes, &mut config).unwrap();
292        let mut config = SerializerConfig::<()>::new(None);
293        let decoded = u32::read(&bytes, &mut config).unwrap();
294        assert_eq!(decoded, val);
295    }
296
297    #[test]
298    fn test_write_read_fixedint_u128() {
299        let mut bytes = Vec::new();
300        let mut config = SerializerConfig::<()>::new(None);
301        let val: u128 = 0b1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010_1010;
302        val.write(&mut bytes, &mut config).unwrap();
303        let mut config = SerializerConfig::<()>::new(None);
304        let decoded = u128::read(&bytes, &mut config).unwrap();
305        assert_eq!(decoded, val);
306    }
307
308    #[test]
309    fn test_read_fixedint_with_offset_bits() {
310        let bytes = [0b0101_0101, 7];
311        let mut config = SerializerConfig::<()>::new(None);
312        config.bits = 4;
313        let decoded = u8::read(&bytes, &mut config).unwrap();
314        assert_eq!(decoded, 7);
315    }
316}