basalt_types/
primitives.rs1use crate::{Decode, Encode, EncodedSize, Error, Result};
2
3impl Encode for bool {
9 fn encode(&self, buf: &mut Vec<u8>) -> Result<()> {
11 buf.push(if *self { 0x01 } else { 0x00 });
12 Ok(())
13 }
14}
15
16impl Decode for bool {
22 fn decode(buf: &mut &[u8]) -> Result<Self> {
26 if buf.is_empty() {
27 return Err(Error::BufferUnderflow {
28 needed: 1,
29 available: 0,
30 });
31 }
32 let value = buf[0] != 0;
33 *buf = &buf[1..];
34 Ok(value)
35 }
36}
37
38impl EncodedSize for bool {
40 fn encoded_size(&self) -> usize {
41 1
42 }
43}
44
45macro_rules! impl_numeric {
52 ($ty:ty, $size:expr) => {
53 #[doc = concat!(stringify!($size), " bytes.")]
58 impl Encode for $ty {
59 #[doc = concat!(stringify!($size), " bytes.")]
61 fn encode(&self, buf: &mut Vec<u8>) -> Result<()> {
62 buf.extend_from_slice(&self.to_be_bytes());
63 Ok(())
64 }
65 }
66
67 #[doc = concat!(stringify!($size), " bytes from the buffer and interprets them as big-endian.")]
71 impl Decode for $ty {
72 #[doc = concat!(stringify!($size), " big-endian bytes and advances the cursor.")]
74 #[doc = concat!(stringify!($size), " bytes remain.")]
77 fn decode(buf: &mut &[u8]) -> Result<Self> {
78 if buf.len() < $size {
79 return Err(Error::BufferUnderflow {
80 needed: $size,
81 available: buf.len(),
82 });
83 }
84 let (bytes, rest) = buf.split_at($size);
85 let value = <$ty>::from_be_bytes(bytes.try_into().unwrap());
86 *buf = rest;
87 Ok(value)
88 }
89 }
90
91 #[doc = concat!(stringify!($size), " bytes, regardless of the value.")]
93 impl EncodedSize for $ty {
94 fn encoded_size(&self) -> usize {
95 $size
96 }
97 }
98 };
99}
100
101impl_numeric!(u8, 1);
102impl_numeric!(u16, 2);
103impl_numeric!(u32, 4);
104impl_numeric!(u64, 8);
105impl_numeric!(i8, 1);
106impl_numeric!(i16, 2);
107impl_numeric!(i32, 4);
108impl_numeric!(i64, 8);
109impl_numeric!(f32, 4);
110impl_numeric!(f64, 8);
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 fn roundtrip<T: Encode + Decode + EncodedSize + PartialEq + std::fmt::Debug>(value: T) {
118 let mut buf = Vec::with_capacity(value.encoded_size());
119 value.encode(&mut buf).unwrap();
120 assert_eq!(buf.len(), value.encoded_size());
121
122 let mut cursor = buf.as_slice();
123 let decoded = T::decode(&mut cursor).unwrap();
124 assert!(cursor.is_empty());
125 assert_eq!(decoded, value);
126 }
127
128 fn decode_underflow<T: Decode + std::fmt::Debug>(short_buf: &[u8]) {
130 let mut cursor = short_buf;
131 let result = T::decode(&mut cursor);
132 assert!(matches!(result, Err(Error::BufferUnderflow { .. })));
133 }
134
135 #[test]
138 fn bool_true() {
139 roundtrip(true);
140 }
141
142 #[test]
143 fn bool_false() {
144 roundtrip(false);
145 }
146
147 #[test]
148 fn bool_nonzero_is_true() {
149 let mut cursor: &[u8] = &[0x42];
150 assert!(bool::decode(&mut cursor).unwrap());
151 }
152
153 #[test]
154 fn bool_underflow() {
155 decode_underflow::<bool>(&[]);
156 }
157
158 #[test]
161 fn u8_roundtrip() {
162 roundtrip(0u8);
163 roundtrip(u8::MAX);
164 }
165
166 #[test]
167 fn i8_roundtrip() {
168 roundtrip(0i8);
169 roundtrip(i8::MAX);
170 roundtrip(i8::MIN);
171 }
172
173 #[test]
176 fn u16_roundtrip() {
177 roundtrip(0u16);
178 roundtrip(u16::MAX);
179 }
180
181 #[test]
182 fn u16_big_endian() {
183 let mut buf = Vec::new();
184 0x0102u16.encode(&mut buf).unwrap();
185 assert_eq!(buf, [0x01, 0x02]);
186 }
187
188 #[test]
189 fn i16_roundtrip() {
190 roundtrip(0i16);
191 roundtrip(i16::MAX);
192 roundtrip(i16::MIN);
193 }
194
195 #[test]
196 fn u16_underflow() {
197 decode_underflow::<u16>(&[0x01]);
198 }
199
200 #[test]
203 fn u32_roundtrip() {
204 roundtrip(0u32);
205 roundtrip(u32::MAX);
206 }
207
208 #[test]
209 fn u32_big_endian() {
210 let mut buf = Vec::new();
211 0x01020304u32.encode(&mut buf).unwrap();
212 assert_eq!(buf, [0x01, 0x02, 0x03, 0x04]);
213 }
214
215 #[test]
216 fn i32_roundtrip() {
217 roundtrip(0i32);
218 roundtrip(i32::MAX);
219 roundtrip(i32::MIN);
220 }
221
222 #[test]
223 fn u32_underflow() {
224 decode_underflow::<u32>(&[0x01, 0x02, 0x03]);
225 }
226
227 #[test]
230 fn u64_roundtrip() {
231 roundtrip(0u64);
232 roundtrip(u64::MAX);
233 }
234
235 #[test]
236 fn i64_roundtrip() {
237 roundtrip(0i64);
238 roundtrip(i64::MAX);
239 roundtrip(i64::MIN);
240 }
241
242 #[test]
243 fn u64_underflow() {
244 decode_underflow::<u64>(&[0x01; 7]);
245 }
246
247 #[test]
250 fn f32_roundtrip() {
251 roundtrip(0.0f32);
252 roundtrip(f32::MAX);
253 roundtrip(f32::MIN);
254 roundtrip(f32::INFINITY);
255 roundtrip(f32::NEG_INFINITY);
256 }
257
258 #[test]
259 fn f32_nan() {
260 let mut buf = Vec::new();
261 f32::NAN.encode(&mut buf).unwrap();
262 let mut cursor = buf.as_slice();
263 let decoded = f32::decode(&mut cursor).unwrap();
264 assert!(decoded.is_nan());
265 }
266
267 #[test]
268 fn f64_roundtrip() {
269 roundtrip(0.0f64);
270 roundtrip(f64::MAX);
271 roundtrip(f64::MIN);
272 roundtrip(f64::INFINITY);
273 roundtrip(f64::NEG_INFINITY);
274 }
275
276 #[test]
277 fn f64_nan() {
278 let mut buf = Vec::new();
279 f64::NAN.encode(&mut buf).unwrap();
280 let mut cursor = buf.as_slice();
281 let decoded = f64::decode(&mut cursor).unwrap();
282 assert!(decoded.is_nan());
283 }
284
285 #[test]
286 fn f64_underflow() {
287 decode_underflow::<f64>(&[0x01; 7]);
288 }
289
290 mod proptests {
293 use super::*;
294 use proptest::prelude::*;
295
296 proptest! {
297 #[test]
298 fn bool_roundtrip(v: bool) {
299 roundtrip(v);
300 }
301
302 #[test]
303 fn u8_roundtrip(v: u8) {
304 roundtrip(v);
305 }
306
307 #[test]
308 fn i8_roundtrip(v: i8) {
309 roundtrip(v);
310 }
311
312 #[test]
313 fn u16_roundtrip(v: u16) {
314 roundtrip(v);
315 }
316
317 #[test]
318 fn i16_roundtrip(v: i16) {
319 roundtrip(v);
320 }
321
322 #[test]
323 fn u32_roundtrip(v: u32) {
324 roundtrip(v);
325 }
326
327 #[test]
328 fn i32_roundtrip(v: i32) {
329 roundtrip(v);
330 }
331
332 #[test]
333 fn u64_roundtrip(v: u64) {
334 roundtrip(v);
335 }
336
337 #[test]
338 fn i64_roundtrip(v: i64) {
339 roundtrip(v);
340 }
341
342 #[test]
343 fn f32_roundtrip_finite(v in proptest::num::f32::NORMAL | proptest::num::f32::SUBNORMAL | proptest::num::f32::ZERO) {
344 roundtrip(v);
345 }
346
347 #[test]
348 fn f64_roundtrip_finite(v in proptest::num::f64::NORMAL | proptest::num::f64::SUBNORMAL | proptest::num::f64::ZERO) {
349 roundtrip(v);
350 }
351 }
352 }
353}