1
use std::error::Error;
2
use std::io::Read;
3
use std::io::Write;
4

            
5
use bitstream_io::BitRead;
6
use bitstream_io::BitReader;
7
use bitstream_io::BitWrite;
8
use bitstream_io::BitWriter;
9
use bitstream_io::LittleEndian;
10

            
11
/// The number of bits needed to represent a value of type T in most significant bit encoding.
12
#[allow(unused)]
13
1
pub fn encoding_size<T>() -> usize {
14
1
    ((std::mem::size_of::<T>() + 1) * 8) / 7
15
1
}
16

            
17
/// Encodes an unsigned variable-length integer using the most significant bit (MSB) algorithm.
18
/// This function assumes that the value is stored as little endian.
19
/// \param value The input value. Any standard integer type is allowed.
20
/// \param output A pointer to a piece of reserved memory. Must have a minimum size dependent on the input size (32 bit = 5 bytes, 64 bit = 10 bytes).
21
/// \returns The number of bytes used in the output.
22
/// \details Implementation taken from <https://techoverflow.net/2013/01/25/efficiently-encoding-variable-length-integers-in-cc/>
23
#[allow(unused)]
24
1
pub fn write_u64_variablelength<W: Write>(
25
1
    stream: &mut BitWriter<W, LittleEndian>,
26
1
    mut value: u64,
27
1
) -> Result<(), Box<dyn Error>> {
28
    // While more than 7 bits of data are left, occupy the last output byte
29
    // and set the next byte flag.
30
3
    while value > 0b01111111 {
31
2
        stream.write(8, (value as u8 & 0b01111111) | 0b10000000)?;
32

            
33
        // Remove the seven bits we just wrote from value.
34
2
        value >>= 7;
35
    }
36

            
37
1
    stream.write(8, value as u8)?;
38
1
    Ok(())
39
1
}
40

            
41
///  Decodes an unsigned variable-length integer using the MSB algorithm.
42
#[allow(unused)]
43
1
pub fn read_u64_variablelength<R: Read>(stream: &mut BitReader<R, LittleEndian>) -> Result<u64, Box<dyn Error>> {
44
1
    let mut value: u64 = 0;
45
3
    for i in 0..encoding_size::<u64>() {
46
3
        let byte = stream.read::<u8>(8)?;
47

            
48
        // Take 7 bits (mask 0x01111111) from byte and shift it before the bits already written to value.
49
3
        value |= ((byte & 0b01111111) as u64) << (7 * i);
50
3

            
51
3
        if byte & 0b10000000 == 0 {
52
            // If the next-byte flag is not set then we are finished.
53
1
            break;
54
2
        }
55
    }
56

            
57
1
    Ok(value)
58
1
}
59

            
60
#[cfg(test)]
61
mod tests {
62
    use super::*;
63

            
64
    #[test]
65
1
    fn test_integer_encoding() {
66
1
        let mut stream: [u8; 10] = [0; 10];
67
1
        let mut writer = BitWriter::new(&mut stream[0..]);
68
1

            
69
1
        let value = 234678;
70
1
        write_u64_variablelength(&mut writer, value).unwrap();
71
1
        writer.write(32, 0 as u64).unwrap();
72
1

            
73
1
        let mut reader = BitReader::new(&stream[0..]);
74
1
        let result = read_u64_variablelength(&mut reader).unwrap();
75
1

            
76
1
        assert_eq!(result, value);
77
1
    }
78
}