233 lines
4.9 KiB
Rust
233 lines
4.9 KiB
Rust
// Based on quinn-proto
|
|
// https://github.com/quinn-rs/quinn/blob/main/quinn-proto/src/varint.rs
|
|
// Licensed via Apache 2.0 and MIT
|
|
|
|
use std::convert::{TryFrom, TryInto};
|
|
use std::fmt;
|
|
|
|
use crate::coding::{AsyncRead, AsyncWrite};
|
|
use thiserror::Error;
|
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
|
|
use super::{Decode, DecodeError, Encode, EncodeError};
|
|
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Error)]
|
|
#[error("value out of range")]
|
|
pub struct BoundsExceeded;
|
|
|
|
/// An integer less than 2^62
|
|
///
|
|
/// Values of this type are suitable for encoding as QUIC variable-length integer.
|
|
// It would be neat if we could express to Rust that the top two bits are available for use as enum
|
|
// discriminants
|
|
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
|
pub struct VarInt(u64);
|
|
|
|
impl VarInt {
|
|
/// The largest possible value.
|
|
pub const MAX: Self = Self((1 << 62) - 1);
|
|
|
|
/// The smallest possible value.
|
|
pub const ZERO: Self = Self(0);
|
|
|
|
/// Construct a `VarInt` infallibly using the largest available type.
|
|
/// Larger values need to use `try_from` instead.
|
|
pub const fn from_u32(x: u32) -> Self {
|
|
Self(x as u64)
|
|
}
|
|
|
|
/// Extract the integer value
|
|
pub const fn into_inner(self) -> u64 {
|
|
self.0
|
|
}
|
|
}
|
|
|
|
impl From<VarInt> for u64 {
|
|
fn from(x: VarInt) -> Self {
|
|
x.0
|
|
}
|
|
}
|
|
|
|
impl From<VarInt> for usize {
|
|
fn from(x: VarInt) -> Self {
|
|
x.0 as usize
|
|
}
|
|
}
|
|
|
|
impl From<VarInt> for u128 {
|
|
fn from(x: VarInt) -> Self {
|
|
x.0 as u128
|
|
}
|
|
}
|
|
|
|
impl From<u8> for VarInt {
|
|
fn from(x: u8) -> Self {
|
|
Self(x.into())
|
|
}
|
|
}
|
|
|
|
impl From<u16> for VarInt {
|
|
fn from(x: u16) -> Self {
|
|
Self(x.into())
|
|
}
|
|
}
|
|
|
|
impl From<u32> for VarInt {
|
|
fn from(x: u32) -> Self {
|
|
Self(x.into())
|
|
}
|
|
}
|
|
|
|
impl TryFrom<u64> for VarInt {
|
|
type Error = BoundsExceeded;
|
|
|
|
/// Succeeds iff `x` < 2^62
|
|
fn try_from(x: u64) -> Result<Self, BoundsExceeded> {
|
|
if x <= Self::MAX.into_inner() {
|
|
Ok(Self(x))
|
|
} else {
|
|
Err(BoundsExceeded)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<u128> for VarInt {
|
|
type Error = BoundsExceeded;
|
|
|
|
/// Succeeds iff `x` < 2^62
|
|
fn try_from(x: u128) -> Result<Self, BoundsExceeded> {
|
|
if x <= Self::MAX.into() {
|
|
Ok(Self(x as u64))
|
|
} else {
|
|
Err(BoundsExceeded)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<usize> for VarInt {
|
|
type Error = BoundsExceeded;
|
|
|
|
/// Succeeds iff `x` < 2^62
|
|
fn try_from(x: usize) -> Result<Self, BoundsExceeded> {
|
|
Self::try_from(x as u64)
|
|
}
|
|
}
|
|
|
|
impl TryFrom<VarInt> for u32 {
|
|
type Error = BoundsExceeded;
|
|
|
|
/// Succeeds iff `x` < 2^32
|
|
fn try_from(x: VarInt) -> Result<Self, BoundsExceeded> {
|
|
if x.0 <= u32::MAX.into() {
|
|
Ok(x.0 as u32)
|
|
} else {
|
|
Err(BoundsExceeded)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<VarInt> for u16 {
|
|
type Error = BoundsExceeded;
|
|
|
|
/// Succeeds iff `x` < 2^16
|
|
fn try_from(x: VarInt) -> Result<Self, BoundsExceeded> {
|
|
if x.0 <= u16::MAX.into() {
|
|
Ok(x.0 as u16)
|
|
} else {
|
|
Err(BoundsExceeded)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<VarInt> for u8 {
|
|
type Error = BoundsExceeded;
|
|
|
|
/// Succeeds iff `x` < 2^8
|
|
fn try_from(x: VarInt) -> Result<Self, BoundsExceeded> {
|
|
if x.0 <= u8::MAX.into() {
|
|
Ok(x.0 as u8)
|
|
} else {
|
|
Err(BoundsExceeded)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Debug for VarInt {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
self.0.fmt(f)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for VarInt {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
self.0.fmt(f)
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl Decode for VarInt {
|
|
/// Decode a varint from the given reader.
|
|
async fn decode<R: AsyncRead>(r: &mut R) -> Result<Self, DecodeError> {
|
|
let b = r.read_u8().await?;
|
|
Self::decode_byte(b, r).await
|
|
}
|
|
}
|
|
|
|
impl VarInt {
|
|
/// Decode a varint given the first byte, reading the rest as needed.
|
|
/// This is silly but useful for determining if the stream has ended.
|
|
pub async fn decode_byte<R: AsyncRead>(b: u8, r: &mut R) -> Result<Self, DecodeError> {
|
|
let tag = b >> 6;
|
|
|
|
let mut buf = [0u8; 8];
|
|
buf[0] = b & 0b0011_1111;
|
|
|
|
let x = match tag {
|
|
0b00 => u64::from(buf[0]),
|
|
0b01 => {
|
|
r.read_exact(buf[1..2].as_mut()).await?;
|
|
u64::from(u16::from_be_bytes(buf[..2].try_into().unwrap()))
|
|
}
|
|
0b10 => {
|
|
r.read_exact(buf[1..4].as_mut()).await?;
|
|
u64::from(u32::from_be_bytes(buf[..4].try_into().unwrap()))
|
|
}
|
|
0b11 => {
|
|
r.read_exact(buf[1..8].as_mut()).await?;
|
|
u64::from_be_bytes(buf)
|
|
}
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
Ok(Self(x))
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl Encode for VarInt {
|
|
/// Encode a varint to the given writer.
|
|
async fn encode<W: AsyncWrite>(&self, w: &mut W) -> Result<(), EncodeError> {
|
|
let x = self.0;
|
|
if x < 2u64.pow(6) {
|
|
w.write_u8(x as u8).await?;
|
|
} else if x < 2u64.pow(14) {
|
|
w.write_u16(0b01 << 14 | x as u16).await?;
|
|
} else if x < 2u64.pow(30) {
|
|
w.write_u32(0b10 << 30 | x as u32).await?;
|
|
} else if x < 2u64.pow(62) {
|
|
w.write_u64(0b11 << 62 | x).await?;
|
|
} else {
|
|
unreachable!("malformed VarInt");
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
// This is a fork of quinn::VarInt.
|
|
impl From<quinn::VarInt> for VarInt {
|
|
fn from(v: quinn::VarInt) -> Self {
|
|
Self(v.into_inner())
|
|
}
|
|
}
|