musli_binary_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_binary_common::int::continuation as c;
6//! use musli_binary_common::fixed_bytes::FixedBytes;
7//!
8//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
9//! let mut bytes = FixedBytes::<8>::new();
10//! c::encode(&mut bytes, 5000u32)?;
11//! assert_eq!(bytes.as_bytes(), &[0b1000_1000, 0b0010_0111]);
12//!
13//! let number: u32 = c::decode(bytes.as_bytes())?;
14//! assert_eq!(number, 5000u32);
15//! # Ok(()) }
16//! ```
17
18#![allow(unused)]
19
20use crate::int;
21use crate::reader::Reader;
22use crate::writer::Writer;
23use musli::error::Error;
24
25use super::Unsigned;
26
27const MASK_BYTE: u8 = 0b0111_1111;
28const CONT_BYTE: u8 = 0b1000_0000;
29
30/// Decode the given length using variable int encoding.
31#[inline(never)]
32pub fn decode<'de, R, T>(mut r: R) -> Result<T, R::Error>
33where
34    R: Reader<'de>,
35    T: int::Unsigned,
36{
37    let mut b = r.read_byte()?;
38
39    if b & 0b1000_0000 == 0 {
40        return Ok(T::from_byte(b));
41    }
42
43    let mut value = T::from_byte(b & MASK_BYTE);
44    let mut shift = 0u32;
45
46    while b & CONT_BYTE == CONT_BYTE {
47        shift += 7;
48        b = r.read_byte()?;
49
50        value = T::from_byte(b & MASK_BYTE)
51            .checked_shl(shift)
52            .and_then(|add| value.checked_add(add))
53            .ok_or_else(|| R::Error::custom("length overflow"))?;
54    }
55
56    Ok(value)
57}
58
59/// Encode the given length using variable length encoding.
60#[inline(never)]
61pub fn encode<W, T>(mut w: W, mut value: T) -> Result<(), W::Error>
62where
63    W: Writer,
64    T: int::Unsigned,
65{
66    let mut b = value.as_byte();
67
68    if value < T::from_byte(0b1000_0000) {
69        w.write_byte(b)?;
70        return Ok(());
71    }
72
73    loop {
74        value = value
75            .checked_shr(7)
76            .ok_or_else(|| W::Error::custom("length underflow"))?;
77
78        if value.is_zero() {
79            w.write_byte(b & MASK_BYTE)?;
80            break;
81        }
82
83        w.write_byte(b | CONT_BYTE)?;
84        b = value.as_byte();
85    }
86
87    Ok(())
88}