use core::fmt;
const MAX_VALUE: u64 = (1 << 62) - 1;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum QuicVarIntParseError {
Incomplete {
required: usize,
available: usize,
},
}
impl fmt::Display for QuicVarIntParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Incomplete {
required,
available,
} => write!(
f,
"QUIC variable-length integer input is incomplete: need {required} bytes, have {available}"
),
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum QuicVarIntLen {
One,
Two,
Four,
Eight,
}
impl QuicVarIntLen {
pub const fn byte_len(self) -> usize {
match self {
Self::One => 1,
Self::Two => 2,
Self::Four => 4,
Self::Eight => 8,
}
}
pub const fn max_value(self) -> u64 {
match self {
Self::One => 63,
Self::Two => 16_383,
Self::Four => 1_073_741_823,
Self::Eight => MAX_VALUE,
}
}
const fn prefix(self) -> u8 {
match self {
Self::One => 0b00,
Self::Two => 0b01,
Self::Four => 0b10,
Self::Eight => 0b11,
}
}
const fn from_first_byte(first: u8) -> Self {
match first >> 6 {
0 => Self::One,
1 => Self::Two,
2 => Self::Four,
_ => Self::Eight,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum QuicVarIntBuildError {
ValueTooLarge {
value: u64,
},
WidthTooSmall {
length: QuicVarIntLen,
value: u64,
},
BufferTooShort {
required: usize,
available: usize,
},
}
impl fmt::Display for QuicVarIntBuildError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::ValueTooLarge { value } => write!(
f,
"QUIC variable-length integer value {value} exceeds the 62-bit maximum"
),
Self::WidthTooSmall { length, value } => write!(
f,
"QUIC variable-length integer width {} cannot represent {value}",
length.byte_len()
),
Self::BufferTooShort {
required,
available,
} => write!(
f,
"QUIC variable-length integer buffer is too short: need {required} bytes, have {available}"
),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct QuicVarInt<'a> {
bytes: &'a [u8],
value: u64,
length: QuicVarIntLen,
}
impl<'a> QuicVarInt<'a> {
pub(crate) const fn from_validated(bytes: &'a [u8], value: u64, length: QuicVarIntLen) -> Self {
Self {
bytes,
value,
length,
}
}
pub fn parse(bytes: &'a [u8]) -> Result<Self, QuicVarIntParseError> {
let first = *bytes.first().ok_or(QuicVarIntParseError::Incomplete {
required: 1,
available: 0,
})?;
let length = QuicVarIntLen::from_first_byte(first);
let required = length.byte_len();
if bytes.len() < required {
return Err(QuicVarIntParseError::Incomplete {
required,
available: bytes.len(),
});
}
let exact = &bytes[..required];
let mut value = u64::from(exact[0] & 0x3f);
let mut index = 1;
while index < required {
value = (value << 8) | u64::from(exact[index]);
index += 1;
}
Ok(Self {
bytes: exact,
value,
length,
})
}
pub const fn value(self) -> u64 {
self.value
}
pub const fn as_bytes(self) -> &'a [u8] {
self.bytes
}
pub const fn encoded_len(self) -> QuicVarIntLen {
self.length
}
pub const fn byte_len(self) -> usize {
self.length.byte_len()
}
pub const fn is_canonical(self) -> bool {
self.length as u8 == canonical_len(self.value) as u8
}
}
pub struct QuicVarIntBuilder<'a> {
destination: &'a mut [u8],
value: u64,
length: Option<QuicVarIntLen>,
}
impl<'a> QuicVarIntBuilder<'a> {
pub fn new(destination: &'a mut [u8], value: u64) -> Self {
Self {
destination,
value,
length: None,
}
}
pub fn with_len(mut self, length: QuicVarIntLen) -> Self {
self.length = Some(length);
self
}
pub fn build(self) -> Result<QuicVarInt<'a>, QuicVarIntBuildError> {
if self.value > MAX_VALUE {
return Err(QuicVarIntBuildError::ValueTooLarge { value: self.value });
}
let length = self.length.unwrap_or(canonical_len(self.value));
if self.value > length.max_value() {
return Err(QuicVarIntBuildError::WidthTooSmall {
length,
value: self.value,
});
}
let required = length.byte_len();
if self.destination.len() < required {
return Err(QuicVarIntBuildError::BufferTooShort {
required,
available: self.destination.len(),
});
}
let exact = &mut self.destination[..required];
let value_bytes = self.value.to_be_bytes();
exact.copy_from_slice(&value_bytes[value_bytes.len() - required..]);
exact[0] |= length.prefix() << 6;
Ok(QuicVarInt {
bytes: exact,
value: self.value,
length,
})
}
}
const fn canonical_len(value: u64) -> QuicVarIntLen {
if value <= QuicVarIntLen::One.max_value() {
QuicVarIntLen::One
} else if value <= QuicVarIntLen::Two.max_value() {
QuicVarIntLen::Two
} else if value <= QuicVarIntLen::Four.max_value() {
QuicVarIntLen::Four
} else {
QuicVarIntLen::Eight
}
}