use bytes::{Buf, BufMut};
pub const MAX_VARINT: u64 = 4_611_686_018_427_387_903;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct VarInt(u64);
#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)]
pub enum VarIntError {
#[error("value {0} exceeds maximum varint value (2^62 - 1)")]
Overflow(u64),
#[error("insufficient bytes for varint decoding")]
UnexpectedEnd,
#[error("7-byte varint is not a defined encoding length in draft-17")]
InvalidCodePoint,
}
impl VarInt {
#[inline]
pub fn from_u64(v: u64) -> Result<Self, VarIntError> {
if v > MAX_VARINT {
Err(VarIntError::Overflow(v))
} else {
Ok(VarInt(v))
}
}
#[inline]
pub fn into_inner(self) -> u64 {
self.0
}
#[inline]
pub fn encoded_len(&self) -> usize {
if self.0 <= 63 {
1
} else if self.0 <= 16383 {
2
} else if self.0 <= 1073741823 {
4
} else {
8
}
}
#[inline]
pub fn encode(&self, buf: &mut impl BufMut) {
match self.encoded_len() {
1 => {
buf.put_u8(self.0 as u8);
}
2 => {
buf.put_u16((self.0 as u16) | 0x4000);
}
4 => {
buf.put_u32((self.0 as u32) | 0x80000000);
}
8 => {
buf.put_u64(self.0 | 0xC000000000000000);
}
_ => unreachable!(),
}
}
#[inline]
pub fn decode(buf: &mut impl Buf) -> Result<Self, VarIntError> {
if buf.remaining() < 1 {
return Err(VarIntError::UnexpectedEnd);
}
let first = buf.chunk()[0];
let prefix = first >> 6;
let len = 1usize << prefix;
if buf.remaining() < len {
return Err(VarIntError::UnexpectedEnd);
}
let val = match len {
1 => {
buf.advance(1);
(first & 0x3F) as u64
}
2 => {
let v = buf.get_u16();
(v & 0x3FFF) as u64
}
4 => {
let v = buf.get_u32();
(v & 0x3FFFFFFF) as u64
}
8 => {
let v = buf.get_u64();
v & 0x3FFFFFFFFFFFFFFF
}
_ => unreachable!(),
};
Ok(VarInt(val))
}
}
pub const MAX_MOQT_VARINT: u64 = u64::MAX;
impl VarInt {
#[inline]
pub fn from_u64_moqt(v: u64) -> Self {
VarInt(v)
}
#[inline]
fn encoded_len_moqt(&self, seven_byte: bool) -> usize {
for len in 1..=8 {
if (len != 7 || seven_byte) && self.0 < 1u64 << (7 * len) {
return len;
}
}
9
}
#[inline]
fn encode_moqt_inner(&self, buf: &mut impl BufMut, seven_byte: bool) {
let len = self.encoded_len_moqt(seven_byte);
if len == 9 {
buf.put_u8(0xFF);
buf.put_u64(self.0);
return;
}
let prefix = (((1u16 << (len - 1)) - 1) << (9 - len)) as u8;
let combined = ((prefix as u64) << (8 * (len - 1))) | self.0;
for i in (0..len).rev() {
buf.put_u8((combined >> (8 * i)) as u8);
}
}
#[inline]
fn decode_moqt_inner(buf: &mut impl Buf, seven_byte: bool) -> Result<Self, VarIntError> {
if buf.remaining() < 1 {
return Err(VarIntError::UnexpectedEnd);
}
let first = buf.chunk()[0];
if first == 0xFF {
if buf.remaining() < 9 {
return Err(VarIntError::UnexpectedEnd);
}
buf.advance(1);
return Ok(VarInt(buf.get_u64()));
}
let len = first.leading_ones() as usize + 1;
if len == 7 && !seven_byte {
return Err(VarIntError::InvalidCodePoint);
}
if buf.remaining() < len {
return Err(VarIntError::UnexpectedEnd);
}
let mut val = (first & ((1u16 << (8 - len)) - 1) as u8) as u64;
buf.advance(1);
for _ in 1..len {
val = (val << 8) | buf.get_u8() as u64;
}
Ok(VarInt(val))
}
#[inline]
pub fn encode_moqt<P: MoqtProfile>(&self, buf: &mut impl BufMut) {
self.encode_moqt_inner(buf, P::SEVEN_BYTE);
}
#[inline]
pub fn decode_moqt<P: MoqtProfile>(buf: &mut impl Buf) -> Result<Self, VarIntError> {
Self::decode_moqt_inner(buf, P::SEVEN_BYTE)
}
}
mod sealed {
pub trait Sealed {}
impl Sealed for super::Moqt17 {}
impl Sealed for super::Moqt18 {}
}
pub trait MoqtProfile: sealed::Sealed {
const SEVEN_BYTE: bool;
}
pub struct Moqt17;
pub struct Moqt18;
impl MoqtProfile for Moqt17 {
const SEVEN_BYTE: bool = false;
}
impl MoqtProfile for Moqt18 {
const SEVEN_BYTE: bool = true;
}
impl TryFrom<u64> for VarInt {
type Error = VarIntError;
#[inline]
fn try_from(v: u64) -> Result<Self, Self::Error> {
Self::from_u64(v)
}
}
impl From<VarInt> for u64 {
#[inline]
fn from(v: VarInt) -> u64 {
v.0
}
}
impl VarInt {
#[inline]
pub fn from_usize(v: usize) -> Self {
VarInt(v as u64)
}
}
impl From<u32> for VarInt {
#[inline]
fn from(v: u32) -> Self {
VarInt(v as u64)
}
}