Skip to main content

Subscription

Struct Subscription 

Source
#[non_exhaustive]
pub struct Subscription { pub priority: u8, pub max_age: Duration, pub start: Option<Position>, pub end: Option<Position>, }
Expand description

Subscriber-side preferences for receiving a track.

Each subscriber holds its own Subscription; the publisher observes an aggregate across all live subscribers via crate::track::Producer::subscription. A subscriber can change its preferences after the fact with crate::track::Subscriber::update.

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§priority: u8

Delivery priority. Higher values preempt lower ones when bandwidth is constrained.

§max_age: Duration

How old a group may get before this subscriber gives up on it.

Duration::ZERO (the default) skips immediately: group 8 arriving means group 7 is abandoned. A larger budget tolerates that much reordering before giving up. This never adds delay, since the bound is only reached once newer data is already that far ahead.

This is the Subscriber Max Age on the wire, and it is stored here verbatim so what was asked for stays readable. Encoded as milliseconds in a QUIC varint, so a duration of 2^62 milliseconds or more cannot be put on the wire. Clamped to the publisher’s Info::max_age, since waiting for a group longer than it is kept around cannot produce it.

§Where it is enforced

At both ends, and neither alone is enough. The publisher skips a group that has aged out instead of putting it on the wire, which bounds a backlog before it costs bandwidth. But what reaches the publisher is the aggregate across every subscriber, resolved in favor of the most tolerant one, so that gate is only ever as tight as the most patient viewer. The subscriber applies the same budget again as it reads, where its own is the only one in play.

This bounds a subscription. track::Consumer::fetch_group is exempt: it names one old group explicitly, so there is no live edge to be late against.

§How age is measured

In presentation time only. A group is measured by its reach, where its immediate successor begins, against the newest frame of the latest group: it cannot present past its successor, so once everything it could still hold falls outside the budget it is provably useless. The candidate needs no timestamp of its own, so an empty or stalled group is bounded by its stamped successor the same way. Wall-clock reclamation of idle content is the cache’s own policy, not this budget’s.

Protocols whose wire can’t carry a timestamp (pre-Lite05 moq-lite, moq-transport without the Timestamp property) have their frames stamped on receipt, which makes the measure burst-blind on the receiving side: thirty seconds of backlog delivered in three reads as three. The publisher’s copy is stamped as it produces, so the gate there still holds; it is just the coarser of the two.

§start: Option<Position>

The lowest Position the publisher may deliver, or None for no floor.

A floor, not a request: only Self::max_age asks for data, and the floor bounds how far back it may reach. None and a floor of group 0 mean the same thing, since nothing sits below group 0. Delivery starts at the oldest group at or above the floor that the budget still considers fresh, so a floor above the live edge simply waits there (a resumed subscription naming where it left off).

Aggregated across every live subscriber (the loosest floor wins, and any subscriber without one clears it), so it says what the publisher sends, not what any one subscriber sees. crate::track::Subscriber::set_groups is the local read cursor; setting one does not imply the other. See Local cursor vs wire preference.

§end: Option<Position>

First Position the publisher should not deliver, or None for no end.

Exclusive, like the end of a std::ops::Range, which is what lets one field carry both “through the end of group 5” (Position::after_group(5)) and “up to frame 2 of group 5” (Position::after(5, 2)). An inclusive end cannot express the first without a sentinel frame, and the ordering falls out for free: group 6’s head sorts above any frame of group 5, so a whole-group subscriber correctly absorbs a frame-capped one in the aggregate.

The wire agrees: Group End and Frame End are both encoded as absolute + 1.

A request, aggregated across every live subscriber (any unbounded subscriber makes the aggregate unbounded). crate::track::Subscriber::set_groups is the local read cursor; Position::group_end translates this field into its bound. Setting one does not imply the other.

Implementations§

Source§

impl Subscription

Source

pub fn with_priority(self, priority: u8) -> Self

Set the delivery priority, returning self for chaining.

Source

pub fn with_max_age(self, max_age: Duration) -> Self

Set how old a group may get before it is skipped, returning self for chaining.

Source

pub fn with_start(self, start: impl Into<Option<Position>>) -> Self

Floor delivery at start, or leave it unfloored when None. Returns self for chaining.

A floor bounds how far back Self::max_age may reach; it does not request data on its own. Position::group is the whole-group form.

Source

pub fn with_end(self, end: impl Into<Option<Position>>) -> Self

Stop delivery at end, or leave the subscription unbounded when None. Returns self for chaining.

Exclusive, matching Self::end, so pass the position after the last one you want. Position::after and Position::after_group name that conversion so no call site has to write the + 1 itself.

Source

pub fn with_groups(self, groups: impl RangeBounds<u64>) -> Self

Request the whole groups in groups, replacing both Self::start and Self::end. Returns self for chaining.

Any range of group sequences works: 2..=5, 2..6, ..6, 2.., or .. to clear both bounds. An inclusive end past the last group is unbounded, as Position::after_group spells it.

Trait Implementations§

Source§

impl Clone for Subscription

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Subscription

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Subscription

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Eq for Subscription

Source§

impl PartialEq for Subscription

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Subscription

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> MaybeSend for T
where T: Send,

Source§

impl<T> MaybeSend for T
where T: Send + ?Sized,

Source§

impl<T> MaybeSend for T
where T: Send,

Source§

impl<T> MaybeSync for T
where T: Sync,

Source§

impl<T> MaybeSync for T
where T: Sync,

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more