minecraft_varint/
lib.rs

1type Result<T> = std::io::Result<T>;
2
3fn zigzag_encode_32(src: i32) -> u32 {
4    if src >= 0 {
5        (src as u32) << 1
6    } else {
7        (((-src) as u32) << 1) - 1
8    }
9}
10
11fn zigzag_decode_32(src: u32) -> i32 {
12    if src & 1 != 0 {
13        -((src >> 1) as i32) - 1
14    } else {
15        (src >> 1) as i32
16    }
17}
18
19fn zigzag_encode_64(src: i64) -> u64 {
20    if src >= 0 {
21        (src as u64) << 1
22    } else {
23        (((-src) as u64) << 1) - 1
24    }
25}
26
27fn zigzag_decode_64(src: u64) -> i64 {
28    if src & 1 != 0 {
29        -((src >> 1) as i64) - 1
30    } else {
31        (src >> 1) as i64
32    }
33}
34
35pub trait VarIntRead {
36    fn read_var_i64(&mut self) -> Result<i64> {
37        self.read_var_u64().map(|x| zigzag_decode_64(x))
38    }
39
40    fn read_var_i32(&mut self) -> Result<i32> {
41        self.read_var_u32().map(|x| zigzag_decode_32(x))
42    }
43
44    fn read_var_u64(&mut self) -> Result<u64>;
45
46    fn read_var_u32(&mut self) -> Result<u32>;
47}
48
49pub trait VarIntWrite {
50    fn write_var_i32(&mut self, value: i32) -> Result<usize> {
51        self.write_var_u32(zigzag_encode_32(value))
52    }
53
54    fn write_var_i64(&mut self, value: i64) -> Result<usize> {
55        self.write_var_u64(zigzag_encode_64(value))
56    }
57
58    fn write_var_u32(&mut self, value: u32) -> Result<usize>;
59
60    fn write_var_u64(&mut self, value: u64) -> Result<usize>;
61}
62
63impl<R> VarIntRead for R
64where
65    R: std::io::Read,
66{
67    fn read_var_u64(&mut self) -> Result<u64> {
68        let mut buf = [0];
69        let mut ans = 0;
70        for i in 0..9 {
71            self.read_exact(&mut buf)?;
72
73            ans |= (buf[0] as u64 & 0x7F) << 7 * i;
74
75            if buf[0] & 0x80 == 0 {
76                break;
77            }
78        }
79        Ok(ans)
80    }
81
82    fn read_var_u32(&mut self) -> Result<u32> {
83        let mut buf = [0];
84        let mut ans = 0;
85        for i in 0..5 {
86            self.read_exact(&mut buf)?;
87
88            ans |= (buf[0] as u32 & 0x7F) << 7 * i;
89
90            if buf[0] & 0x80 == 0 {
91                break;
92            }
93        }
94        Ok(ans)
95    }
96}
97
98impl<W> VarIntWrite for W
99where
100    W: std::io::Write,
101{
102    fn write_var_u32(&mut self, mut value: u32) -> Result<usize> {
103        let mut buf = [0; (u32::BITS as usize + 6) / 7];
104        let mut i = 0;
105
106        loop {
107            buf[i] = (value & 0b0111_1111) as u8;
108            value >>= 7;
109            if value != 0 {
110                buf[i] |= 0b1000_0000;
111            }
112            i += 1;
113
114            if value == 0 {
115                break;
116            }
117        }
118
119        self.write_all(&buf[..i])?;
120        Ok(i)
121    }
122
123    fn write_var_u64(&mut self, mut value: u64) -> Result<usize> {
124        let mut buf = [0; (u64::BITS as usize + 6) / 7];
125        let mut i = 0;
126
127        loop {
128            buf[i] = (value & 0b0111_1111) as u8;
129            value >>= 7;
130            if value != 0 {
131                buf[i] |= 0b1000_0000;
132            }
133            i += 1;
134
135            if value == 0 {
136                break;
137            }
138        }
139
140        self.write_all(&buf[..i])?;
141        Ok(i)
142    }
143}