moqtap_client/datagram_prefix.rs
1//! The fields of a received datagram up to its Extension Headers Length.
2//!
3//! On drafts 11 through 16 the codec's datagram header decoder refuses an
4//! announced extension block with a length of 0 as a bare `InvalidField`,
5//! which it also returns for other faults. Each draft's `recv_datagram` reads
6//! the prefix again here, after that refusal, to tell whether the empty block
7//! was the fault, since the drafts answer it with a session close.
8
9use moqtap_codec::varint::VarInt;
10
11/// Which fields a datagram Type puts before its Extension Headers Length.
12pub(crate) struct Prefix {
13 /// An Object ID field is present; absent, the Object ID is 0.
14 pub object_id: bool,
15 /// A Publisher Priority byte is present.
16 pub priority: bool,
17}
18
19/// The Object ID of a datagram whose Type announces an extension block and
20/// whose Extension Headers Length is 0, or `None` for any other datagram.
21///
22/// `prefix` answers, for the Type's value and its encoded width in bytes, the
23/// fields before the length when the Type announces a block the draft's rule
24/// covers, and `None` for every other Type.
25pub(crate) fn empty_extension_block(
26 data: &[u8],
27 prefix: impl Fn(u64, usize) -> Option<Prefix>,
28) -> Option<u64> {
29 let mut cursor = data;
30 let datagram_type = VarInt::decode(&mut cursor).ok()?.into_inner();
31 let layout = prefix(datagram_type, data.len() - cursor.len())?;
32 VarInt::decode(&mut cursor).ok()?;
33 VarInt::decode(&mut cursor).ok()?;
34 let object_id =
35 if layout.object_id { VarInt::decode(&mut cursor).ok()?.into_inner() } else { 0 };
36 if layout.priority {
37 cursor = cursor.get(1..)?;
38 }
39 (VarInt::decode(&mut cursor).ok()?.into_inner() == 0).then_some(object_id)
40}