Skip to main content

voidmc_codec/primitives/
vari.rs

1use crate::{Decode, DecodeError, Encode};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub struct VarI32(pub i32);
5
6impl Encode for VarI32 {
7    fn encode(&self, buf: &mut Vec<u8>) {
8        let mut value = self.0 as u32;
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 VarI32 {
27    fn decode(buf: &mut &[u8]) -> Result<Self, DecodeError> {
28        let mut value: u32 = 0;
29        let mut shift = 0;
30
31        for _ in 0..5 {
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 u32) << shift;
40
41            if byte & 0x80 == 0 {
42                return Ok(VarI32(value as i32));
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_vari32_zero() {
58        let value = VarI32(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 = VarI32::decode(&mut slice).unwrap();
65        assert_eq!(decoded.0, 0);
66    }
67
68    #[test]
69    fn test_vari32_small_positive() {
70        let value = VarI32(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 = VarI32::decode(&mut slice).unwrap();
77        assert_eq!(decoded.0, 127);
78    }
79
80    #[test]
81    fn test_vari32_128() {
82        let value = VarI32(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 = VarI32::decode(&mut slice).unwrap();
89        assert_eq!(decoded.0, 128);
90    }
91
92    #[test]
93    fn test_vari32_negative() {
94        let value = VarI32(-1);
95        let mut buf = Vec::new();
96        value.encode(&mut buf);
97
98        let mut slice = buf.as_slice();
99        let decoded = VarI32::decode(&mut slice).unwrap();
100        assert_eq!(decoded.0, -1);
101    }
102
103    #[test]
104    fn test_vari32_max() {
105        let value = VarI32(i32::MAX);
106        let mut buf = Vec::new();
107        value.encode(&mut buf);
108
109        let mut slice = buf.as_slice();
110        let decoded = VarI32::decode(&mut slice).unwrap();
111        assert_eq!(decoded.0, i32::MAX);
112    }
113
114    #[test]
115    fn test_vari32_min() {
116        let value = VarI32(i32::MIN);
117        let mut buf = Vec::new();
118        value.encode(&mut buf);
119
120        let mut slice = buf.as_slice();
121        let decoded = VarI32::decode(&mut slice).unwrap();
122        assert_eq!(decoded.0, i32::MIN);
123    }
124
125    #[test]
126    fn test_vari32_truncated() {
127        let mut slice = &[0x80][..];
128        let result = VarI32::decode(&mut slice);
129        assert_eq!(result, Err(DecodeError::UnexpectedEof));
130    }
131
132    #[test]
133    fn test_vari32_too_long() {
134        let bytes = vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
135        let mut slice = bytes.as_slice();
136        let result = VarI32::decode(&mut slice);
137        assert_eq!(result, Err(DecodeError::InvalidVarintLength));
138    }
139
140    #[test]
141    fn test_vari32_exact_bytes_zero() {
142        let value = VarI32(0);
143        let mut buf = Vec::new();
144        value.encode(&mut buf);
145        assert_eq!(buf, vec![0x00]);
146    }
147
148    #[test]
149    fn test_vari32_exact_bytes_one() {
150        let value = VarI32(1);
151        let mut buf = Vec::new();
152        value.encode(&mut buf);
153        assert_eq!(buf, vec![0x01]);
154    }
155
156    #[test]
157    fn test_vari32_exact_bytes_127() {
158        let value = VarI32(127);
159        let mut buf = Vec::new();
160        value.encode(&mut buf);
161        assert_eq!(buf, vec![0x7F]);
162    }
163
164    #[test]
165    fn test_vari32_exact_bytes_128() {
166        let value = VarI32(128);
167        let mut buf = Vec::new();
168        value.encode(&mut buf);
169        assert_eq!(buf, vec![0x80, 0x01]);
170    }
171
172    #[test]
173    fn test_vari32_exact_bytes_255() {
174        let value = VarI32(255);
175        let mut buf = Vec::new();
176        value.encode(&mut buf);
177        assert_eq!(buf, vec![0xFF, 0x01]);
178    }
179
180    #[test]
181    fn test_vari32_exact_bytes_256() {
182        let value = VarI32(256);
183        let mut buf = Vec::new();
184        value.encode(&mut buf);
185        assert_eq!(buf, vec![0x80, 0x02]);
186    }
187
188    #[test]
189    fn test_vari32_exact_bytes_16383() {
190        let value = VarI32(16383);
191        let mut buf = Vec::new();
192        value.encode(&mut buf);
193        assert_eq!(buf, vec![0xFF, 0x7F]);
194    }
195
196    #[test]
197    fn test_vari32_exact_bytes_16384() {
198        let value = VarI32(16384);
199        let mut buf = Vec::new();
200        value.encode(&mut buf);
201        assert_eq!(buf, vec![0x80, 0x80, 0x01]);
202    }
203
204    #[test]
205    fn test_vari32_negative_exact_bytes() {
206        let value = VarI32(-1);
207        let mut buf = Vec::new();
208        value.encode(&mut buf);
209        assert_eq!(buf, vec![0xFF, 0xFF, 0xFF, 0xFF, 0x0F]);
210    }
211
212    #[test]
213    fn test_vari32_negative_two() {
214        let value = VarI32(-2);
215        let mut buf = Vec::new();
216        value.encode(&mut buf);
217        assert_eq!(buf, vec![0xFE, 0xFF, 0xFF, 0xFF, 0x0F]);
218    }
219
220    #[test]
221    fn test_vari32_negative_128() {
222        let value = VarI32(-128);
223        let mut buf = Vec::new();
224        value.encode(&mut buf);
225        assert_eq!(buf, vec![0x80, 0xFF, 0xFF, 0xFF, 0x0F]);
226    }
227
228    #[test]
229    fn test_vari32_100() {
230        let value = VarI32(100);
231        let mut buf = Vec::new();
232        value.encode(&mut buf);
233        assert_eq!(buf.len(), 1);
234        assert_eq!(buf, vec![100]);
235    }
236
237    #[test]
238    fn test_vari32_1000() {
239        let value = VarI32(1000);
240        let mut buf = Vec::new();
241        value.encode(&mut buf);
242        assert_eq!(buf.len(), 2);
243        assert_eq!(buf, vec![0xE8, 0x07]);
244    }
245
246    #[test]
247    fn test_vari32_serialization_efficiency() {
248        struct TestCase {
249            value: i32,
250            expected_len: usize,
251        }
252
253        let cases = [
254            TestCase {
255                value: 0,
256                expected_len: 1,
257            },
258            TestCase {
259                value: 127,
260                expected_len: 1,
261            },
262            TestCase {
263                value: 128,
264                expected_len: 2,
265            },
266            TestCase {
267                value: 16383,
268                expected_len: 2,
269            },
270            TestCase {
271                value: 16384,
272                expected_len: 3,
273            },
274            TestCase {
275                value: i32::MAX,
276                expected_len: 5,
277            },
278        ];
279
280        for case in &cases {
281            let mut buf = Vec::new();
282            VarI32(case.value).encode(&mut buf);
283            assert_eq!(
284                buf.len(),
285                case.expected_len,
286                "VarI32({}) should encode to {} bytes, got {}",
287                case.value,
288                case.expected_len,
289                buf.len()
290            );
291        }
292    }
293
294    #[test]
295    fn test_vari32_java_compliance_roundtrip() {
296        let test_values = [
297            0,
298            1,
299            127,
300            128,
301            255,
302            256,
303            16383,
304            16384,
305            -1,
306            -2,
307            -128,
308            -32768,
309            i32::MAX,
310            i32::MIN,
311        ];
312
313        for value in &test_values {
314            let vi32 = VarI32(*value);
315            let mut buf = Vec::new();
316            vi32.encode(&mut buf);
317
318            let mut slice = buf.as_slice();
319            let decoded = VarI32::decode(&mut slice).unwrap();
320            assert_eq!(
321                decoded.0, *value,
322                "VarI32 roundtrip failed for value {}",
323                value
324            );
325            assert_eq!(
326                slice.len(),
327                0,
328                "VarI32 decode didn't consume all bytes for value {}",
329                value
330            );
331        }
332    }
333
334    #[test]
335    fn test_vari32_max_bytes_limit() {
336        let mut buf = Vec::new();
337        (i32::MAX).encode(&mut buf);
338        assert!(
339            buf.len() <= 5,
340            "VarI32 should encode to at most 5 bytes, got {}",
341            buf.len()
342        );
343    }
344
345    #[test]
346    fn test_vari32_more_than_five_bytes_rejected() {
347        let bytes = vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01];
348        let mut slice = bytes.as_slice();
349        let result = VarI32::decode(&mut slice);
350        assert!(
351            result.is_err(),
352            "VarI32 with 6 bytes should be rejected like Java's position >= 32 check"
353        );
354    }
355
356    #[test]
357    fn test_vari32_java_segment_and_continue_bits() {
358        let value = VarI32(300);
359        let mut buf = Vec::new();
360        value.encode(&mut buf);
361
362        assert_eq!(buf.len(), 2);
363        assert_eq!(buf[0] & 0x80, 0x80, "First byte should have continue bit");
364        assert_eq!(
365            buf[1] & 0x80,
366            0x00,
367            "Last byte should NOT have continue bit"
368        );
369
370        let segment_bits = 0x7F;
371
372        assert_eq!(
373            buf[0] & segment_bits,
374            300u32 as u8 & segment_bits,
375            "First byte segment bits should match"
376        );
377    }
378
379    #[test]
380    fn test_vari32_java_logic_equivalence() {
381        let test_values = [0, 1, 63, 64, 127, 128, 255, 256, 16383, 16384];
382
383        for &value in &test_values {
384            let vi32 = VarI32(value);
385            let mut buf = Vec::new();
386            vi32.encode(&mut buf);
387
388            assert!(!buf.is_empty(), "VarI32 should encode to at least 1 byte");
389            assert!(buf.len() <= 5, "VarI32 should encode to at most 5 bytes");
390
391            let mut decoded_value = 0u32;
392            for (i, &byte) in buf.iter().enumerate() {
393                decoded_value |= ((byte & 0x7F) as u32) << (i * 7);
394
395                if byte & 0x80 == 0 {
396                    assert_eq!(
397                        i + 1,
398                        buf.len(),
399                        "No-continue-bit should be on the last byte"
400                    );
401                    break;
402                }
403            }
404
405            assert_eq!(
406                decoded_value, value as u32,
407                "Manual decode should match encoded value for {}: bytes = {:?}",
408                value, buf
409            );
410        }
411    }
412}