Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 2 additions & 16 deletions moq-transport/src/coding/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ impl Decode for Bytes {
#[async_trait]
impl Decode for Vec<u8> {
async fn decode<R: AsyncRead + Unpin + Send>(r: &mut R) -> anyhow::Result<Self> {
let size = u64::decode(r).await?;
let size = VarInt::decode(r).await?;

// NOTE: we don't use with_capacity since size is from an untrusted source
let mut buf = Vec::new();
r.take(size).read_to_end(&mut buf).await?;
r.take(size.into()).read_to_end(&mut buf).await?;

Ok(buf)
}
Expand All @@ -38,17 +38,3 @@ impl Decode for String {
Ok(s)
}
}

#[async_trait]
impl Decode for u64 {
async fn decode<R: AsyncRead + Unpin + Send>(r: &mut R) -> anyhow::Result<Self> {
VarInt::decode(r).await.map(Into::into)
}
}

#[async_trait]
impl Decode for usize {
async fn decode<R: AsyncRead + Unpin + Send>(r: &mut R) -> anyhow::Result<Self> {
VarInt::decode(r).await.map(Into::into)
}
}
8 changes: 4 additions & 4 deletions moq-transport/src/coding/duration.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::{Decode, Encode};

use crate::coding::VarInt;
use async_trait::async_trait;
use tokio::io::{AsyncRead, AsyncWrite};

Expand All @@ -9,16 +10,15 @@ use std::time::Duration;
impl Encode for Duration {
async fn encode<W: AsyncWrite + Unpin + Send>(&self, w: &mut W) -> anyhow::Result<()> {
let ms = self.as_millis();
let ms = u64::try_from(ms)?;
let ms = VarInt::try_from(ms)?;
ms.encode(w).await
}
}

#[async_trait]
impl Decode for Duration {
async fn decode<R: AsyncRead + Unpin + Send>(r: &mut R) -> anyhow::Result<Self> {
let ms = u64::decode(r).await?;
let ms = ms;
Ok(Self::from_millis(ms))
let ms = VarInt::decode(r).await?;
Ok(Self::from_millis(ms.into()))
}
}
25 changes: 4 additions & 21 deletions moq-transport/src/coding/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,22 @@ pub trait Encode: Sized {
#[async_trait]
impl Encode for Bytes {
async fn encode<W: AsyncWrite + Unpin + Send>(&self, w: &mut W) -> anyhow::Result<()> {
self.len().encode(w).await?;
w.write_all(self).await?;
Ok(())
self.as_ref().encode(w).await
}
}

#[async_trait]
impl Encode for Vec<u8> {
async fn encode<W: AsyncWrite + Unpin + Send>(&self, w: &mut W) -> anyhow::Result<()> {
self.len().encode(w).await?;
w.write_all(self).await?;
Ok(())
self.as_slice().encode(w).await
}
}

#[async_trait]
impl Encode for &[u8] {
async fn encode<W: AsyncWrite + Unpin + Send>(&self, w: &mut W) -> anyhow::Result<()> {
self.len().encode(w).await?;
let size: VarInt = self.len().try_into()?;
size.encode(w).await?;
w.write_all(self).await?;
Ok(())
}
Expand All @@ -42,17 +39,3 @@ impl Encode for String {
self.as_bytes().encode(w).await
}
}

#[async_trait]
impl Encode for u64 {
async fn encode<W: AsyncWrite + Unpin + Send>(&self, w: &mut W) -> anyhow::Result<()> {
VarInt::try_from(*self)?.encode(w).await
}
}

#[async_trait]
impl Encode for usize {
async fn encode<W: AsyncWrite + Unpin + Send>(&self, w: &mut W) -> anyhow::Result<()> {
VarInt::try_from(*self)?.encode(w).await
}
}
38 changes: 36 additions & 2 deletions moq-transport/src/coding/varint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,22 @@ pub struct BoundsExceeded;
// 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(crate) struct VarInt(u64);
pub struct VarInt(u64);

impl VarInt {
pub const MAX: Self = Self((1 << 62) - 1);

/// 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 {
Expand All @@ -35,6 +50,12 @@ impl From<VarInt> for 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())
Expand All @@ -58,14 +79,27 @@ impl TryFrom<u64> for VarInt {

/// Succeeds iff `x` < 2^62
fn try_from(x: u64) -> Result<Self, BoundsExceeded> {
if x < 2u64.pow(62) {
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
Expand Down
6 changes: 3 additions & 3 deletions moq-transport/src/control/announce_error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::coding::{Decode, Encode};
use crate::coding::{Decode, Encode, VarInt};

use async_trait::async_trait;
use tokio::io::{AsyncRead, AsyncWrite};
Expand All @@ -10,7 +10,7 @@ pub struct AnnounceError {
pub track_namespace: String,

// An error code.
pub code: u64,
pub code: VarInt,

// An optional, human-readable reason.
pub reason: String,
Expand All @@ -20,7 +20,7 @@ pub struct AnnounceError {
impl Decode for AnnounceError {
async fn decode<R: AsyncRead + Unpin + Send>(r: &mut R) -> anyhow::Result<Self> {
let track_namespace = String::decode(r).await?;
let code = u64::decode(r).await?;
let code = VarInt::decode(r).await?;
let reason = String::decode(r).await?;

Ok(Self {
Expand Down
9 changes: 4 additions & 5 deletions moq-transport/src/control/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub use subscribe::*;
pub use subscribe_error::*;
pub use subscribe_ok::*;

use crate::coding::{Decode, Encode};
use crate::coding::{Decode, Encode, VarInt};

use async_trait::async_trait;
use std::fmt;
Expand All @@ -35,9 +35,9 @@ macro_rules! message_types {
#[async_trait]
impl Decode for Message {
async fn decode<R: AsyncRead + Unpin + Send>(r: &mut R) -> anyhow::Result<Self> {
let t = u64::decode(r).await.context("failed to decode type")?;
let t = VarInt::decode(r).await.context("failed to decode type")?;

Ok(match u64::from(t) {
Ok(match t.into_inner() {
$($val => {
let msg = $name::decode(r).await.context(concat!("failed to decode ", stringify!($name)))?;
Self::$name(msg)
Expand All @@ -52,8 +52,7 @@ macro_rules! message_types {
async fn encode<W: AsyncWrite + Unpin + Send>(&self, w: &mut W) -> anyhow::Result<()> {
match self {
$(Self::$name(ref m) => {
let id: u64 = $val; // tell the compiler this is a u64
id.encode(w).await.context("failed to encode type")?;
VarInt::from_u32($val).encode(w).await.context("failed to encode type")?;
m.encode(w).await.context("failed to encode message")
},)*
}
Expand Down
6 changes: 3 additions & 3 deletions moq-transport/src/control/subscribe.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::coding::{Decode, Encode};
use crate::coding::{Decode, Encode, VarInt};

use async_trait::async_trait;
use tokio::io::{AsyncRead, AsyncWrite};
Expand All @@ -7,7 +7,7 @@ use tokio::io::{AsyncRead, AsyncWrite};
pub struct Subscribe {
// An ID we choose so we can map to the track_name.
// Proposal: https://github.com/moq-wg/moq-transport/issues/209
pub track_id: u64,
pub track_id: VarInt,

// The track namespace.
pub track_namespace: String,
Expand All @@ -19,7 +19,7 @@ pub struct Subscribe {
#[async_trait]
impl Decode for Subscribe {
async fn decode<R: AsyncRead + Unpin + Send>(r: &mut R) -> anyhow::Result<Self> {
let track_id = u64::decode(r).await?;
let track_id = VarInt::decode(r).await?;
let track_namespace = String::decode(r).await?;
let track_name = String::decode(r).await?;

Expand Down
10 changes: 5 additions & 5 deletions moq-transport/src/control/subscribe_error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::coding::{Decode, Encode};
use crate::coding::{Decode, Encode, VarInt};

use async_trait::async_trait;
use tokio::io::{AsyncRead, AsyncWrite};
Expand All @@ -8,10 +8,10 @@ pub struct SubscribeError {
// NOTE: No full track name because of this proposal: https://github.com/moq-wg/moq-transport/issues/209

// The ID for this track.
pub track_id: u64,
pub track_id: VarInt,

// An error code.
pub code: u64,
pub code: VarInt,

// An optional, human-readable reason.
pub reason: String,
Expand All @@ -20,8 +20,8 @@ pub struct SubscribeError {
#[async_trait]
impl Decode for SubscribeError {
async fn decode<R: AsyncRead + Unpin + Send>(r: &mut R) -> anyhow::Result<Self> {
let track_id = u64::decode(r).await?;
let code = u64::decode(r).await?;
let track_id = VarInt::decode(r).await?;
let code = VarInt::decode(r).await?;
let reason = String::decode(r).await?;

Ok(Self { track_id, code, reason })
Expand Down
6 changes: 3 additions & 3 deletions moq-transport/src/control/subscribe_ok.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::coding::{Decode, Encode};
use crate::coding::{Decode, Encode, VarInt};

use std::time::Duration;

Expand All @@ -10,7 +10,7 @@ pub struct SubscribeOk {
// NOTE: No full track name because of this proposal: https://github.com/moq-wg/moq-transport/issues/209

// The ID for this track.
pub track_id: u64,
pub track_id: VarInt,

// The subscription will end after this duration has elapsed.
// A value of zero is invalid.
Expand All @@ -20,7 +20,7 @@ pub struct SubscribeOk {
#[async_trait]
impl Decode for SubscribeOk {
async fn decode<R: AsyncRead + Unpin + Send>(r: &mut R) -> anyhow::Result<Self> {
let track_id = u64::decode(r).await?;
let track_id = VarInt::decode(r).await?;
let expires = Duration::decode(r).await?;
let expires = if expires == Duration::ZERO { None } else { Some(expires) };

Expand Down
24 changes: 12 additions & 12 deletions moq-transport/src/data/header.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::coding::{Decode, Encode};
use crate::coding::{Decode, Encode, VarInt};

use async_trait::async_trait;
use tokio::io::{AsyncRead, AsyncWrite};
Expand All @@ -8,30 +8,30 @@ use tokio::io::{AsyncRead, AsyncWrite};
pub struct Header {
// An ID for this track.
// Proposal: https://github.com/moq-wg/moq-transport/issues/209
pub track_id: u64,
pub track_id: VarInt,

// The group sequence number.
pub group_sequence: u64,
pub group_sequence: VarInt,

// The object sequence number.
pub object_sequence: u64,
pub object_sequence: VarInt,

// The priority/send order.
pub send_order: u64,
pub send_order: VarInt,
}

#[async_trait]
impl Decode for Header {
async fn decode<R: AsyncRead + Unpin + Send>(r: &mut R) -> anyhow::Result<Self> {
let typ = u64::decode(r).await?;
anyhow::ensure!(typ == 0, "OBJECT type must be 0");
let typ = VarInt::decode(r).await?;
anyhow::ensure!(u64::from(typ) == 0, "OBJECT type must be 0");

// NOTE: size has been omitted

let track_id = u64::decode(r).await?;
let group_sequence = u64::decode(r).await?;
let object_sequence = u64::decode(r).await?;
let send_order = u64::decode(r).await?;
let track_id = VarInt::decode(r).await?;
let group_sequence = VarInt::decode(r).await?;
let object_sequence = VarInt::decode(r).await?;
let send_order = VarInt::decode(r).await?;

Ok(Self {
track_id,
Expand All @@ -45,7 +45,7 @@ impl Decode for Header {
#[async_trait]
impl Encode for Header {
async fn encode<W: AsyncWrite + Unpin + Send>(&self, w: &mut W) -> anyhow::Result<()> {
0u64.encode(w).await?;
VarInt::from_u32(0).encode(w).await?;
self.track_id.encode(w).await?;
self.group_sequence.encode(w).await?;
self.object_sequence.encode(w).await?;
Expand Down
8 changes: 4 additions & 4 deletions moq-transport/src/setup/client.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{Role, Versions};
use crate::coding::{Decode, Encode};
use crate::coding::{Decode, Encode, VarInt};

use async_trait::async_trait;
use tokio::io::{AsyncRead, AsyncWrite};
Expand All @@ -26,8 +26,8 @@ pub struct Client {
#[async_trait]
impl Decode for Client {
async fn decode<R: AsyncRead + Unpin + Send>(r: &mut R) -> anyhow::Result<Self> {
let typ = u64::decode(r).await.context("failed to read type")?;
anyhow::ensure!(typ == 1, "client SETUP must be type 1");
let typ = VarInt::decode(r).await.context("failed to read type")?;
anyhow::ensure!(typ.into_inner() == 1, "client SETUP must be type 1");

let versions = Versions::decode(r).await.context("failed to read supported versions")?;
anyhow::ensure!(!versions.is_empty(), "client must support at least one version");
Expand All @@ -42,7 +42,7 @@ impl Decode for Client {
#[async_trait]
impl Encode for Client {
async fn encode<W: AsyncWrite + Unpin + Send>(&self, w: &mut W) -> anyhow::Result<()> {
1u64.encode(w).await?;
VarInt::from_u32(1).encode(w).await?;

anyhow::ensure!(!self.versions.is_empty(), "client must support at least one version");
self.versions.encode(w).await?;
Expand Down
Loading