use alloc::vec::Vec;
use arrayvec::ArrayVec;
use core::convert::{From, TryFrom};
use core::fmt;
use serde::{Serialize, Serializer};
#[cfg(feature = "std")]
use std::io::IoSlice;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VariableByteInteger {
encoded: ArrayVec<u8, 4>,
}
impl VariableByteInteger {
pub const MAX: u32 = 0x0FFF_FFFF;
pub fn from_u32(mut value: u32) -> Option<Self> {
if value > Self::MAX {
return None;
}
let mut buf = ArrayVec::<u8, 4>::new();
loop {
let mut byte = (value % 128) as u8;
value /= 128;
if value > 0 {
byte |= 0x80;
}
buf.push(byte);
if value == 0 {
break;
}
}
Some(Self { encoded: buf })
}
pub fn to_u32(&self) -> u32 {
let mut multiplier = 1u32;
let mut result = 0u32;
for &b in &*self.encoded {
result += u32::from(b & 0x7F) * multiplier;
multiplier = multiplier.saturating_mul(128);
}
result
}
pub fn size(&self) -> usize {
self.encoded.len()
}
pub fn as_bytes(&self) -> &[u8] {
&self.encoded
}
#[cfg(feature = "std")]
pub fn to_buffers(&self) -> Vec<IoSlice<'_>> {
vec![IoSlice::new(&self.encoded)]
}
pub fn to_continuous_buffer(&self) -> Vec<u8> {
self.encoded.to_vec()
}
pub fn decode_stream(buf: &[u8]) -> DecodeResult<Self> {
let mut multiplier = 1u32;
let mut value = 0u32;
let mut read = ArrayVec::<u8, 4>::new();
for (i, &b) in buf.iter().take(4).enumerate() {
value = value.saturating_add(u32::from(b & 0x7F) * multiplier);
if value > Self::MAX {
return DecodeResult::Err("VariableByteInteger too large");
}
read.push(b);
if (b & 0x80) == 0 {
return match Self::from_u32(value) {
Some(vbi) => DecodeResult::Ok(vbi, i + 1),
None => DecodeResult::Err("Encoding failure"),
};
}
multiplier = multiplier.checked_mul(128).unwrap_or(0);
}
if buf.len() < 4 {
DecodeResult::Incomplete
} else {
DecodeResult::Err("Malformed VariableByteInteger: too many bytes")
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DecodeResult<T> {
Ok(T, usize),
Incomplete,
Err(&'static str),
}
impl Serialize for VariableByteInteger {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u32(self.to_u32())
}
}
impl fmt::Display for VariableByteInteger {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_u32())
}
}
impl From<VariableByteInteger> for u32 {
fn from(vbi: VariableByteInteger) -> Self {
vbi.to_u32()
}
}
impl TryFrom<u32> for VariableByteInteger {
type Error = &'static str;
fn try_from(value: u32) -> Result<Self, Self::Error> {
VariableByteInteger::from_u32(value).ok_or("Value too large")
}
}