serde_jam/compact/
num.rs

1//! Number encoding and decoding
2
3use crate::{Vec, compact, vec};
4use serde::Serialize;
5
6/// Trait for types that can be encoded and decoded using serde-jam
7pub trait Numeric: Sized + Default + Copy + Serialize {
8    /// The length of the numeric value in bytes
9    const LENGTH: usize;
10
11    /// Encode the value into a byte vector
12    fn encode(&self) -> Vec<u8>;
13
14    /// Decode the value from a byte vector
15    fn decode(value: &[u8]) -> Self;
16
17    /// Encode the value into a compact byte vector
18    fn compact_encode(&self) -> Vec<u8>;
19
20    /// Decode the value from a compact byte vector
21    fn compact_decode(source: &[u8]) -> Self;
22
23    /// Convert the value to a u64
24    fn as_u64(&self) -> u64;
25
26    /// Create a numeric value from a u64
27    fn from_u64(value: u64) -> Self;
28}
29
30/// Implement the `Numeric` trait for the given types.
31macro_rules! impl_numeric {
32    ($(($t:ty, $len:expr)),+) => {
33        $(
34            impl Numeric for $t {
35                const LENGTH: usize = $len;
36
37                fn encode(&self) -> Vec<u8> {
38                    let bytes = self.to_le_bytes().to_vec();
39                    let end = $len - self.leading_zeros() as usize / 8;
40                    if end == 0 {
41                        vec![0] // Return [0] for zero values instead of empty
42                    } else {
43                        bytes[..end].to_vec()
44                    }
45                }
46
47                fn decode(source: &[u8]) -> Self {
48                    let len = source.len();
49                    let mut bytes = [0; $len];
50                    bytes[0..len.min($len)].copy_from_slice(source);
51                    Self::from_le_bytes(bytes)
52                }
53
54                fn compact_encode(&self) -> Vec<u8> {
55                    compact::encode(*self as u64)
56                }
57
58                fn compact_decode(source: &[u8]) -> Self {
59                    compact::decode(source) as $t
60                }
61
62                fn as_u64(&self) -> u64 {
63                    *self as u64
64                }
65
66                fn from_u64(value: u64) -> Self {
67                    value as $t
68                }
69            }
70        )+
71    }
72}
73
74impl_numeric! {
75    (i8, 1),
76    (u8, 1),
77    (i16, 2),
78    (u16, 2),
79    (i32, 4),
80    (u32, 4),
81    (i64, 8),
82    (u64, 8)
83}
84
85#[cfg(test)]
86macro_rules! test_codec {
87    ($t:ty, $source:expr) => {
88        let value = <$t>::from_le_bytes($source);
89        let encoded = value.encode();
90        let decoded = <$t>::decode(&encoded);
91        assert_eq!(value, decoded);
92        assert_eq!(
93            encoded.len(),
94            $source.len() - value.leading_zeros() as usize / 8,
95        );
96    };
97}
98
99#[test]
100fn i8() {
101    let values = vec![-128, -1, 0, 1, 127];
102    for value in values {
103        let encoded = value.encode();
104        let decoded = i8::decode(&encoded);
105        assert_eq!(value, decoded);
106    }
107}
108
109#[test]
110fn u8() {
111    let values = vec![0, 1, 127, 128, 255];
112    for value in values {
113        let encoded = value.encode();
114        let decoded = u8::decode(&encoded);
115        assert_eq!(value, decoded);
116    }
117}
118
119#[test]
120fn i16() {
121    let values = vec![[255, 0], [0, 255]];
122    for source in values {
123        test_codec!(i16, source);
124    }
125}
126
127#[test]
128fn u16() {
129    let values = vec![[255, 0], [0, 255]];
130    for source in values {
131        test_codec!(u16, source);
132    }
133}
134
135#[test]
136fn i32() {
137    let values = vec![
138        [255, 0, 0, 0],
139        [0, 255, 0, 0],
140        [0, 0, 255, 0],
141        [0, 0, 0, 255],
142    ];
143    for source in values {
144        test_codec!(i32, source);
145    }
146}
147
148#[test]
149fn u32() {
150    let values = vec![
151        [255, 0, 0, 0],
152        [0, 255, 0, 0],
153        [0, 0, 255, 0],
154        [0, 0, 0, 255],
155    ];
156    for source in values {
157        test_codec!(u32, source);
158    }
159}
160
161#[test]
162fn i64() {
163    let values = vec![
164        [255, 0, 0, 0, 0, 0, 0, 0],
165        [0, 255, 0, 0, 0, 0, 0, 0],
166        [0, 0, 255, 0, 0, 0, 0, 0],
167        [0, 0, 0, 255, 0, 0, 0, 0],
168        [0, 0, 0, 0, 255, 0, 0, 0],
169        [0, 0, 0, 0, 0, 255, 0, 0],
170        [0, 0, 0, 0, 0, 0, 255, 0],
171        [0, 0, 0, 0, 0, 0, 0, 255],
172    ];
173    for source in values {
174        test_codec!(i64, source);
175    }
176}
177
178#[test]
179fn u64() {
180    let values = vec![
181        [255, 0, 0, 0, 0, 0, 0, 0],
182        [0, 255, 0, 0, 0, 0, 0, 0],
183        [0, 0, 255, 0, 0, 0, 0, 0],
184        [0, 0, 0, 255, 0, 0, 0, 0],
185        [0, 0, 0, 0, 255, 0, 0, 0],
186        [0, 0, 0, 0, 0, 255, 0, 0],
187        [0, 0, 0, 0, 0, 0, 255, 0],
188        [0, 0, 0, 0, 0, 0, 0, 255],
189    ];
190    for source in values {
191        test_codec!(u64, source);
192    }
193}