steel_utils/codec/
var_long.rs1use std::io::{Cursor, Error, Write};
2
3use crate::serial::{ReadFrom, WriteTo};
4
5#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub struct VarLong(pub i64);
8
9impl VarLong {
10 pub const MAX_SIZE: usize = 10;
12}
13
14impl ReadFrom for VarLong {
15 fn read(read: &mut Cursor<&[u8]>) -> Result<Self, Error> {
16 let mut val = 0i64;
17 for i in 0..Self::MAX_SIZE {
18 let byte = u8::read(read)?;
19 val |= (i64::from(byte) & 0x7F) << (i * 7);
20 if byte & 0x80 == 0 {
21 return Ok(Self(val));
22 }
23 }
24 Err(Error::other("VarLong too long"))
25 }
26}
27
28impl WriteTo for VarLong {
29 fn write(&self, writer: &mut impl Write) -> Result<(), Error> {
30 let mut val = self.0 as u64;
31 loop {
32 let b: u8 = val as u8 & 0x7F;
33 val >>= 7;
34 if val == 0 {
35 b.write(writer)?;
36 break;
37 }
38 (b | 0x80).write(writer)?;
39 }
40 Ok(())
41 }
42}
43
44impl From<i64> for VarLong {
45 fn from(value: i64) -> Self {
46 Self(value)
47 }
48}
49
50impl From<VarLong> for i64 {
51 fn from(value: VarLong) -> i64 {
52 value.0
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59 use std::io::Cursor;
60
61 #[test]
62 fn test_varlong_read_write() {
63 let test_values = vec![
64 0i64,
65 1i64,
66 127i64,
67 128i64,
68 255i64,
69 2_147_483_647_i64,
70 9_223_372_036_854_775_807_i64,
71 -1i64,
72 -2_147_483_648_i64,
73 ];
74
75 for val in test_values {
76 let var_long = VarLong(val);
77 let mut buf = Vec::new();
78 var_long.write(&mut buf).expect("write failed");
79
80 let mut cursor = Cursor::new(buf.as_slice());
81 let read_val = VarLong::read(&mut cursor).expect("read failed");
82 assert_eq!(read_val, var_long, "Failed for value {val}");
83 }
84 }
85}