valence_protocol/
var_int.rs
1use std::io::{Read, Write};
2
3use anyhow::bail;
4use byteorder::ReadBytesExt;
5use derive_more::{Deref, DerefMut, From, Into};
6use serde::{Deserialize, Serialize};
7use thiserror::Error;
8
9use crate::{Decode, Encode};
10
11#[derive(
13 Clone,
14 Copy,
15 Default,
16 PartialEq,
17 Eq,
18 PartialOrd,
19 Ord,
20 Hash,
21 Debug,
22 Deref,
23 DerefMut,
24 From,
25 Into,
26 Serialize,
27 Deserialize,
28)]
29#[serde(transparent)]
30#[repr(transparent)]
31pub struct VarInt(pub i32);
32
33impl VarInt {
34 pub const MAX_SIZE: usize = 5;
37
38 pub const fn written_size(self) -> usize {
41 match self.0 {
42 0 => 1,
43 n => (31 - n.leading_zeros() as usize) / 7 + 1,
44 }
45 }
46
47 pub fn decode_partial<R: Read>(mut r: R) -> Result<i32, VarIntDecodeError> {
48 let mut val = 0;
49 for i in 0..Self::MAX_SIZE {
50 let byte = r.read_u8().map_err(|_| VarIntDecodeError::Incomplete)?;
51 val |= (i32::from(byte) & 0b01111111) << (i * 7);
52 if byte & 0b10000000 == 0 {
53 return Ok(val);
54 }
55 }
56
57 Err(VarIntDecodeError::TooLarge)
58 }
59}
60
61#[derive(Copy, Clone, PartialEq, Eq, Debug, Error)]
62pub enum VarIntDecodeError {
63 #[error("incomplete VarInt decode")]
64 Incomplete,
65 #[error("VarInt is too large")]
66 TooLarge,
67}
68
69impl Encode for VarInt {
70 fn encode(&self, mut w: impl Write) -> anyhow::Result<()> {
73 let x = self.0 as u64;
74 let stage1 = (x & 0x000000000000007f)
75 | ((x & 0x0000000000003f80) << 1)
76 | ((x & 0x00000000001fc000) << 2)
77 | ((x & 0x000000000fe00000) << 3)
78 | ((x & 0x00000000f0000000) << 4);
79
80 let leading = stage1.leading_zeros();
81
82 let unused_bytes = (leading - 1) >> 3;
83 let bytes_needed = 8 - unused_bytes;
84
85 let msbs = 0x8080808080808080;
87 let msbmask = 0xffffffffffffffff >> (((8 - bytes_needed + 1) << 3) - 1);
88
89 let merged = stage1 | (msbs & msbmask);
90 let bytes = merged.to_le_bytes();
91
92 w.write_all(unsafe { bytes.get_unchecked(..bytes_needed as usize) })?;
93
94 Ok(())
95 }
96}
97
98impl Decode<'_> for VarInt {
99 fn decode(r: &mut &[u8]) -> anyhow::Result<Self> {
100 let mut val = 0;
101 for i in 0..Self::MAX_SIZE {
102 let byte = r.read_u8()?;
103 val |= (i32::from(byte) & 0b01111111) << (i * 7);
104 if byte & 0b10000000 == 0 {
105 return Ok(VarInt(val));
106 }
107 }
108 bail!("VarInt is too large")
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use rand::{thread_rng, Rng};
115
116 use super::*;
117
118 #[test]
119 fn varint_written_size() {
120 let mut rng = thread_rng();
121 let mut buf = vec![];
122
123 for n in (0..100_000)
124 .map(|_| rng.gen())
125 .chain([0, i32::MIN, i32::MAX])
126 .map(VarInt)
127 {
128 buf.clear();
129 n.encode(&mut buf).unwrap();
130 assert_eq!(buf.len(), n.written_size());
131 }
132 }
133
134 #[test]
135 fn varint_round_trip() {
136 let mut rng = thread_rng();
137 let mut buf = vec![];
138
139 for n in (0..1_000_000)
140 .map(|_| rng.gen())
141 .chain([0, i32::MIN, i32::MAX])
142 {
143 VarInt(n).encode(&mut buf).unwrap();
144
145 let mut slice = buf.as_slice();
146 assert!(slice.len() <= VarInt::MAX_SIZE);
147
148 assert_eq!(n, VarInt::decode(&mut slice).unwrap().0);
149
150 assert!(slice.is_empty());
151 buf.clear();
152 }
153 }
154}