musli_common/int/
continuation.rs

1//! A variable-length 7-bit encoder where each bit indicates if there is a
2//! continuation of the sequence or not.
3//!
4//! ```
5//! # use musli_common::exports::context::Ignore;
6//! # use musli_common::exports::fixed::FixedBytes;
7//! # use musli_common::exports::allocator;
8//! # use musli_common::int::continuation as c;
9//! let mut buf = allocator::buffer();
10//! let alloc = allocator::new(&mut buf);
11//!
12//! let cx = Ignore::marker(&alloc);
13//! let mut bytes = FixedBytes::<8>::new();
14//! c::encode(&cx, &mut bytes, 5000u32).unwrap();
15//! assert_eq!(bytes.as_slice(), &[0b1000_1000, 0b0010_0111]);
16//!
17//! let cx = Ignore::marker(&alloc);
18//! let number: u32 = c::decode(&cx, bytes.as_slice()).unwrap();
19//! assert_eq!(number, 5000u32);
20//! ```
21
22#![allow(unused)]
23
24use musli::de;
25use musli::Context;
26
27use crate::int;
28use crate::reader::Reader;
29use crate::writer::Writer;
30
31use super::Unsigned;
32
33const MASK_BYTE: u8 = 0b0111_1111;
34const CONT_BYTE: u8 = 0b1000_0000;
35
36/// Decode the given length using variable int encoding.
37#[inline(never)]
38pub fn decode<'de, C, R, T>(cx: &C, mut r: R) -> Result<T, C::Error>
39where
40    C: ?Sized + Context,
41    R: Reader<'de>,
42    T: int::Unsigned,
43{
44    let mut b = r.read_byte(cx)?;
45
46    if b & 0b1000_0000 == 0 {
47        return Ok(T::from_byte(b));
48    }
49
50    let mut value = T::from_byte(b & MASK_BYTE);
51    let mut shift = 0u32;
52
53    while b & CONT_BYTE == CONT_BYTE {
54        shift += 7;
55
56        if shift >= T::BITS {
57            return Err(cx.message("Bits overflow"));
58        }
59
60        b = r.read_byte(cx)?;
61        value = value.wrapping_add(T::from_byte(b & MASK_BYTE).wrapping_shl(shift));
62    }
63
64    Ok(value)
65}
66
67/// Encode the given length using variable length encoding.
68#[inline(never)]
69pub fn encode<C, W, T>(cx: &C, mut w: W, mut value: T) -> Result<(), C::Error>
70where
71    C: ?Sized + Context,
72    W: Writer,
73    T: int::Unsigned,
74{
75    let mut b = value.as_byte();
76
77    if value < T::from_byte(0b1000_0000) {
78        w.write_byte(cx, b)?;
79        return Ok(());
80    }
81
82    loop {
83        value = value >> 7;
84
85        if value.is_zero() {
86            w.write_byte(cx, b & MASK_BYTE)?;
87            break;
88        }
89
90        w.write_byte(cx, b | CONT_BYTE)?;
91        b = value.as_byte();
92    }
93
94    Ok(())
95}