1use std::fmt;
2use std::io::{Read, Write};
3use std::marker::PhantomData;
4
5use byteorder::{
6 BigEndian as ByteOrderBigEndian, ByteOrder, LittleEndian as ByteOrderLittleEndian,
7 ReadBytesExt, WriteBytesExt,
8};
9use paste::paste;
10
11use crate::error::{Error, Result};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum EncodingKind {
15 BigEndian,
16 LittleEndian,
17 NetworkLittleEndian,
18}
19
20impl EncodingKind {
21 pub const fn is_network(self) -> bool {
22 matches!(self, Self::NetworkLittleEndian)
23 }
24}
25
26pub trait Encoding: Copy + Clone + Default + fmt::Debug + Send + Sync + 'static {
27 const KIND: EncodingKind;
28
29 fn read_i16<R: Read>(reader: &mut R) -> Result<i16>;
30 fn write_i16<W: Write>(writer: &mut W, value: i16) -> Result<()>;
31
32 fn read_i32<R: Read>(reader: &mut R) -> Result<i32>;
33 fn write_i32<W: Write>(writer: &mut W, value: i32) -> Result<()>;
34
35 fn read_i64<R: Read>(reader: &mut R) -> Result<i64>;
36 fn write_i64<W: Write>(writer: &mut W, value: i64) -> Result<()>;
37
38 fn read_f32<R: Read>(reader: &mut R) -> Result<f32>;
39 fn write_f32<W: Write>(writer: &mut W, value: f32) -> Result<()>;
40
41 fn read_f64<R: Read>(reader: &mut R) -> Result<f64>;
42 fn write_f64<W: Write>(writer: &mut W, value: f64) -> Result<()>;
43
44 fn read_string_len<R: Read>(reader: &mut R) -> Result<usize>;
45 fn write_string_len<W: Write>(writer: &mut W, len: usize) -> Result<()>;
46
47 fn read_list_len<R: Read>(reader: &mut R) -> Result<usize>;
48 fn write_list_len<W: Write>(writer: &mut W, len: usize) -> Result<()>;
49}
50
51#[derive(Debug, Clone, Copy, Default)]
52pub struct BigEndian;
53
54#[derive(Debug, Clone, Copy, Default)]
55pub struct LittleEndian;
56
57#[derive(Debug, Clone, Copy, Default)]
58pub struct NetworkLittleEndian;
59
60#[derive(Debug, Clone, Copy, Default)]
61pub struct Codec<E: Encoding> {
62 _marker: PhantomData<E>,
63}
64
65impl<E: Encoding> Codec<E> {
66 pub const fn new() -> Self {
67 Self {
68 _marker: PhantomData,
69 }
70 }
71
72 pub const fn kind(self) -> EncodingKind {
73 E::KIND
74 }
75
76 pub fn read_i16<R: Read>(self, reader: &mut R) -> Result<i16> {
77 E::read_i16(reader)
78 }
79
80 pub fn write_i16<W: Write>(self, writer: &mut W, value: i16) -> Result<()> {
81 E::write_i16(writer, value)
82 }
83
84 pub fn read_i32<R: Read>(self, reader: &mut R) -> Result<i32> {
85 E::read_i32(reader)
86 }
87
88 pub fn write_i32<W: Write>(self, writer: &mut W, value: i32) -> Result<()> {
89 E::write_i32(writer, value)
90 }
91
92 pub fn read_i64<R: Read>(self, reader: &mut R) -> Result<i64> {
93 E::read_i64(reader)
94 }
95
96 pub fn write_i64<W: Write>(self, writer: &mut W, value: i64) -> Result<()> {
97 E::write_i64(writer, value)
98 }
99
100 pub fn read_f32<R: Read>(self, reader: &mut R) -> Result<f32> {
101 E::read_f32(reader)
102 }
103
104 pub fn write_f32<W: Write>(self, writer: &mut W, value: f32) -> Result<()> {
105 E::write_f32(writer, value)
106 }
107
108 pub fn read_f64<R: Read>(self, reader: &mut R) -> Result<f64> {
109 E::read_f64(reader)
110 }
111
112 pub fn write_f64<W: Write>(self, writer: &mut W, value: f64) -> Result<()> {
113 E::write_f64(writer, value)
114 }
115
116 pub fn read_string_len<R: Read>(self, reader: &mut R) -> Result<usize> {
117 E::read_string_len(reader)
118 }
119
120 pub fn write_string_len<W: Write>(self, writer: &mut W, len: usize) -> Result<()> {
121 E::write_string_len(writer, len)
122 }
123
124 pub fn read_list_len<R: Read>(self, reader: &mut R) -> Result<usize> {
125 E::read_list_len(reader)
126 }
127
128 pub fn write_list_len<W: Write>(self, writer: &mut W, len: usize) -> Result<()> {
129 E::write_list_len(writer, len)
130 }
131}
132
133pub type BigEndianCodec = Codec<BigEndian>;
134pub type LittleEndianCodec = Codec<LittleEndian>;
135pub type NetworkLittleEndianCodec = Codec<NetworkLittleEndian>;
136
137pub const BE: BigEndianCodec = Codec::new();
138pub const LE: LittleEndianCodec = Codec::new();
139pub const NLE: NetworkLittleEndianCodec = Codec::new();
140
141impl Encoding for BigEndian {
142 const KIND: EncodingKind = EncodingKind::BigEndian;
143
144 fn read_i16<R: Read>(reader: &mut R) -> Result<i16> {
145 read_i16_order::<_, ByteOrderBigEndian>(reader)
146 }
147
148 fn write_i16<W: Write>(writer: &mut W, value: i16) -> Result<()> {
149 write_i16_order::<_, ByteOrderBigEndian>(writer, value)
150 }
151
152 fn read_i32<R: Read>(reader: &mut R) -> Result<i32> {
153 read_i32_order::<_, ByteOrderBigEndian>(reader)
154 }
155
156 fn write_i32<W: Write>(writer: &mut W, value: i32) -> Result<()> {
157 write_i32_order::<_, ByteOrderBigEndian>(writer, value)
158 }
159
160 fn read_i64<R: Read>(reader: &mut R) -> Result<i64> {
161 read_i64_order::<_, ByteOrderBigEndian>(reader)
162 }
163
164 fn write_i64<W: Write>(writer: &mut W, value: i64) -> Result<()> {
165 write_i64_order::<_, ByteOrderBigEndian>(writer, value)
166 }
167
168 fn read_f32<R: Read>(reader: &mut R) -> Result<f32> {
169 read_f32_order::<_, ByteOrderBigEndian>(reader)
170 }
171
172 fn write_f32<W: Write>(writer: &mut W, value: f32) -> Result<()> {
173 write_f32_order::<_, ByteOrderBigEndian>(writer, value)
174 }
175
176 fn read_f64<R: Read>(reader: &mut R) -> Result<f64> {
177 read_f64_order::<_, ByteOrderBigEndian>(reader)
178 }
179
180 fn write_f64<W: Write>(writer: &mut W, value: f64) -> Result<()> {
181 write_f64_order::<_, ByteOrderBigEndian>(writer, value)
182 }
183
184 fn read_string_len<R: Read>(reader: &mut R) -> Result<usize> {
185 Ok(read_u16_order::<_, ByteOrderBigEndian>(reader)? as usize)
186 }
187
188 fn write_string_len<W: Write>(writer: &mut W, len: usize) -> Result<()> {
189 ensure_fit("string_length", len, u16::MAX as usize)?;
190 write_u16_order::<_, ByteOrderBigEndian>(writer, len as u16)
191 }
192
193 fn read_list_len<R: Read>(reader: &mut R) -> Result<usize> {
194 let len = read_i32_order::<_, ByteOrderBigEndian>(reader)?;
195 non_negative_len("list_length", len)
196 }
197
198 fn write_list_len<W: Write>(writer: &mut W, len: usize) -> Result<()> {
199 ensure_fit("list_length", len, i32::MAX as usize)?;
200 write_i32_order::<_, ByteOrderBigEndian>(writer, len as i32)
201 }
202}
203
204impl Encoding for LittleEndian {
205 const KIND: EncodingKind = EncodingKind::LittleEndian;
206
207 fn read_i16<R: Read>(reader: &mut R) -> Result<i16> {
208 read_i16_order::<_, ByteOrderLittleEndian>(reader)
209 }
210
211 fn write_i16<W: Write>(writer: &mut W, value: i16) -> Result<()> {
212 write_i16_order::<_, ByteOrderLittleEndian>(writer, value)
213 }
214
215 fn read_i32<R: Read>(reader: &mut R) -> Result<i32> {
216 read_i32_order::<_, ByteOrderLittleEndian>(reader)
217 }
218
219 fn write_i32<W: Write>(writer: &mut W, value: i32) -> Result<()> {
220 write_i32_order::<_, ByteOrderLittleEndian>(writer, value)
221 }
222
223 fn read_i64<R: Read>(reader: &mut R) -> Result<i64> {
224 read_i64_order::<_, ByteOrderLittleEndian>(reader)
225 }
226
227 fn write_i64<W: Write>(writer: &mut W, value: i64) -> Result<()> {
228 write_i64_order::<_, ByteOrderLittleEndian>(writer, value)
229 }
230
231 fn read_f32<R: Read>(reader: &mut R) -> Result<f32> {
232 read_f32_order::<_, ByteOrderLittleEndian>(reader)
233 }
234
235 fn write_f32<W: Write>(writer: &mut W, value: f32) -> Result<()> {
236 write_f32_order::<_, ByteOrderLittleEndian>(writer, value)
237 }
238
239 fn read_f64<R: Read>(reader: &mut R) -> Result<f64> {
240 read_f64_order::<_, ByteOrderLittleEndian>(reader)
241 }
242
243 fn write_f64<W: Write>(writer: &mut W, value: f64) -> Result<()> {
244 write_f64_order::<_, ByteOrderLittleEndian>(writer, value)
245 }
246
247 fn read_string_len<R: Read>(reader: &mut R) -> Result<usize> {
248 Ok(read_u16_order::<_, ByteOrderLittleEndian>(reader)? as usize)
249 }
250
251 fn write_string_len<W: Write>(writer: &mut W, len: usize) -> Result<()> {
252 ensure_fit("string_length", len, u16::MAX as usize)?;
253 write_u16_order::<_, ByteOrderLittleEndian>(writer, len as u16)
254 }
255
256 fn read_list_len<R: Read>(reader: &mut R) -> Result<usize> {
257 let len = read_i32_order::<_, ByteOrderLittleEndian>(reader)?;
258 non_negative_len("list_length", len)
259 }
260
261 fn write_list_len<W: Write>(writer: &mut W, len: usize) -> Result<()> {
262 ensure_fit("list_length", len, i32::MAX as usize)?;
263 write_i32_order::<_, ByteOrderLittleEndian>(writer, len as i32)
264 }
265}
266
267impl Encoding for NetworkLittleEndian {
268 const KIND: EncodingKind = EncodingKind::NetworkLittleEndian;
269
270 fn read_i16<R: Read>(reader: &mut R) -> Result<i16> {
271 read_i16_order::<_, ByteOrderLittleEndian>(reader)
272 }
273
274 fn write_i16<W: Write>(writer: &mut W, value: i16) -> Result<()> {
275 write_i16_order::<_, ByteOrderLittleEndian>(writer, value)
276 }
277
278 fn read_i32<R: Read>(reader: &mut R) -> Result<i32> {
279 read_var_i32(reader)
280 }
281
282 fn write_i32<W: Write>(writer: &mut W, value: i32) -> Result<()> {
283 write_var_i32(writer, value)
284 }
285
286 fn read_i64<R: Read>(reader: &mut R) -> Result<i64> {
287 read_var_i64(reader)
288 }
289
290 fn write_i64<W: Write>(writer: &mut W, value: i64) -> Result<()> {
291 write_var_i64(writer, value)
292 }
293
294 fn read_f32<R: Read>(reader: &mut R) -> Result<f32> {
295 read_f32_order::<_, ByteOrderLittleEndian>(reader)
296 }
297
298 fn write_f32<W: Write>(writer: &mut W, value: f32) -> Result<()> {
299 write_f32_order::<_, ByteOrderLittleEndian>(writer, value)
300 }
301
302 fn read_f64<R: Read>(reader: &mut R) -> Result<f64> {
303 read_f64_order::<_, ByteOrderLittleEndian>(reader)
304 }
305
306 fn write_f64<W: Write>(writer: &mut W, value: f64) -> Result<()> {
307 write_f64_order::<_, ByteOrderLittleEndian>(writer, value)
308 }
309
310 fn read_string_len<R: Read>(reader: &mut R) -> Result<usize> {
311 let len = read_var_u32(reader)? as usize;
312 ensure_fit("string_length", len, i32::MAX as usize)?;
313 Ok(len)
314 }
315
316 fn write_string_len<W: Write>(writer: &mut W, len: usize) -> Result<()> {
317 ensure_fit("string_length", len, i32::MAX as usize)?;
318 write_var_u32(writer, len as u32)
319 }
320
321 fn read_list_len<R: Read>(reader: &mut R) -> Result<usize> {
322 let len = read_var_u32(reader)? as usize;
323 ensure_fit("list_length", len, i32::MAX as usize)?;
324 Ok(len)
325 }
326
327 fn write_list_len<W: Write>(writer: &mut W, len: usize) -> Result<()> {
328 ensure_fit("list_length", len, i32::MAX as usize)?;
329 write_var_u32(writer, len as u32)
330 }
331}
332
333pub fn encode_zigzag_i32(value: i32) -> u32 {
334 ((value << 1) ^ (value >> 31)) as u32
335}
336
337pub fn decode_zigzag_i32(value: u32) -> i32 {
338 ((value >> 1) as i32) ^ -((value & 1) as i32)
339}
340
341pub fn encode_zigzag_i64(value: i64) -> u64 {
342 ((value << 1) ^ (value >> 63)) as u64
343}
344
345pub fn decode_zigzag_i64(value: u64) -> i64 {
346 ((value >> 1) as i64) ^ -((value & 1) as i64)
347}
348
349pub fn read_var_u32<R: Read>(reader: &mut R) -> Result<u32> {
350 let mut value = 0u32;
351 let mut shift = 0u32;
352
353 for index in 0..5u8 {
354 let byte = match read_u8(reader) {
355 Ok(byte) => byte,
356 Err(Error::Io(io_error)) if io_error.kind() == std::io::ErrorKind::UnexpectedEof => {
357 return Err(Error::InvalidVarint {
358 detail: "truncated u32 varint",
359 });
360 }
361 Err(error) => return Err(error),
362 };
363 value |= ((byte & 0x7F) as u32) << shift;
364 if byte & 0x80 == 0 {
365 return Ok(value);
366 }
367 shift += 7;
368 if index == 4 {
369 return Err(Error::InvalidVarint {
370 detail: "u32 varint exceeds 5 bytes",
371 });
372 }
373 }
374
375 Err(Error::InvalidVarint {
376 detail: "failed to decode u32 varint",
377 })
378}
379
380pub fn write_var_u32<W: Write>(writer: &mut W, mut value: u32) -> Result<()> {
381 loop {
382 let mut byte = (value & 0x7F) as u8;
383 value >>= 7;
384 if value != 0 {
385 byte |= 0x80;
386 }
387 writer.write_all(&[byte])?;
388 if value == 0 {
389 return Ok(());
390 }
391 }
392}
393
394pub fn read_var_u64<R: Read>(reader: &mut R) -> Result<u64> {
395 let mut value = 0u64;
396 let mut shift = 0u32;
397
398 for index in 0..10u8 {
399 let byte = match read_u8(reader) {
400 Ok(byte) => byte,
401 Err(Error::Io(io_error)) if io_error.kind() == std::io::ErrorKind::UnexpectedEof => {
402 return Err(Error::InvalidVarint {
403 detail: "truncated u64 varint",
404 });
405 }
406 Err(error) => return Err(error),
407 };
408 if index == 9 {
409 if byte & 0x80 != 0 {
410 return Err(Error::InvalidVarint {
411 detail: "u64 varint exceeds 10 bytes",
412 });
413 }
414 if byte > 0x01 {
415 return Err(Error::InvalidVarint {
416 detail: "u64 varint terminal byte overflow",
417 });
418 }
419 }
420 value |= ((byte & 0x7F) as u64) << shift;
421 if byte & 0x80 == 0 {
422 return Ok(value);
423 }
424 shift += 7;
425 if index == 9 {
426 return Err(Error::InvalidVarint {
427 detail: "u64 varint exceeds 10 bytes",
428 });
429 }
430 }
431
432 Err(Error::InvalidVarint {
433 detail: "failed to decode u64 varint",
434 })
435}
436
437pub fn write_var_u64<W: Write>(writer: &mut W, mut value: u64) -> Result<()> {
438 loop {
439 let mut byte = (value & 0x7F) as u8;
440 value >>= 7;
441 if value != 0 {
442 byte |= 0x80;
443 }
444 writer.write_all(&[byte])?;
445 if value == 0 {
446 return Ok(());
447 }
448 }
449}
450
451pub fn read_var_i32<R: Read>(reader: &mut R) -> Result<i32> {
452 let raw = read_var_u32(reader)?;
453 Ok(decode_zigzag_i32(raw))
454}
455
456pub fn write_var_i32<W: Write>(writer: &mut W, value: i32) -> Result<()> {
457 write_var_u32(writer, encode_zigzag_i32(value))
458}
459
460pub fn read_var_i64<R: Read>(reader: &mut R) -> Result<i64> {
461 let raw = read_var_u64(reader)?;
462 Ok(decode_zigzag_i64(raw))
463}
464
465pub fn write_var_i64<W: Write>(writer: &mut W, value: i64) -> Result<()> {
466 write_var_u64(writer, encode_zigzag_i64(value))
467}
468
469fn read_u8<R: Read>(reader: &mut R) -> Result<u8> {
470 let mut byte = [0u8; 1];
471 reader.read_exact(&mut byte)?;
472 Ok(byte[0])
473}
474
475macro_rules! define_ordered_rw {
476 ($(($suffix:ident, $ty:ty)),+ $(,)?) => {
477 paste! {
478 $(
479 fn [<read_ $suffix _order>]<R: Read, O: ByteOrder>(
480 reader: &mut R,
481 ) -> Result<$ty> {
482 reader.[<read_ $suffix>]::<O>().map_err(Error::from)
483 }
484
485 fn [<write_ $suffix _order>]<W: Write, O: ByteOrder>(
486 writer: &mut W,
487 value: $ty,
488 ) -> Result<()> {
489 writer.[<write_ $suffix>]::<O>(value).map_err(Error::from)
490 }
491 )+
492 }
493 };
494}
495
496define_ordered_rw!(
497 (u16, u16),
498 (i16, i16),
499 (i32, i32),
500 (i64, i64),
501 (f32, f32),
502 (f64, f64)
503);
504
505fn ensure_fit(field: &'static str, actual: usize, max: usize) -> Result<()> {
506 if actual > max {
507 return Err(Error::LengthOverflow { field, max, actual });
508 }
509 Ok(())
510}
511
512fn non_negative_len(field: &'static str, value: i32) -> Result<usize> {
513 if value < 0 {
514 return Err(Error::NegativeLength { field, value });
515 }
516 Ok(value as usize)
517}
518
519#[cfg(test)]
520mod tests {
521 use std::io::Cursor;
522
523 use super::*;
524
525 #[test]
526 fn be_uses_fixed_width_i32() {
527 let mut out = Vec::new();
528 BE.write_i32(&mut out, 300).unwrap();
529 assert_eq!(out, vec![0x00, 0x00, 0x01, 0x2c]);
530 }
531
532 #[test]
533 fn le_uses_fixed_width_i32() {
534 let mut out = Vec::new();
535 LE.write_i32(&mut out, 300).unwrap();
536 assert_eq!(out, vec![0x2c, 0x01, 0x00, 0x00]);
537 }
538
539 #[test]
540 fn nle_i32_roundtrip_uses_zigzag_varint() {
541 let values = [0, 1, -1, 2, -2, i32::MAX, i32::MIN];
542 for value in values {
543 let mut out = Vec::new();
544 NLE.write_i32(&mut out, value).unwrap();
545 let mut input = Cursor::new(out);
546 let decoded = NLE.read_i32(&mut input).unwrap();
547 assert_eq!(decoded, value);
548 }
549 }
550
551 #[test]
552 fn nle_i64_roundtrip_uses_zigzag_varint() {
553 let values = [0, 1, -1, 2, -2, i64::MAX, i64::MIN];
554 for value in values {
555 let mut out = Vec::new();
556 NLE.write_i64(&mut out, value).unwrap();
557 let mut input = Cursor::new(out);
558 let decoded = NLE.read_i64(&mut input).unwrap();
559 assert_eq!(decoded, value);
560 }
561 }
562
563 #[test]
564 fn nle_keeps_float_as_little_endian() {
565 let mut out = Vec::new();
566 NLE.write_f32(&mut out, 1.5).unwrap();
567 assert_eq!(out, 1.5f32.to_le_bytes());
568 }
569
570 #[test]
571 fn nle_uses_varuint_for_string_and_list_lengths() {
572 let mut out = Vec::new();
573 NLE.write_string_len(&mut out, 300).unwrap();
574 NLE.write_list_len(&mut out, 300).unwrap();
575
576 assert_eq!(out, vec![0xAC, 0x02, 0xAC, 0x02]);
578
579 let mut input = Cursor::new(out);
580 assert_eq!(NLE.read_string_len(&mut input).unwrap(), 300);
581 assert_eq!(NLE.read_list_len(&mut input).unwrap(), 300);
582 }
583
584 #[test]
585 fn be_string_len_uses_u16_prefix() {
586 let mut out = Vec::new();
587 BE.write_string_len(&mut out, 300).unwrap();
588 assert_eq!(out, vec![0x01, 0x2C]);
589
590 let mut input = Cursor::new(out);
591 assert_eq!(BE.read_string_len(&mut input).unwrap(), 300);
592 }
593
594 #[test]
595 fn le_string_len_uses_u16_prefix() {
596 let mut out = Vec::new();
597 LE.write_string_len(&mut out, 300).unwrap();
598 assert_eq!(out, vec![0x2C, 0x01]);
599
600 let mut input = Cursor::new(out);
601 assert_eq!(LE.read_string_len(&mut input).unwrap(), 300);
602 }
603
604 #[test]
605 fn be_list_len_uses_i32_prefix() {
606 let mut out = Vec::new();
607 BE.write_list_len(&mut out, 300).unwrap();
608 assert_eq!(out, vec![0x00, 0x00, 0x01, 0x2C]);
609
610 let mut input = Cursor::new(out);
611 assert_eq!(BE.read_list_len(&mut input).unwrap(), 300);
612 }
613
614 #[test]
615 fn le_list_len_uses_i32_prefix() {
616 let mut out = Vec::new();
617 LE.write_list_len(&mut out, 300).unwrap();
618 assert_eq!(out, vec![0x2C, 0x01, 0x00, 0x00]);
619
620 let mut input = Cursor::new(out);
621 assert_eq!(LE.read_list_len(&mut input).unwrap(), 300);
622 }
623
624 #[test]
625 fn be_string_len_overflow_is_rejected() {
626 let err = BE.write_string_len(&mut Vec::new(), (u16::MAX as usize) + 1);
627 assert!(matches!(err, Err(Error::LengthOverflow { .. })));
628 }
629
630 #[test]
631 fn be_negative_list_len_is_rejected() {
632 let mut input = Cursor::new((-1i32).to_be_bytes());
633 let err = BE.read_list_len(&mut input);
634 assert!(matches!(err, Err(Error::NegativeLength { .. })));
635 }
636
637 #[test]
638 fn overlong_var_u32_is_rejected() {
639 let bytes = vec![0x80, 0x80, 0x80, 0x80, 0x80, 0x00];
640 let mut input = Cursor::new(bytes);
641 let err = read_var_u32(&mut input);
642 assert!(matches!(err, Err(Error::InvalidVarint { .. })));
643 }
644
645 #[test]
646 fn overlong_var_u64_is_rejected() {
647 let bytes = vec![
648 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
649 ];
650 let mut input = Cursor::new(bytes);
651 let err = read_var_u64(&mut input);
652 assert!(matches!(err, Err(Error::InvalidVarint { .. })));
653 }
654
655 #[test]
656 fn invalid_terminal_byte_var_u64_is_rejected() {
657 let bytes = vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x02];
659 let mut input = Cursor::new(bytes);
660 let err = read_var_u64(&mut input);
661 assert!(matches!(
662 err,
663 Err(Error::InvalidVarint {
664 detail: "u64 varint terminal byte overflow"
665 })
666 ));
667 }
668
669 #[test]
670 fn truncated_var_u32_is_rejected_as_invalid_varint() {
671 let mut input = Cursor::new(vec![0x80]);
672 let err = read_var_u32(&mut input);
673 assert!(matches!(err, Err(Error::InvalidVarint { .. })));
674 }
675
676 #[test]
677 fn truncated_var_u64_is_rejected_as_invalid_varint() {
678 let mut input = Cursor::new(vec![0x80]);
679 let err = read_var_u64(&mut input);
680 assert!(matches!(err, Err(Error::InvalidVarint { .. })));
681 }
682
683 #[test]
684 fn var_u64_boundary_values_roundtrip() {
685 let values = [
686 0u64,
687 1,
688 127,
689 128,
690 255,
691 16_383,
692 16_384,
693 u32::MAX as u64,
694 (u32::MAX as u64) + 1,
695 (1u64 << 63) - 1,
696 1u64 << 63,
697 u64::MAX,
698 ];
699
700 for value in values {
701 let mut out = Vec::new();
702 write_var_u64(&mut out, value).unwrap();
703 let mut input = Cursor::new(out);
704 let decoded = read_var_u64(&mut input).unwrap();
705 assert_eq!(decoded, value);
706 }
707 }
708
709 #[test]
710 fn nle_keeps_i16_as_little_endian_fixed_width() {
711 let mut out = Vec::new();
712 NLE.write_i16(&mut out, 0x1234).unwrap();
713 assert_eq!(out, 0x1234i16.to_le_bytes());
714
715 let mut input = Cursor::new(out);
716 let value = NLE.read_i16(&mut input).unwrap();
717 assert_eq!(value, 0x1234i16);
718 }
719
720 #[test]
721 fn nle_keeps_f64_as_little_endian() {
722 let mut out = Vec::new();
723 NLE.write_f64(&mut out, 123.456).unwrap();
724 assert_eq!(out, 123.456f64.to_le_bytes());
725
726 let mut input = Cursor::new(out);
727 let value = NLE.read_f64(&mut input).unwrap();
728 assert_eq!(value, 123.456f64);
729 }
730
731 #[test]
732 fn nle_read_string_len_over_i32_max_is_rejected() {
733 let mut input = Cursor::new(vec![0x80, 0x80, 0x80, 0x80, 0x08]);
735 let err = NLE.read_string_len(&mut input);
736 assert!(matches!(err, Err(Error::LengthOverflow { .. })));
737 }
738
739 #[test]
740 fn nle_write_list_len_over_i32_max_is_rejected() {
741 let err = NLE.write_list_len(&mut Vec::new(), (i32::MAX as usize) + 1);
742 assert!(matches!(err, Err(Error::LengthOverflow { .. })));
743 }
744}