use core::fmt;
use crate::decode::{Decode, DecodeError};
use crate::encode::Encode;
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct VarU16 {
inner: u16,
}
impl VarU16 {
pub fn new(value: u16) -> Self {
Self::try_new(value).expect("Value too large for variable-length u16")
}
pub const fn try_new(value: u16) -> Result<Self, VarU16SizeError> {
if value > (u16::MAX >> 1) {
Err(VarU16SizeError { value })
} else {
Ok(Self { inner: value })
}
}
pub fn into_inner(self) -> u16 {
self.inner
}
pub fn check_wide(first: u8) -> bool {
first > (u8::MAX >> 1) as _
}
}
impl Encode for VarU16 {
fn size(&self) -> usize {
if self.inner > (u8::MAX >> 1) as _ {
2
} else {
1
}
}
fn encode(&self, data: &mut [u8]) {
if self.inner > (u8::MAX >> 1) as _ {
data[0] = (self.inner >> 8) as u8 | 0x80;
data[1] = (self.inner & u8::MAX as u16) as u8;
} else {
data[0] = self.inner as u8;
}
}
}
impl Decode for VarU16 {
fn decode(data: &mut &[u8]) -> Result<Self, DecodeError> {
let first = u8::decode(data)?;
let wide = first & (1 << 7) != 0;
Ok(Self {
inner: if wide {
let last = u8::decode(data)?;
let both = [first & u8::MAX >> 1, last];
u16::from_be_bytes(both)
} else {
first as u16
},
})
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct VarU16SizeError {
pub value: u16,
}
impl fmt::Display for VarU16SizeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"value {} cannot fit in a variable-length u16",
self.value
)
}
}
impl core::error::Error for VarU16SizeError {
fn description(&self) -> &str {
"value too large for variable-length u16"
}
}
#[cfg(test)]
mod tests {
use crate::{decode::Decode, encode::Encode, varint::VarU16};
#[test]
fn wide() {
const VAL: u16 = 0xF00;
const EXPECTED_ENCODING: [u8; 2] = [0x8f, 0x00];
let mut buf = [0; 2];
let var = VarU16::new(VAL);
var.encode(&mut buf);
assert_eq!(EXPECTED_ENCODING, buf);
assert_eq!(
VAL,
VarU16::decode(&mut EXPECTED_ENCODING.as_slice())
.unwrap()
.into_inner()
)
}
#[test]
fn thin() {
const VAL: u16 = 0x0F;
const EXPECTED_ENCODING: [u8; 1] = [0x0F];
let mut buf = [0; 1];
let var = VarU16::new(VAL);
var.encode(&mut buf);
assert_eq!(EXPECTED_ENCODING, buf);
assert_eq!(
VAL,
VarU16::decode(&mut EXPECTED_ENCODING.as_slice())
.unwrap()
.into_inner()
)
}
}