use crate::*;
use std::{
convert::{Infallible, TryFrom},
fmt,
};
#[cfg(feature = "L2")]
pub use L2 as Len;
#[cfg(not(feature = "L2"))]
pub use L3 as Len;
macro_rules! def {
[$name:ident($ty:ty), BITS: $BITS:literal, TryFromErr: $err: ty, $encoder:item, $decoder:item] => {
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct $name(pub $ty);
impl $name {
pub const MAX: $name = $name((1 << $BITS) - 1);
pub const BITS: u32 = $BITS;
}
impl Encoder for $name { #[inline] $encoder }
impl Decoder<'_> for $name { #[inline] $decoder }
impl TryFrom<usize> for $name {
type Error = String;
#[inline] fn try_from(num: usize) -> std::result::Result<Self, Self::Error> {
if num > (1 << $BITS) - 1 {
Err(format!("Max payload length is {}, But got {num}", Self::MAX.0))
} else {
Ok(Self(num as $ty))
}
}
}
impl TryFrom<$name> for usize {
type Error = $err;
#[inline] fn try_from(num: $name) -> std::result::Result<Self, Self::Error> { TryFrom::try_from(num.0) }
}
impl From<$ty> for $name { fn from(num: $ty) -> Self { Self(num) } }
impl fmt::Display for $name {
#[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) }
}
impl core::ops::Deref for $name {
type Target = $ty;
#[inline] fn deref(&self) -> &Self::Target { &self.0 }
}
impl core::ops::DerefMut for $name {
#[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}
};
}
def!(
L2(u16),
BITS: 15,
TryFromErr: Infallible,
fn encoder(&self, c: &mut impl Write) -> io::Result<()> {
let num = self.0;
let b1 = num as u8;
if num < 128 { c.write_all(&[b1]) }
else {
debug_assert!(num <= 0x7FFF);
let b1 = 0x80 | b1; let b2 = (num >> 7) as u8; c.write_all(&[b1, b2])
}
},
fn decoder(c: &mut &[u8]) -> Result<Self> {
let mut num = u8::decoder(c)? as u16;
if num >> 7 == 1 {
let snd = u8::decoder(c)? as u16;
num = (num & 0x7F) | snd << 7; }
Ok(Self(num))
}
);
def!(
L3(u32),
BITS: 22,
TryFromErr: std::num::TryFromIntError,
fn encoder(&self, c: &mut impl Write) -> io::Result<()> {
let num = self.0;
let b1 = num as u8;
if num < 128 { c.write_all(&[b1]) }
else {
let b1 = b1 & 0x3F; let b2 = (num >> 6) as u8; if num < 0x4000 {
c.write_all(&[0x80 | b1, b2])
}
else {
debug_assert!(num <= 0x3FFFFF);
let b3 = (num >> 14) as u8; c.write_all(&[0xC0 | b1, b2, b3])
}
}
},
fn decoder(c: &mut &[u8]) -> Result<Self> {
let num = u8::decoder(c)? as u32;
let num = if num >> 7 == 0 { num }
else if num >> 6 == 2 {
let b2 = u8::decoder(c)? as u32;
(num & 0x3F) | b2 << 6
} else {
let [b2, b3] = <&[u8; 2]>::decoder(c)?;
(num & 0x3F) | (*b2 as u32) << 6 | (*b3 as u32) << 14 };
Ok(Self(num))
}
);
#[cfg(test)]
mod tests {
use super::*;
macro_rules! assert_len {
[$len: expr, $expect: expr] => {
let bytes = $len.encode();
assert_eq!(bytes, $expect);
assert_eq!($len, Decoder::decode(&bytes).unwrap());
};
}
#[test]
fn l2() {
assert_len!(L2(0), [0]);
assert_len!(L2(127), [127]);
assert_len!(L2(128), [128, 1]);
assert_len!(L2(32767), [255, 255]);
}
#[test]
fn l3() {
assert_len!(L3(0), [0]);
assert_len!(L3(127), [127]);
assert_len!(L3(128), [128, 2]);
assert_len!(L3(16383), [191, 255]);
assert_len!(L3(16384), [192, 0, 1]);
assert_len!(L3(4194303), [255, 255, 255]);
}
}