fxfs/serialized_types/
varint.rs1use anyhow::{Error, ensure};
36
37pub trait Buffer: AsRef<[u8]> + AsMut<[u8]> + Send {
39 fn put(&mut self, data: &[u8]);
41}
42
43impl Buffer for Vec<u8> {
44 fn put(&mut self, data: &[u8]) {
45 self.extend_from_slice(data);
46 }
47}
48
49#[inline]
51pub fn encode_varint_bytes(v: u64) -> ([u8; 9], usize) {
52 let mut buf = [0u8; 9];
53 let len = if v < 0xc0 {
54 buf[0] = v as u8;
55 1
56 } else if v < 0x2000 {
57 buf[..2].copy_from_slice(&(v as u16 | 0xc000).to_be_bytes());
58 2
59 } else if v < 0x1000_0000 {
60 buf[..4].copy_from_slice(&(v as u32 | 0xe000_0000).to_be_bytes());
61 4
62 } else if v < 0x0f00_0000_0000_0000 {
63 buf[..8].copy_from_slice(&(v | 0xf000_0000_0000_0000).to_be_bytes());
64 8
65 } else {
66 buf[0] = 0xff;
67 buf[1..9].copy_from_slice(&v.to_be_bytes());
68 9
69 };
70 (buf, len)
71}
72
73#[inline]
75pub fn encode_varint(v: u64, buf: &mut impl Buffer) -> usize {
76 if v < 0xc0 {
77 buf.put(&[v as u8]);
78 1
79 } else if v < 0x2000 {
80 buf.put(&(v as u16 | 0xc000).to_be_bytes());
81 2
82 } else if v < 0x1000_0000 {
83 buf.put(&(v as u32 | 0xe000_0000).to_be_bytes());
84 4
85 } else if v < 0x0f00_0000_0000_0000 {
86 buf.put(&(v | 0xf000_0000_0000_0000).to_be_bytes());
87 8
88 } else {
89 let mut b = [0u8; 9];
90 b[0] = 0xff;
91 b[1..9].copy_from_slice(&v.to_be_bytes());
92 buf.put(&b);
93 9
94 }
95}
96
97#[inline]
101pub fn decode_varint<'a>(data: &'a [u8]) -> Result<(u64, &'a [u8]), Error> {
102 ensure!(!data.is_empty(), "Data too short");
103 let b = data[0];
104 let (val, len) = if b < 0xc0 {
105 (b as u64, 1)
106 } else if b < 0xe0 {
107 ensure!(data.len() >= 2, "Data too short");
108 let v = u16::from_be_bytes(data[..2].try_into().unwrap());
109 let val = (v & !0xc000) as u64;
110 ensure!(val >= 0xc0, "Non-canonical varint");
111 (val, 2)
112 } else if b < 0xf0 {
113 ensure!(data.len() >= 4, "Data too short");
114 let v = u32::from_be_bytes(data[..4].try_into().unwrap());
115 let val = (v & !0xe000_0000) as u64;
116 ensure!(val >= 0x2000, "Non-canonical varint");
117 (val, 4)
118 } else if b < 0xff {
119 ensure!(data.len() >= 8, "Data too short");
120 let v = u64::from_be_bytes(data[..8].try_into().unwrap());
121 let val = v & !0xf000_0000_0000_0000;
122 ensure!(val >= 0x1000_0000, "Non-canonical varint");
123 (val, 8)
124 } else {
125 ensure!(data.len() >= 9, "Data too short");
126 let val = u64::from_be_bytes(data[1..9].try_into().unwrap());
127 ensure!(val >= 0x0f00_0000_0000_0000, "Non-canonical varint");
128 (val, 9)
129 };
130 Ok((val, &data[len..]))
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136
137 #[test]
138 fn test_correctness() {
139 let test_cases = vec![
140 0,
141 1,
142 0xbe,
143 0xbf,
144 0xc0,
145 0x1ffe,
146 0x1fff,
147 0x2000,
148 0x0fff_ffff,
149 0x1000_0000,
150 0x0eff_ffff_ffff_ffff,
151 0x0f00_0000_0000_0000,
152 u64::MAX,
153 ];
154 for v in test_cases {
155 let mut buf = Vec::new();
156 let len = encode_varint(v, &mut buf);
157 let (decoded, remainder) = decode_varint(&buf).unwrap();
158 assert_eq!(v, decoded);
159 assert_eq!(remainder.len(), 0);
160 assert_eq!(buf.len(), len);
161
162 let (bytes, bytes_len) = encode_varint_bytes(v);
163 assert_eq!(len, bytes_len);
164 assert_eq!(&buf[..], &bytes[..bytes_len]);
165 }
166 }
167
168 #[test]
169 fn test_ordering_correctness() {
170 let test_cases = vec![
171 0,
172 1,
173 0xbe,
174 0xbf,
175 0xc0,
176 0x1ffe,
177 0x1fff,
178 0x2000,
179 0x0fff_ffff,
180 0x1000_0000,
181 0x0eff_ffff_ffff_ffff,
182 0x0f00_0000_0000_0000,
183 u64::MAX,
184 ];
185 for i in 0..test_cases.len() {
186 for j in 0..test_cases.len() {
187 let a = test_cases[i];
188 let b = test_cases[j];
189
190 let mut buf_a = Vec::new();
191 let mut buf_b = Vec::new();
192
193 encode_varint(a, &mut buf_a);
194 encode_varint(b, &mut buf_b);
195
196 let ord_cmp = a.cmp(&b);
197 let ser_cmp = buf_a.cmp(&buf_b);
198 assert_eq!(ord_cmp, ser_cmp, "Mismatch for {} and {}", a, b);
199 }
200 }
201 }
202
203 #[test]
204 fn test_non_canonical() {
205 assert!(decode_varint(&[0xc0, 0x03]).is_err());
206 assert!(decode_varint(&[0xe0, 0x00, 0x1f, 0xff]).is_err());
207 assert!(decode_varint(&[0xf0, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff]).is_err());
208 assert!(decode_varint(&[0xff, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]).is_err());
209 }
210}