Git fork
1/// Decode the variable-length integer stored in `bufp` and return the decoded value.
2///
3/// Returns 0 in case the decoded integer would overflow u64::MAX.
4///
5/// # Safety
6///
7/// The buffer must be NUL-terminated to ensure safety.
8#[no_mangle]
9pub unsafe extern "C" fn decode_varint(bufp: *mut *const u8) -> u64 {
10 let mut buf = *bufp;
11 let mut c = *buf;
12 let mut val = u64::from(c & 127);
13
14 buf = buf.add(1);
15
16 while (c & 128) != 0 {
17 val = val.wrapping_add(1);
18 if val == 0 || val.leading_zeros() < 7 {
19 return 0; // overflow
20 }
21
22 c = *buf;
23 buf = buf.add(1);
24
25 val = (val << 7) + u64::from(c & 127);
26 }
27
28 *bufp = buf;
29 val
30}
31
32/// Encode `value` into `buf` as a variable-length integer unless `buf` is null.
33///
34/// Returns the number of bytes written, or, if `buf` is null, the number of bytes that would be
35/// written to encode the integer.
36///
37/// # Safety
38///
39/// `buf` must either be null or point to at least 16 bytes of memory.
40#[no_mangle]
41pub unsafe extern "C" fn encode_varint(value: u64, buf: *mut u8) -> u8 {
42 let mut varint: [u8; 16] = [0; 16];
43 let mut pos = varint.len() - 1;
44
45 varint[pos] = (value & 127) as u8;
46
47 let mut value = value >> 7;
48 while value != 0 {
49 pos -= 1;
50 value -= 1;
51 varint[pos] = 128 | (value & 127) as u8;
52 value >>= 7;
53 }
54
55 if !buf.is_null() {
56 std::ptr::copy_nonoverlapping(varint.as_ptr().add(pos), buf, varint.len() - pos);
57 }
58
59 (varint.len() - pos) as u8
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn test_decode_varint() {
68 unsafe {
69 assert_eq!(decode_varint(&mut [0x00].as_slice().as_ptr()), 0);
70 assert_eq!(decode_varint(&mut [0x01].as_slice().as_ptr()), 1);
71 assert_eq!(decode_varint(&mut [0x7f].as_slice().as_ptr()), 127);
72 assert_eq!(decode_varint(&mut [0x80, 0x00].as_slice().as_ptr()), 128);
73 assert_eq!(decode_varint(&mut [0x80, 0x01].as_slice().as_ptr()), 129);
74 assert_eq!(decode_varint(&mut [0x80, 0x7f].as_slice().as_ptr()), 255);
75
76 // Overflows are expected to return 0.
77 assert_eq!(decode_varint(&mut [0x88; 16].as_slice().as_ptr()), 0);
78 }
79 }
80
81 #[test]
82 fn test_encode_varint() {
83 unsafe {
84 let mut varint: [u8; 16] = [0; 16];
85
86 assert_eq!(encode_varint(0, std::ptr::null_mut()), 1);
87
88 assert_eq!(encode_varint(0, varint.as_mut_slice().as_mut_ptr()), 1);
89 assert_eq!(varint, [0; 16]);
90
91 assert_eq!(encode_varint(10, varint.as_mut_slice().as_mut_ptr()), 1);
92 assert_eq!(varint, [10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
93
94 assert_eq!(encode_varint(127, varint.as_mut_slice().as_mut_ptr()), 1);
95 assert_eq!(varint, [127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
96
97 assert_eq!(encode_varint(128, varint.as_mut_slice().as_mut_ptr()), 2);
98 assert_eq!(varint, [128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
99
100 assert_eq!(encode_varint(129, varint.as_mut_slice().as_mut_ptr()), 2);
101 assert_eq!(varint, [128, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
102
103 assert_eq!(encode_varint(255, varint.as_mut_slice().as_mut_ptr()), 2);
104 assert_eq!(varint, [128, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
105 }
106 }
107}