1#[inline]
18pub fn encode_prefix_integer(
19 out: &mut Vec<u8>,
20 value: u64,
21 prefix_bits: u8,
22 prefix_pattern: u8,
23) {
24 if prefix_bits == 0 || prefix_bits > 8 {
25 return;
26 }
27 let mask = (1u64 << prefix_bits) - 1;
28 if value < mask {
29 out.push(prefix_pattern | (value as u8));
30 return;
31 }
32 out.push(prefix_pattern | mask as u8);
33 let mut v = value - mask;
34 while v >= 0x80 {
35 out.push(((v as u8) & 0x7F) | 0x80);
36 v >>= 7;
37 }
38 out.push(v as u8);
39}
40
41#[inline]
50pub fn decode_prefix_integer(data: &[u8], prefix_bits: u8) -> Option<(u64, usize)> {
51 if data.is_empty() || prefix_bits == 0 || prefix_bits > 8 {
52 return None;
53 }
54 let mask = ((1u16 << prefix_bits as u16) - 1) as u8;
56 let first = data[0] & mask;
57 let mut value = first as u64;
58 if first < mask {
59 return Some((value, 1));
60 }
61 let mut m: u32 = 0;
62 let mut i: usize = 1;
63 loop {
64 if m > 56 {
67 return None;
68 }
69 let Some(&b) = data.get(i) else {
70 return None; };
72 i += 1;
73 let shift = 1u64.checked_shl(m)?;
74 let contribution = ((b & 0x7F) as u64).checked_mul(shift)?;
75 value = value.checked_add(contribution)?;
76 m = m.checked_add(7)?;
77 if b & 0x80 == 0 {
78 break;
79 }
80 }
81 Some((value, i))
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
90 fn decode_small_single_byte() {
91 assert_eq!(decode_prefix_integer(&[0x0A], 5), Some((10, 1)));
92 assert_eq!(decode_prefix_integer(&[0x0A], 8), Some((10, 1)));
93 }
94
95 #[test]
97 fn decode_max_prefix() {
98 assert_eq!(decode_prefix_integer(&[0x2A], 8), Some((42, 1)));
99 }
100
101 #[test]
103 fn decode_multi_byte() {
104 let data = [0x1F, 0x9A, 0x0A];
105 assert_eq!(decode_prefix_integer(&data, 5), Some((1337, 3)));
106 }
107
108 #[test]
109 fn decode_empty_rejected() {
110 assert_eq!(decode_prefix_integer(&[], 5), None);
111 assert_eq!(decode_prefix_integer(&[0x00], 0), None);
112 assert_eq!(decode_prefix_integer(&[0x00], 9), None);
113 }
114
115 #[test]
117 fn decode_overflow_rejected() {
118 let data = [0x1F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01];
119 assert_eq!(decode_prefix_integer(&data, 5), None);
120 }
121
122 #[test]
124 fn decode_never_terminating_rejected() {
125 assert_eq!(decode_prefix_integer(&[0xFF; 16], 7), None);
126 }
127
128 #[test]
130 fn decode_truncated_rejected() {
131 assert_eq!(decode_prefix_integer(&[0xFF], 7), None);
132 }
133
134 #[test]
136 fn encode_decode_roundtrip() {
137 let cases: &[(u64, u8, u8)] = &[
138 (5, 7, 0x00),
139 (10, 5, 0x00),
140 (127, 7, 0x00),
141 (128, 7, 0x00),
142 (1337, 7, 0x00),
143 (65535, 7, 0x00),
144 (u32::MAX as u64, 7, 0x00),
145 (i64::MAX as u64, 7, 0x00),
148 (42, 8, 0x00),
149 (1, 4, 0x10),
150 (2, 6, 0x40),
151 (3, 6, 0x80),
152 ];
153 for &(value, prefix_bits, pattern) in cases {
154 let mut out = Vec::new();
155 encode_prefix_integer(&mut out, value, prefix_bits, pattern);
156 let (decoded, consumed) = decode_prefix_integer(&out, prefix_bits).unwrap();
157 assert_eq!(decoded, value, "value {value} (prefix {prefix_bits})");
158 assert_eq!(consumed, out.len());
159 }
160 }
161
162 #[test]
164 fn encode_preserves_prefix_pattern() {
165 let mut out = Vec::new();
166 encode_prefix_integer(&mut out, 5, 7, 0x80);
167 assert_eq!(out, vec![0x85]); let mut out = Vec::new();
169 encode_prefix_integer(&mut out, 1, 6, 0x40);
170 assert_eq!(out, vec![0x41]); }
172}