use crate::{
Buf,
BufError::{self},
BufMut, BufResult, Codec, Cursor,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct VariableLengthInteger(pub u64);
impl VariableLengthInteger {
pub const MAX: u64 = (1 << 62) - 1;
pub const MIN: u64 = 0;
pub const ZERO: Self = VariableLengthInteger(0);
pub const MAX_VARINT: Self = VariableLengthInteger(Self::MAX);
pub fn new(value: u64) -> BufResult<Self> {
if value > Self::MAX {
Err(BufError::UnexpectedValue)
} else {
Ok(VariableLengthInteger(value))
}
}
pub const fn new_const(value: u64) -> Self {
if value > Self::MAX {
panic!("Variable-length integer value exceeded 2^62 - 1")
} else {
VariableLengthInteger(value)
}
}
pub const fn into_inner(self) -> u64 {
self.0
}
pub fn encoded_length(&self) -> usize {
if self.0 <= 63 {
1
} else if self.0 <= 16_383 {
2
} else if self.0 <= 1_073_741_823 {
4
} else {
8
}
}
}
impl TryFrom<u64> for VariableLengthInteger {
type Error = BufError;
fn try_from(val: u64) -> Result<Self, Self::Error> {
VariableLengthInteger::new(val)
}
}
impl From<VariableLengthInteger> for u64 {
fn from(v: VariableLengthInteger) -> Self {
v.0
}
}
impl From<u8> for VariableLengthInteger {
fn from(val: u8) -> Self {
VariableLengthInteger(val as u64)
}
}
impl From<u16> for VariableLengthInteger {
fn from(val: u16) -> Self {
VariableLengthInteger(val as u64)
}
}
impl From<u32> for VariableLengthInteger {
fn from(val: u32) -> Self {
VariableLengthInteger(val as u64)
}
}
#[cfg(feature = "std")]
impl std::ops::Deref for VariableLengthInteger {
type Target = u64;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(feature = "std")]
impl std::fmt::Display for VariableLengthInteger {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Codec for VariableLengthInteger {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
let len = self.encoded_length();
match len {
1 => (self.0 as u8).encode(writer, ()),
2 => {
let val = ((0b01u16) << 14) | (self.0 as u16);
(&val.to_be_bytes()).encode(writer, ())
}
4 => {
let val = ((0b10u32) << 30) | (self.0 as u32);
(&val.to_be_bytes()).encode(writer, ())
}
8 => {
let val = ((0b11u64) << 62) | self.0;
(&val.to_be_bytes()).encode(writer, ())
}
_ => Err(BufError::UnexpectedValue),
}
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let first_byte = reader.peek_u8()?;
let tag = first_byte >> 6;
let len = 1 << tag;
match len {
1 => {
reader.advance(1)?;
Ok(VariableLengthInteger((first_byte & 0x3F) as u64))
}
2 => {
let mut bytes = reader.read_array::<2>()?;
bytes[0] &= 0x3F;
Ok(VariableLengthInteger(u16::from_be_bytes(bytes) as u64))
}
4 => {
let mut bytes = reader.read_array::<4>()?;
bytes[0] &= 0x3F;
Ok(VariableLengthInteger(u32::from_be_bytes(bytes) as u64))
}
8 => {
let mut bytes = reader.read_array::<8>()?;
bytes[0] &= 0x3F;
Ok(VariableLengthInteger(u64::from_be_bytes(bytes)))
}
_ => Err(BufError::UnexpectedValue),
}
}
}
pub type VarInt = VariableLengthInteger;
#[cfg(test)]
mod tests {
use crate::{Codec, Cursor, ietf::quicv1::VariableLengthInteger};
#[test]
fn variable_length_integer() {
let bytes = &[0x25];
let varint = VariableLengthInteger::decode(&mut Cursor::new(bytes), ()).unwrap();
let expected_value = 37;
assert_eq!(varint.into_inner(), expected_value);
let bytes = &[0x7b, 0x40];
let varint = VariableLengthInteger::decode(&mut Cursor::new(bytes), ()).unwrap();
let expected_value = 15168;
assert_eq!(varint.into_inner(), expected_value);
let bytes = &[0x9d, 0x7f, 0x3e, 0x7d];
let varint = VariableLengthInteger::decode(&mut Cursor::new(bytes), ()).unwrap();
let expected_value = 494_878_333;
assert_eq!(varint.into_inner(), expected_value);
let bytes = &[0xc2, 0x19, 0x7c, 0x5e, 0x2f, 0x3b, 0x5a, 0x4d];
let varint = VariableLengthInteger::decode(&mut Cursor::new(bytes), ()).unwrap();
let expected_value = 151_288_806_454_811_213;
assert_eq!(varint.into_inner(), expected_value);
}
#[test]
fn rfc_roundtrip() {
let examples: &[u64] = &[37, 15_168, 494_878_333, 151_288_806_454_811_213];
let expected_bytes: &[&[u8]] = &[
&[0x25],
&[0x7b, 0x40],
&[0x9d, 0x7f, 0x3e, 0x7d],
&[0xc2, 0x19, 0x7c, 0x5e, 0x2f, 0x3b, 0x5a, 0x4d],
];
for (val, expected) in examples.iter().zip(expected_bytes.iter()) {
let varint = VariableLengthInteger::new(*val).unwrap();
let mut buf = [0u8; 8];
varint.encode(&mut Cursor::new(&mut buf), ()).unwrap();
let len = varint.encoded_length();
assert_eq!(&buf[..len], *expected);
}
}
}