musli_common/int/
continuation.rs

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
86
87
88
89
90
91
92
93
94
95
//! A variable-length 7-bit encoder where each bit indicates if there is a
//! continuation of the sequence or not.
//!
//! ```
//! # use musli_common::exports::context::Ignore;
//! # use musli_common::exports::fixed::FixedBytes;
//! # use musli_common::exports::allocator;
//! # use musli_common::int::continuation as c;
//! let mut buf = allocator::buffer();
//! let alloc = allocator::new(&mut buf);
//!
//! let cx = Ignore::marker(&alloc);
//! let mut bytes = FixedBytes::<8>::new();
//! c::encode(&cx, &mut bytes, 5000u32).unwrap();
//! assert_eq!(bytes.as_slice(), &[0b1000_1000, 0b0010_0111]);
//!
//! let cx = Ignore::marker(&alloc);
//! let number: u32 = c::decode(&cx, bytes.as_slice()).unwrap();
//! assert_eq!(number, 5000u32);
//! ```

#![allow(unused)]

use musli::de;
use musli::Context;

use crate::int;
use crate::reader::Reader;
use crate::writer::Writer;

use super::Unsigned;

const MASK_BYTE: u8 = 0b0111_1111;
const CONT_BYTE: u8 = 0b1000_0000;

/// Decode the given length using variable int encoding.
#[inline(never)]
pub fn decode<'de, C, R, T>(cx: &C, mut r: R) -> Result<T, C::Error>
where
    C: ?Sized + Context,
    R: Reader<'de>,
    T: int::Unsigned,
{
    let mut b = r.read_byte(cx)?;

    if b & 0b1000_0000 == 0 {
        return Ok(T::from_byte(b));
    }

    let mut value = T::from_byte(b & MASK_BYTE);
    let mut shift = 0u32;

    while b & CONT_BYTE == CONT_BYTE {
        shift += 7;

        if shift >= T::BITS {
            return Err(cx.message("Bits overflow"));
        }

        b = r.read_byte(cx)?;
        value = value.wrapping_add(T::from_byte(b & MASK_BYTE).wrapping_shl(shift));
    }

    Ok(value)
}

/// Encode the given length using variable length encoding.
#[inline(never)]
pub fn encode<C, W, T>(cx: &C, mut w: W, mut value: T) -> Result<(), C::Error>
where
    C: ?Sized + Context,
    W: Writer,
    T: int::Unsigned,
{
    let mut b = value.as_byte();

    if value < T::from_byte(0b1000_0000) {
        w.write_byte(cx, b)?;
        return Ok(());
    }

    loop {
        value = value >> 7;

        if value.is_zero() {
            w.write_byte(cx, b & MASK_BYTE)?;
            break;
        }

        w.write_byte(cx, b | CONT_BYTE)?;
        b = value.as_byte();
    }

    Ok(())
}