Skip to main content

voidmc_codec/primitives/
vari64.rs

1use crate::{Decode, DecodeError, Encode};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub struct VarI64(pub i64);
5
6impl Encode for VarI64 {
7    fn encode(&self, buf: &mut Vec<u8>) {
8        let mut value = self.0 as u64;
9        loop {
10            let mut byte = (value & 0x7F) as u8;
11            value >>= 7;
12
13            if value != 0 {
14                byte |= 0x80;
15            }
16
17            buf.push(byte);
18
19            if value == 0 {
20                break;
21            }
22        }
23    }
24}
25
26impl Decode for VarI64 {
27    fn decode(buf: &mut &[u8]) -> Result<Self, DecodeError> {
28        let mut value: u64 = 0;
29        let mut shift = 0;
30
31        for _ in 0..10 {
32            if buf.is_empty() {
33                return Err(DecodeError::UnexpectedEof);
34            }
35
36            let byte = buf[0];
37            *buf = &buf[1..];
38
39            value |= ((byte & 0x7F) as u64) << shift;
40
41            if byte & 0x80 == 0 {
42                return Ok(VarI64(value as i64));
43            }
44
45            shift += 7;
46        }
47
48        Err(DecodeError::InvalidVarintLength)
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn test_vari64_zero() {
58        let value = VarI64(0);
59        let mut buf = Vec::new();
60        value.encode(&mut buf);
61        assert_eq!(buf, vec![0x00]);
62
63        let mut slice = buf.as_slice();
64        let decoded = VarI64::decode(&mut slice).unwrap();
65        assert_eq!(decoded.0, 0);
66    }
67
68    #[test]
69    fn test_vari64_small_positive() {
70        let value = VarI64(127);
71        let mut buf = Vec::new();
72        value.encode(&mut buf);
73        assert_eq!(buf, vec![0x7F]);
74
75        let mut slice = buf.as_slice();
76        let decoded = VarI64::decode(&mut slice).unwrap();
77        assert_eq!(decoded.0, 127);
78    }
79
80    #[test]
81    fn test_vari64_128() {
82        let value = VarI64(128);
83        let mut buf = Vec::new();
84        value.encode(&mut buf);
85        assert_eq!(buf, vec![0x80, 0x01]);
86
87        let mut slice = buf.as_slice();
88        let decoded = VarI64::decode(&mut slice).unwrap();
89        assert_eq!(decoded.0, 128);
90    }
91
92    #[test]
93    fn test_vari64_negative() {
94        let value = VarI64(-1);
95        let mut buf = Vec::new();
96        value.encode(&mut buf);
97
98        let mut slice = buf.as_slice();
99        let decoded = VarI64::decode(&mut slice).unwrap();
100        assert_eq!(decoded.0, -1);
101    }
102
103    #[test]
104    fn test_vari64_max() {
105        let value = VarI64(i64::MAX);
106        let mut buf = Vec::new();
107        value.encode(&mut buf);
108
109        let mut slice = buf.as_slice();
110        let decoded = VarI64::decode(&mut slice).unwrap();
111        assert_eq!(decoded.0, i64::MAX);
112    }
113
114    #[test]
115    fn test_vari64_min() {
116        let value = VarI64(i64::MIN);
117        let mut buf = Vec::new();
118        value.encode(&mut buf);
119
120        let mut slice = buf.as_slice();
121        let decoded = VarI64::decode(&mut slice).unwrap();
122        assert_eq!(decoded.0, i64::MIN);
123    }
124
125    #[test]
126    fn test_vari64_truncated() {
127        let mut slice = &[0x80][..];
128        let result = VarI64::decode(&mut slice);
129        assert_eq!(result, Err(DecodeError::UnexpectedEof));
130    }
131
132    #[test]
133    fn test_vari64_too_long() {
134        let bytes = vec![
135            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
136        ];
137        let mut slice = bytes.as_slice();
138        let result = VarI64::decode(&mut slice);
139        assert_eq!(result, Err(DecodeError::InvalidVarintLength));
140    }
141
142    #[test]
143    fn test_vari64_exact_bytes_zero() {
144        let value = VarI64(0);
145        let mut buf = Vec::new();
146        value.encode(&mut buf);
147        assert_eq!(buf, vec![0x00]);
148    }
149
150    #[test]
151    fn test_vari64_exact_bytes_one() {
152        let value = VarI64(1);
153        let mut buf = Vec::new();
154        value.encode(&mut buf);
155        assert_eq!(buf, vec![0x01]);
156    }
157
158    #[test]
159    fn test_vari64_exact_bytes_127() {
160        let value = VarI64(127);
161        let mut buf = Vec::new();
162        value.encode(&mut buf);
163        assert_eq!(buf, vec![0x7F]);
164    }
165
166    #[test]
167    fn test_vari64_exact_bytes_128() {
168        let value = VarI64(128);
169        let mut buf = Vec::new();
170        value.encode(&mut buf);
171        assert_eq!(buf, vec![0x80, 0x01]);
172    }
173
174    #[test]
175    fn test_vari64_exact_bytes_16384() {
176        let value = VarI64(16384);
177        let mut buf = Vec::new();
178        value.encode(&mut buf);
179        assert_eq!(buf, vec![0x80, 0x80, 0x01]);
180    }
181
182    #[test]
183    fn test_vari64_negative_exact_bytes() {
184        let value = VarI64(-1);
185        let mut buf = Vec::new();
186        value.encode(&mut buf);
187        assert_eq!(
188            buf,
189            vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01]
190        );
191    }
192
193    #[test]
194    fn test_vari64_negative_two() {
195        let value = VarI64(-2);
196        let mut buf = Vec::new();
197        value.encode(&mut buf);
198        assert_eq!(
199            buf,
200            vec![0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01]
201        );
202    }
203
204    #[test]
205    fn test_vari64_100() {
206        let value = VarI64(100);
207        let mut buf = Vec::new();
208        value.encode(&mut buf);
209        assert_eq!(buf.len(), 1);
210        assert_eq!(buf, vec![100]);
211    }
212
213    #[test]
214    fn test_vari64_1000() {
215        let value = VarI64(1000);
216        let mut buf = Vec::new();
217        value.encode(&mut buf);
218        assert_eq!(buf.len(), 2);
219        assert_eq!(buf, vec![0xE8, 0x07]);
220    }
221
222    #[test]
223    fn test_vari64_serialization_efficiency() {
224        struct TestCase {
225            value: i64,
226            expected_len: usize,
227        }
228
229        let cases = [
230            TestCase {
231                value: 0,
232                expected_len: 1,
233            },
234            TestCase {
235                value: 127,
236                expected_len: 1,
237            },
238            TestCase {
239                value: 128,
240                expected_len: 2,
241            },
242            TestCase {
243                value: 16383,
244                expected_len: 2,
245            },
246            TestCase {
247                value: 16384,
248                expected_len: 3,
249            },
250            TestCase {
251                value: 2097151,
252                expected_len: 3,
253            },
254            TestCase {
255                value: 2097152,
256                expected_len: 4,
257            },
258            TestCase {
259                value: i64::MAX,
260                expected_len: 9,
261            },
262            TestCase {
263                value: i64::MIN,
264                expected_len: 10,
265            },
266        ];
267
268        for case in &cases {
269            let mut buf = Vec::new();
270            VarI64(case.value).encode(&mut buf);
271            assert_eq!(
272                buf.len(),
273                case.expected_len,
274                "VarI64({}) should encode to {} bytes, got {}",
275                case.value,
276                case.expected_len,
277                buf.len()
278            );
279        }
280    }
281
282    #[test]
283    fn test_vari64_java_compliance_roundtrip() {
284        let test_values = [
285            0i64,
286            1,
287            127,
288            128,
289            255,
290            256,
291            16383,
292            16384,
293            2097151,
294            2097152,
295            -1,
296            -2,
297            -128,
298            -32768,
299            i64::MAX,
300            i64::MIN,
301        ];
302
303        for value in &test_values {
304            let vi64 = VarI64(*value);
305            let mut buf = Vec::new();
306            vi64.encode(&mut buf);
307
308            let mut slice = buf.as_slice();
309            let decoded = VarI64::decode(&mut slice).unwrap();
310            assert_eq!(
311                decoded.0, *value,
312                "VarI64 roundtrip failed for value {}",
313                value
314            );
315            assert_eq!(
316                slice.len(),
317                0,
318                "VarI64 decode didn't consume all bytes for value {}",
319                value
320            );
321        }
322    }
323
324    #[test]
325    fn test_vari64_max_bytes_limit() {
326        let mut buf = Vec::new();
327        (i64::MAX).encode(&mut buf);
328        assert!(
329            buf.len() <= 10,
330            "VarI64 should encode to at most 10 bytes, got {}",
331            buf.len()
332        );
333    }
334
335    #[test]
336    fn test_vari64_more_than_ten_bytes_rejected() {
337        let bytes = vec![
338            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01,
339        ];
340        let mut slice = bytes.as_slice();
341        let result = VarI64::decode(&mut slice);
342        assert!(
343            result.is_err(),
344            "VarI64 with 11 bytes should be rejected like Java's position >= 64 check"
345        );
346    }
347
348    #[test]
349    fn test_vari64_java_segment_and_continue_bits() {
350        let value = VarI64(300);
351        let mut buf = Vec::new();
352        value.encode(&mut buf);
353
354        assert_eq!(buf.len(), 2);
355        assert_eq!(buf[0] & 0x80, 0x80, "First byte should have continue bit");
356        assert_eq!(
357            buf[1] & 0x80,
358            0x00,
359            "Last byte should NOT have continue bit"
360        );
361
362        let segment_bits = 0x7F;
363
364        assert_eq!(
365            buf[0] & segment_bits,
366            300u64 as u8 & segment_bits,
367            "First byte segment bits should match"
368        );
369    }
370
371    #[test]
372    fn test_vari64_java_logic_equivalence() {
373        let test_values = [
374            0i64, 1, 63, 64, 127, 128, 255, 256, 16383, 16384, 2097151, 2097152,
375        ];
376
377        for &value in &test_values {
378            let vi64 = VarI64(value);
379            let mut buf = Vec::new();
380            vi64.encode(&mut buf);
381
382            assert!(!buf.is_empty(), "VarI64 should encode to at least 1 byte");
383            assert!(buf.len() <= 10, "VarI64 should encode to at most 10 bytes");
384
385            let mut decoded_value = 0u64;
386            for (i, &byte) in buf.iter().enumerate() {
387                decoded_value |= ((byte & 0x7F) as u64) << (i * 7);
388
389                if byte & 0x80 == 0 {
390                    assert_eq!(
391                        i + 1,
392                        buf.len(),
393                        "No-continue-bit should be on the last byte"
394                    );
395                    break;
396                }
397            }
398
399            assert_eq!(
400                decoded_value, value as u64,
401                "Manual decode should match encoded value for {}: bytes = {:?}",
402                value, buf
403            );
404        }
405    }
406
407    #[test]
408    fn test_vari64_large_values() {
409        let test_values = [
410            1000000i64,
411            10000000,
412            100000000,
413            1000000000,
414            10000000000,
415            100000000000,
416        ];
417
418        for value in &test_values {
419            let vi64 = VarI64(*value);
420            let mut buf = Vec::new();
421            vi64.encode(&mut buf);
422
423            let mut slice = buf.as_slice();
424            let decoded = VarI64::decode(&mut slice).unwrap();
425            assert_eq!(decoded.0, *value, "Failed for large value {}", value);
426            assert!(
427                buf.len() <= 10,
428                "Large value {} should encode to at most 10 bytes, got {}",
429                value,
430                buf.len()
431            );
432        }
433    }
434}