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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
//! ### Variable-Length Integer Encoding
//!
//! This encoding ensures that smaller integer values need fewer bytes to encode. Support types are `L2` and `L3`.
//!
//! By default, `L2` (u15) is used to encode length (integer) for record. But you override it by setting `L3` (u22) in features flag.
//!
//! Encoding algorithm is very straightforward, reserving one or two most significant bits of the first byte to encode rest of the length.
//!
//! #### L2
//!
//! | MSB | Length | Usable Bits | Range |
//! | :---: | :----: | :---------: | :------- |
//! | 0 | 1 | 7 | 0..127 |
//! | 1 | 2 | 15 | 0..32767 |
//!
//!
//! #### L3
//!
//! | MSB | Length | Usable Bits | Range |
//! | :---: | :----: | :---------: | :--------- |
//! | 0 | 1 | 7 | 0..127 |
//! | 10 | 2 | 14 | 0..16383 |
//! | 11 | 3 | 22 | 0..4194303 |
//!
//!
//! For example, Binary representation of `0x_C0DE` is `0x_11_00000011_011110`
//!
//! `L3(0x_C0DE)` is encoded in 3 bytes:
//!
//! ```text
//! 1st byte: 11_011110 # MSB is 11, so read next 2 bytes
//! 2nd byte: 11
//! 3rd byte: 11
//! ```
//!
//! Another example, `L3(107)` is encoded in just 1 byte:
//!
//! ```text
//! 1st byte: 0_1101011 # MSB is 0, So we don't have to read another bytes.
//! ```
use crate::*;
#[cfg(not(feature = "L3"))]
pub use L2 as Lencoder;
#[cfg(feature = "L3")]
pub use L3 as Lencoder;
macro_rules! def {
[$name:ident($ty:ty), LenSize: $size:literal, MAX: $MAX:literal, $encoder:item, $decoder:item] => {
#[derive(Default, Debug, Clone, Copy)]
pub struct $name(pub $ty);
impl $name { pub const MAX: $ty = $MAX; }
impl Encoder for $name {
const SIZE: usize = $size;
#[inline] $encoder
}
impl<E: Error> Decoder<'_, E> for $name { #[inline] $decoder }
impl From<$ty> for $name { fn from(num: $ty) -> Self { Self(num) } }
impl core::ops::Deref for $name {
type Target = $ty;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl core::ops::DerefMut for $name {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}
};
}
def!(
L2(u16),
LenSize: 2,
MAX: 0x7FFF,
fn encoder(self, c: &mut Cursor<impl Bytes>) {
let num = self.0;
let b1 = num as u8;
if num < 128 {
b1.encoder(c); // No MSB is set, Bcs `num` is less then `128`
} else {
debug_assert!(num <= Self::MAX);
let b1 = 0x80 | b1; // 7 bits with MSB is set.
let b2 = (num >> 7) as u8; // next 8 bits
c.write_slice([b1, b2]);
}
},
fn decoder(c: &mut Cursor<&[u8]>) -> Result<Self, E> {
let mut num = u8::decoder(c)? as u16;
// if MSB is set, read another byte.
if num >> 7 == 1 {
let snd = u8::decoder(c)? as u16;
num = (num & 0x7F) | snd << 7; // num <- add 8 bits
}
Ok(Self(num))
}
);
def!(
L3(u32),
LenSize: 3,
MAX: 0x3FFFFF,
fn encoder(self, c: &mut Cursor<impl Bytes>) {
let num = self.0;
let b1 = num as u8;
if num < 128 {
b1.encoder(c);
}
else {
let b1 = b1 & 0x3F; // read last 6 bits
let b2 = (num >> 6) as u8; // next 8 bits
if num < 0x4000 {
// set first 2 bits of `b1` to `10`
c.write_slice([0x80 | b1, b2]);
}
else {
debug_assert!(num <= Self::MAX);
let b3 = (num >> 14) as u8; // next 8 bits
// set first 2 bits of `b1` to `11`
c.write_slice([0xC0 | b1, b2, b3]);
}
}
},
fn decoder(c: &mut Cursor<& [u8]>) -> Result<Self, E> {
let num = u8::decoder(c)? as u32;
// if 1st bit is `0`
let num = if num >> 7 == 0 { num }
// and 2nd bit is `0`
else if num >> 6 == 2 {
let b2 = u8::decoder(c)? as u32;
(num & 0x3F) | b2 << 6
} else {
// At this point, only possible first 2 bits are `11`
let b2 = *c.data.get(c.offset).ok_or_else(E::insufficient_bytes)? as u32;
let b3 = *c.data.get(c.offset + 1).ok_or_else(E::insufficient_bytes)? as u32;
c.offset += 2;
(num & 0x3F) // get last 6 bits
| b2 << 6 // add 8 bits from 2nd byte
| b3 << 14 // add 8 bits from 3rd byte
};
Ok(Self(num))
}
);