use crate::{
fmt::{const_debug_assert, debug_assert, debug_assert_eq},
types::TooLargeToEncode,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct VarByteInt(u32);
impl VarByteInt {
pub const MAX_ENCODABLE: u32 = 268_435_455;
#[must_use]
pub const fn new(value: u32) -> Option<Self> {
if value > Self::MAX_ENCODABLE {
None
} else {
Some(Self(value))
}
}
#[must_use]
pub const fn new_unchecked(value: u32) -> Self {
const_debug_assert!(
value <= Self::MAX_ENCODABLE,
"the value exceeds MAX_ENCODABLE"
);
Self(value)
}
#[must_use]
pub const fn value(&self) -> u32 {
self.0
}
#[must_use]
pub const fn size(&self) -> usize {
self.0 as usize
}
pub(crate) fn from_slice_unchecked(slice: &[u8]) -> Self {
let mut multiplier = 1;
let mut value = 0;
debug_assert!(
!slice.is_empty() && slice.len() <= 4,
"encodings are always 1..=4 bytes long, {} is invalid",
slice.len()
);
debug_assert_eq!(
slice.last().unwrap() & 128,
0,
"the last byte of the encoding must not have bit 7 set"
);
for b in slice {
value += u32::from(b & 0x7F) * multiplier;
multiplier *= 128;
if b & 128 == 0 {
break;
}
}
Self::new_unchecked(value)
}
}
impl TryFrom<u32> for VarByteInt {
type Error = TooLargeToEncode;
fn try_from(value: u32) -> Result<Self, Self::Error> {
Self::new(value).ok_or(TooLargeToEncode)
}
}
impl From<u16> for VarByteInt {
fn from(value: u16) -> Self {
Self(u32::from(value))
}
}
impl From<u8> for VarByteInt {
fn from(value: u8) -> Self {
Self(u32::from(value))
}
}