1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use std::fmt;
/// A lite protocol version.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Version {
Lite01,
Lite02,
Lite03,
Lite04,
/// lite-05. Adds the TRACK stream (immutable per-track properties incl.
/// timescale), zigzag-delta timestamps in per-frame headers, and drops
/// SUBSCRIBE_OK/FETCH_OK.
Lite05,
/// Work-in-progress lite-06. Adds announce ids: each `active` ANNOUNCE_BROADCAST
/// implicitly assigns the next ordinal, and `ended`/`restart` reference that id
/// instead of repeating the path. Also adds the route cost carried alongside the
/// hop chain, ranking above hop count in route selection. Advertised over ALPN
/// (`moq-lite-06`, no `-wip` suffix on the wire) and the preferred version in the
/// default sets. The wire format is still WIP; finalizing is a pure rename to
/// `Lite06` with no wire change.
Lite06Wip,
}
impl Version {
/// Whether the version has lite-05's dedicated TRACK stream and related stream
/// layout changes.
///
/// This is the common feature boundary for TRACK_INFO, FETCH streams,
/// SUBSCRIBE_START/END, and per-frame timestamp prefixes.
#[allow(clippy::match_like_matches_macro)]
pub fn has_track_stream(self) -> bool {
// Match form so future versions default forward (CLAUDE.md convention).
match self {
Self::Lite01 | Self::Lite02 | Self::Lite03 | Self::Lite04 => false,
_ => true,
}
}
/// Whether the session opens a unidirectional Setup Stream carrying a single SETUP
/// message (capabilities + optional Path). Added in lite-05; the older bidirectional
/// setup exchange (Lite01/02) and the no-setup drafts (Lite03/04) don't use it.
#[allow(clippy::match_like_matches_macro)]
pub fn has_setup_stream(self) -> bool {
// Match form so future versions default forward (CLAUDE.md convention).
match self {
Self::Lite01 | Self::Lite02 | Self::Lite03 | Self::Lite04 => false,
_ => true,
}
}
/// Whether the session may deliver groups over unreliable QUIC datagrams (lite-05 ยง6.4).
/// A datagram carries one single-frame group's `subscribe | sequence | timestamp | payload`
/// and is routed over the existing subscription. Added in lite-05; older versions never
/// send or accept datagram bodies.
#[allow(clippy::match_like_matches_macro)]
pub fn has_datagrams(self) -> bool {
// Match form so future versions default forward (CLAUDE.md convention).
match self {
Self::Lite01 | Self::Lite02 | Self::Lite03 | Self::Lite04 => false,
_ => true,
}
}
/// Whether announce streams begin with ANNOUNCE_OK and omit the sender's origin
/// from each announcement's hop chain. Added in lite-05.
#[allow(clippy::match_like_matches_macro)]
pub fn has_announce_ok(self) -> bool {
// Match form so future versions default forward (CLAUDE.md convention).
match self {
Self::Lite01 | Self::Lite02 | Self::Lite03 | Self::Lite04 => false,
_ => true,
}
}
/// Whether announcements carry implicit announce ids: each `active`
/// ANNOUNCE_BROADCAST assigns the next per-stream ordinal, and `ended`/`restart`
/// reference that id instead of repeating the path. Added in lite-06.
#[allow(clippy::match_like_matches_macro)]
pub fn has_announce_id(self) -> bool {
// Match form so future versions default forward (CLAUDE.md convention).
match self {
Self::Lite01 | Self::Lite02 | Self::Lite03 | Self::Lite04 | Self::Lite05 => false,
_ => true,
}
}
/// Whether announcements carry the route cost: the marginal cost of pulling
/// the broadcast via this route, accumulated per link. Added in lite-06.
/// Older versions carry nothing, so a received route stays at zero and ranks
/// on hop count alone, exactly as before.
#[allow(clippy::match_like_matches_macro)]
pub fn has_route_cost(self) -> bool {
// Match form so future versions default forward (CLAUDE.md convention).
match self {
Self::Lite01 | Self::Lite02 | Self::Lite03 | Self::Lite04 | Self::Lite05 => false,
_ => true,
}
}
}
impl fmt::Display for Version {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Lite01 => write!(f, "moq-lite-01"),
Self::Lite02 => write!(f, "moq-lite-02"),
Self::Lite03 => write!(f, "moq-lite-03"),
Self::Lite04 => write!(f, "moq-lite-04"),
Self::Lite05 => write!(f, "moq-lite-05"),
Self::Lite06Wip => write!(f, "moq-lite-06-wip"),
}
}
}
impl From<Version> for crate::Version {
fn from(v: Version) -> Self {
match v {
Version::Lite01 => crate::Version::Lite(Version::Lite01),
Version::Lite02 => crate::Version::Lite(Version::Lite02),
Version::Lite03 => crate::Version::Lite(Version::Lite03),
Version::Lite04 => crate::Version::Lite(Version::Lite04),
Version::Lite05 => crate::Version::Lite(Version::Lite05),
Version::Lite06Wip => crate::Version::Lite(Version::Lite06Wip),
}
}
}
impl TryFrom<crate::Version> for Version {
type Error = ();
fn try_from(v: crate::Version) -> Result<Self, Self::Error> {
match v {
crate::Version::Lite(v) => Ok(v),
crate::Version::Ietf(_) => Err(()),
}
}
}