justcode_core/
varint.rs

1//! Variable-length integer encoding (varint).
2
3use crate::error::{JustcodeError, Result};
4use crate::reader::Reader;
5use crate::writer::Writer;
6
7/// Encode a u64 as a varint.
8///
9/// Varints use a variable number of bytes:
10/// - Values 0-127: 1 byte
11/// - Values 128-16383: 2 bytes
12/// - Values 16384-2097151: 3 bytes
13/// - etc.
14///
15/// The encoding uses the high bit as a continuation bit.
16pub fn encode_varint(writer: &mut Writer, mut value: u64) -> Result<()> {
17    loop {
18        let byte = (value & 0x7F) as u8;
19        value >>= 7;
20        if value == 0 {
21            writer.write_u8(byte)?;
22            break;
23        } else {
24            writer.write_u8(byte | 0x80)?;
25        }
26    }
27    Ok(())
28}
29
30/// Decode a u64 from a varint.
31pub fn decode_varint(reader: &mut Reader) -> Result<u64> {
32    let mut result = 0u64;
33    let mut shift = 0;
34
35    loop {
36        let byte = reader.read_u8()?;
37        result |= ((byte & 0x7F) as u64) << shift;
38
39        if (byte & 0x80) == 0 {
40            break;
41        }
42
43        shift += 7;
44        if shift >= 64 {
45            return Err(JustcodeError::InvalidVarint);
46        }
47    }
48
49    Ok(result)
50}
51
52/// Encode a usize as a varint (for lengths).
53pub fn encode_length(writer: &mut Writer, value: usize, config: crate::Config) -> Result<()> {
54    if config.variable_int_encoding {
55        encode_varint(writer, value as u64)
56    } else {
57        // Use fixed-size u64 encoding
58        writer.write_u64(value as u64)
59    }
60}
61
62/// Decode a usize from a varint (for lengths).
63pub fn decode_length(reader: &mut Reader, config: crate::Config) -> Result<usize> {
64    if config.variable_int_encoding {
65        let value = decode_varint(reader)?;
66        Ok(value as usize)
67    } else {
68        // Use fixed-size u64 decoding
69        let value = reader.read_u64()?;
70        Ok(value as usize)
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77    use crate::config;
78
79    #[test]
80    fn test_varint_encode_decode() {
81        let config = config::standard();
82        let test_cases = vec![
83            0u64,
84            1,
85            127,
86            128,
87            255,
88            256,
89            16383,
90            16384,
91            65535,
92            1000000,
93            u64::MAX,
94        ];
95
96        for value in test_cases {
97            let mut writer = Writer::new(config);
98            encode_varint(&mut writer, value).unwrap();
99            let bytes = writer.into_bytes();
100
101            let mut reader = Reader::new(&bytes, config);
102            let decoded = decode_varint(&mut reader).unwrap();
103            assert_eq!(value, decoded);
104        }
105    }
106
107    #[test]
108    fn test_length_encode_decode() {
109        let config = config::standard();
110        let test_cases = vec![0usize, 1, 127, 128, 255, 1000, 1000000];
111
112        for value in test_cases {
113            let mut writer = Writer::new(config);
114            encode_length(&mut writer, value, config).unwrap();
115            let bytes = writer.into_bytes();
116
117            let mut reader = Reader::new(&bytes, config);
118            let decoded = decode_length(&mut reader, config).unwrap();
119            assert_eq!(value, decoded);
120        }
121    }
122
123    #[test]
124    fn test_varint_small_values() {
125        let config = config::standard();
126        let value = 42u64;
127        let mut writer = Writer::new(config);
128        encode_varint(&mut writer, value).unwrap();
129        let bytes = writer.into_bytes();
130        // Small values should use 1 byte
131        assert_eq!(bytes.len(), 1);
132    }
133
134    #[test]
135    fn test_varint_multi_byte() {
136        let config = config::standard();
137        // Test 2-byte varint
138        let value = 200u64;
139        let mut writer = Writer::new(config);
140        encode_varint(&mut writer, value).unwrap();
141        let bytes = writer.into_bytes();
142        assert_eq!(bytes.len(), 2);
143        
144        let mut reader = Reader::new(&bytes, config);
145        let decoded = decode_varint(&mut reader).unwrap();
146        assert_eq!(value, decoded);
147    }
148
149    #[test]
150    fn test_varint_large_values() {
151        let config = config::standard();
152        // Test large varint values
153        let test_cases = vec![
154            (16384u64, 3),  // 3 bytes
155            (2097151u64, 3), // 3 bytes
156            (268435455u64, 4), // 4 bytes
157        ];
158
159        for (value, expected_bytes) in test_cases {
160            let mut writer = Writer::new(config);
161            encode_varint(&mut writer, value).unwrap();
162            let bytes = writer.into_bytes();
163            assert_eq!(bytes.len(), expected_bytes, "Value {} should use {} bytes", value, expected_bytes);
164            
165            let mut reader = Reader::new(&bytes, config);
166            let decoded = decode_varint(&mut reader).unwrap();
167            assert_eq!(value, decoded);
168        }
169    }
170
171    #[test]
172    fn test_invalid_varint() {
173        let config = config::standard();
174        // Create an invalid varint with too many continuation bytes
175        let invalid_data = vec![0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80]; // 11 bytes, exceeds 64-bit limit
176        let mut reader = Reader::new(&invalid_data, config);
177        assert!(decode_varint(&mut reader).is_err());
178    }
179
180    #[test]
181    fn test_length_fixed_encoding() {
182        let config = config::standard().with_variable_int_encoding(false);
183        let value = 42usize;
184        let mut writer = Writer::new(config);
185        encode_length(&mut writer, value, config).unwrap();
186        let bytes = writer.into_bytes();
187        // Should use fixed 8 bytes
188        assert_eq!(bytes.len(), 8);
189        
190        let mut reader = Reader::new(&bytes, config);
191        let decoded = decode_length(&mut reader, config).unwrap();
192        assert_eq!(value, decoded);
193    }
194
195    #[test]
196    fn test_length_varint_encoding() {
197        let config = config::standard().with_variable_int_encoding(true);
198        let value = 42usize;
199        let mut writer = Writer::new(config);
200        encode_length(&mut writer, value, config).unwrap();
201        let bytes = writer.into_bytes();
202        // Should use 1 byte varint
203        assert_eq!(bytes.len(), 1);
204        
205        let mut reader = Reader::new(&bytes, config);
206        let decoded = decode_length(&mut reader, config).unwrap();
207        assert_eq!(value, decoded);
208    }
209
210    #[test]
211    fn test_length_large_value() {
212        let config = config::standard();
213        let value = 1000000usize;
214        let mut writer = Writer::new(config);
215        encode_length(&mut writer, value, config).unwrap();
216        let bytes = writer.into_bytes();
217        
218        let mut reader = Reader::new(&bytes, config);
219        let decoded = decode_length(&mut reader, config).unwrap();
220        assert_eq!(value, decoded);
221    }
222}
223