use crate::error::{CrafterError, Result};
pub const QUIC_VARINT_ONE_BYTE_MAX: u64 = (1 << 6) - 1;
pub const QUIC_VARINT_TWO_BYTE_MAX: u64 = (1 << 14) - 1;
pub const QUIC_VARINT_FOUR_BYTE_MAX: u64 = (1 << 30) - 1;
pub const QUIC_VARINT_MAX: u64 = (1u64 << 62) - 1;
const QUIC_VARINT_TWO_BYTE_PREFIX: u16 = 0x4000;
const QUIC_VARINT_FOUR_BYTE_PREFIX: u32 = 0x8000_0000;
const QUIC_VARINT_EIGHT_BYTE_PREFIX: u64 = 0xc000_0000_0000_0000;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QuicVarInt {
value: u64,
}
impl QuicVarInt {
pub const fn new(value: u64) -> Result<Self> {
if value <= QUIC_VARINT_MAX {
Ok(Self { value })
} else {
Err(CrafterError::invalid_field_value(
"quic.varint",
"QUIC varint value exceeds 62 bits",
))
}
}
pub const fn from_u64_unchecked(value: u64) -> Self {
Self { value }
}
pub const fn value(self) -> u64 {
self.value
}
pub const fn encoded_len(self) -> Result<usize> {
encoded_len_for_value(self.value)
}
pub fn encode(self, out: &mut Vec<u8>) -> Result<usize> {
let len = self.encoded_len()?;
self.encode_with_len(len, out)?;
Ok(len)
}
pub fn encode_to_vec(self) -> Result<Vec<u8>> {
let mut out = Vec::with_capacity(self.encoded_len()?);
self.encode(&mut out)?;
Ok(out)
}
pub fn encode_with_len(self, len: usize, out: &mut Vec<u8>) -> Result<()> {
encode_value_with_len(self.value, len, out)
}
pub fn encode_placeholder(self, out: &mut Vec<u8>) -> Result<()> {
self.encode(out).map(|_| ())
}
pub fn decode(bytes: &[u8]) -> Result<(Self, usize)> {
decode(bytes)
}
pub fn decode_placeholder(bytes: &[u8]) -> Result<(Self, usize)> {
Self::decode(bytes)
}
}
pub const fn quic_varint(value: u64) -> Result<QuicVarInt> {
QuicVarInt::new(value)
}
pub const fn encoded_len_for_value(value: u64) -> Result<usize> {
if value <= QUIC_VARINT_ONE_BYTE_MAX {
Ok(1)
} else if value <= QUIC_VARINT_TWO_BYTE_MAX {
Ok(2)
} else if value <= QUIC_VARINT_FOUR_BYTE_MAX {
Ok(4)
} else if value <= QUIC_VARINT_MAX {
Ok(8)
} else {
Err(CrafterError::invalid_field_value(
"quic.varint",
"QUIC varint value exceeds 62 bits",
))
}
}
pub fn encode_value(value: u64, out: &mut Vec<u8>) -> Result<usize> {
QuicVarInt::new(value)?.encode(out)
}
pub fn encode_value_with_len(value: u64, len: usize, out: &mut Vec<u8>) -> Result<()> {
match len {
1 if value <= QUIC_VARINT_ONE_BYTE_MAX => out.push(value as u8),
2 if value <= QUIC_VARINT_TWO_BYTE_MAX => {
out.extend_from_slice(&((value as u16) | QUIC_VARINT_TWO_BYTE_PREFIX).to_be_bytes());
}
4 if value <= QUIC_VARINT_FOUR_BYTE_MAX => {
out.extend_from_slice(&((value as u32) | QUIC_VARINT_FOUR_BYTE_PREFIX).to_be_bytes());
}
8 if value <= QUIC_VARINT_MAX => {
out.extend_from_slice(&(value | QUIC_VARINT_EIGHT_BYTE_PREFIX).to_be_bytes());
}
1 | 2 | 4 | 8 => {
return Err(CrafterError::invalid_field_value(
"quic.varint",
"value does not fit requested QUIC varint length",
))
}
_ => {
return Err(CrafterError::invalid_field_value(
"quic.varint.length",
"QUIC varint length must be 1, 2, 4, or 8 bytes",
))
}
}
Ok(())
}
pub fn decode(bytes: &[u8]) -> Result<(QuicVarInt, usize)> {
let Some(first) = bytes.first().copied() else {
return Err(CrafterError::buffer_too_short("quic.varint", 1, 0));
};
let len = encoded_len_from_prefix(first);
if bytes.len() < len {
return Err(CrafterError::buffer_too_short(
"quic.varint",
len,
bytes.len(),
));
}
let value = match len {
1 => (first & 0x3f) as u64,
2 => (u16::from_be_bytes([bytes[0], bytes[1]]) & 0x3fff) as u64,
4 => (u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) & 0x3fff_ffff) as u64,
8 => {
u64::from_be_bytes([
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
]) & 0x3fff_ffff_ffff_ffff
}
_ => unreachable!("QUIC varint prefix maps only to 1, 2, 4, or 8 bytes"),
};
Ok((QuicVarInt::from_u64_unchecked(value), len))
}
pub const fn encoded_len_from_prefix(first: u8) -> usize {
match first >> 6 {
0 => 1,
1 => 2,
2 => 4,
_ => 8,
}
}
pub const fn is_shortest_encoding(value: u64, encoded_len: usize) -> bool {
if value <= QUIC_VARINT_ONE_BYTE_MAX {
encoded_len == 1
} else if value <= QUIC_VARINT_TWO_BYTE_MAX {
encoded_len == 2
} else if value <= QUIC_VARINT_FOUR_BYTE_MAX {
encoded_len == 4
} else if value <= QUIC_VARINT_MAX {
encoded_len == 8
} else {
false
}
}
#[cfg(test)]
mod tests {
use super::*;
fn encoded(value: u64) -> Vec<u8> {
QuicVarInt::new(value).unwrap().encode_to_vec().unwrap()
}
#[test]
fn quic_varint_encoding_uses_shortest_widths_at_boundaries() {
assert_eq!(encoded(0), [0x00]);
assert_eq!(encoded(QUIC_VARINT_ONE_BYTE_MAX), [0x3f]);
assert_eq!(encoded(QUIC_VARINT_ONE_BYTE_MAX + 1), [0x40, 0x40]);
assert_eq!(encoded(QUIC_VARINT_TWO_BYTE_MAX), [0x7f, 0xff]);
assert_eq!(
encoded(QUIC_VARINT_TWO_BYTE_MAX + 1),
[0x80, 0x00, 0x40, 0x00]
);
assert_eq!(encoded(QUIC_VARINT_FOUR_BYTE_MAX), [0xbf, 0xff, 0xff, 0xff]);
assert_eq!(
encoded(QUIC_VARINT_FOUR_BYTE_MAX + 1),
[0xc0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00]
);
assert_eq!(
encoded(QUIC_VARINT_MAX),
[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
);
}
#[test]
fn quic_varint_encoding_reports_canonical_lengths() {
assert_eq!(encoded_len_for_value(0).unwrap(), 1);
assert_eq!(encoded_len_for_value(64).unwrap(), 2);
assert_eq!(encoded_len_for_value(16_384).unwrap(), 4);
assert_eq!(encoded_len_for_value(1_073_741_824).unwrap(), 8);
}
#[test]
fn quic_varint_encoding_supports_explicit_valid_widths() {
let mut out = Vec::new();
encode_value_with_len(63, 1, &mut out).unwrap();
encode_value_with_len(64, 2, &mut out).unwrap();
encode_value_with_len(16_384, 4, &mut out).unwrap();
encode_value_with_len(1_073_741_824, 8, &mut out).unwrap();
assert_eq!(
out,
[
0x3f, 0x40, 0x40, 0x80, 0x00, 0x40, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
0x00,
]
);
}
#[test]
fn quic_varint_encoding_rejects_impossible_values_and_widths() {
assert_eq!(
QuicVarInt::new(QUIC_VARINT_MAX + 1).unwrap_err(),
CrafterError::invalid_field_value("quic.varint", "QUIC varint value exceeds 62 bits")
);
let mut out = Vec::new();
assert_eq!(
encode_value_with_len(64, 1, &mut out).unwrap_err(),
CrafterError::invalid_field_value(
"quic.varint",
"value does not fit requested QUIC varint length"
)
);
assert_eq!(
encode_value_with_len(0, 3, &mut out).unwrap_err(),
CrafterError::invalid_field_value(
"quic.varint.length",
"QUIC varint length must be 1, 2, 4, or 8 bytes"
)
);
assert!(out.is_empty());
}
#[test]
fn quic_varint_decode_errors_report_empty_and_truncated_inputs() {
assert_eq!(
decode(&[]).unwrap_err(),
CrafterError::buffer_too_short("quic.varint", 1, 0)
);
assert_eq!(
decode(&[0x40]).unwrap_err(),
CrafterError::buffer_too_short("quic.varint", 2, 1)
);
assert_eq!(
decode(&[0x80, 0x00, 0x00]).unwrap_err(),
CrafterError::buffer_too_short("quic.varint", 4, 3)
);
assert_eq!(
decode(&[0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]).unwrap_err(),
CrafterError::buffer_too_short("quic.varint", 8, 7)
);
}
#[test]
fn quic_varint_decode_errors_consume_one_complete_value() {
let cases: &[(&[u8], u64, usize)] = &[
(&[0x25, 0xaa], 0x25, 1),
(&[0x40, 0x25, 0xaa], 0x25, 2),
(&[0x80, 0x00, 0x00, 0x25, 0xaa], 0x25, 4),
(
&[0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0xaa],
0x25,
8,
),
];
for (bytes, expected, consumed) in cases {
let (decoded, actual_consumed) = decode(bytes).unwrap();
assert_eq!(decoded.value(), *expected);
assert_eq!(actual_consumed, *consumed);
assert_eq!(bytes[actual_consumed], 0xaa);
}
}
#[test]
fn quic_varint_decode_errors_cover_overlong_and_maximum_values() {
let (overlong, consumed) = decode(&[0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25])
.expect("complete overlong value decodes");
assert_eq!(overlong.value(), 0x25);
assert_eq!(consumed, 8);
assert!(!is_shortest_encoding(overlong.value(), consumed));
let (max, consumed) = decode(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])
.expect("maximum value decodes");
assert_eq!(max.value(), QUIC_VARINT_MAX);
assert_eq!(consumed, 8);
assert!(is_shortest_encoding(max.value(), consumed));
}
}