1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use core::mem;
/// Stateful vli decoder.
#[derive(Clone, Copy, Default, Debug)]
pub struct VliDecoder {
/// The vli as far as it has already been decoded.
vli: u64,
/// How many bits we already decoded, values about 62 are invalid.
vli_bits: u8,
}
impl VliDecoder {
/// Constructor
pub const fn new() -> Self {
Self {
vli: 0,
vli_bits: 0,
}
}
/// Reset back to initial state
pub const fn reset(&mut self) {
self.vli_bits = 0;
self.vli = 0;
}
/// Decodes a vli with a buffer that is known to hold the full vli.
/// Returns (decoded vli, amount of bytes consumed)
///
/// Returns None on `InvalidVli` or Insufficient data. This is fatal
/// and the decoder will not produce correct output anymore until reset.
pub fn decode_single(&mut self, input: &[u8]) -> Option<(u64, usize)> {
debug_assert_eq!(self.vli_bits, 0);
match self.decode(input) {
VliResult::InvalidVli | VliResult::MoreDataNeeded(_) => None,
VliResult::Ok(vli, size) => Some((vli, size)),
}
}
/// Decode a vli returning the decoded vli or potentially requesting more data.
///
/// The return value `VliResult::InvalidVli` is a fatal error
/// and the decoder will not produce correct output anymore until reset.
pub fn decode(&mut self, input: &[u8]) -> VliResult {
let mut in_pos = 0;
#[cfg(debug_assertions)]
if self.vli_bits == 0 {
debug_assert_eq!(self.vli, 0);
}
while in_pos < input.len() {
let byte = input[in_pos];
in_pos += 1;
self.vli |= u64::from(byte & 0x7f) << self.vli_bits;
if byte & 0x80 == 0 {
if byte == 0 && self.vli_bits != 0 {
return VliResult::InvalidVli;
}
self.vli_bits = 0;
return VliResult::Ok(mem::take(&mut self.vli), in_pos);
}
self.vli_bits += 7;
if self.vli_bits >= 63 {
self.vli_bits = 0;
return VliResult::InvalidVli;
}
}
VliResult::MoreDataNeeded(in_pos)
}
}
/// Result type of vli decode operation.
pub enum VliResult {
/// Vli is not valid, this is a fatal error
InvalidVli,
/// Vli is valid, (data, size of data consumed in bytes)
Ok(u64, usize),
/// Need more data (size of data consumed in bytes)
MoreDataNeeded(usize),
}