moq_lite/ietf/
group.rs

1use crate::coding::{Decode, DecodeError, Encode};
2
3use num_enum::{IntoPrimitive, TryFromPrimitive};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
6#[repr(u8)]
7pub enum GroupOrder {
8	Any = 0x0,
9	Ascending = 0x1,
10	Descending = 0x2,
11}
12
13impl<V> Encode<V> for GroupOrder {
14	fn encode<W: bytes::BufMut>(&self, w: &mut W, version: V) {
15		u8::from(*self).encode(w, version);
16	}
17}
18
19impl<V> Decode<V> for GroupOrder {
20	fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, DecodeError> {
21		Self::try_from(u8::decode(r, version)?).map_err(|_| DecodeError::InvalidValue)
22	}
23}
24
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct GroupFlags {
27	// The group has extensions.
28	pub has_extensions: bool,
29
30	// There's an explicit subgroup on the wire.
31	pub has_subgroup: bool,
32
33	// Use the first object ID as the subgroup ID
34	// Since we don't support subgroups or object ID > 0, this is trivial to support.
35	// Not compatibile with has_subgroup
36	pub has_subgroup_object: bool,
37
38	// There's an implicit end marker when the stream is closed.
39	pub has_end: bool,
40}
41
42impl GroupFlags {
43	pub const START: u64 = 0x10;
44	pub const END: u64 = 0x1d;
45
46	pub fn encode(&self) -> u64 {
47		assert!(
48			!self.has_subgroup || !self.has_subgroup_object,
49			"has_subgroup and has_subgroup_object cannot be true at the same time"
50		);
51
52		let mut id: u64 = Self::START; // Base value
53		if self.has_extensions {
54			id |= 0x01;
55		}
56		if self.has_subgroup_object {
57			id |= 0x02;
58		}
59		if self.has_subgroup {
60			id |= 0x04;
61		}
62		if self.has_end {
63			id |= 0x08;
64		}
65		id
66	}
67
68	pub fn decode(id: u64) -> Result<Self, DecodeError> {
69		if !(Self::START..=Self::END).contains(&id) {
70			return Err(DecodeError::InvalidValue);
71		}
72
73		let has_extensions = (id & 0x01) != 0;
74		let has_subgroup_object = (id & 0x02) != 0;
75		let has_subgroup = (id & 0x04) != 0;
76		let has_end = (id & 0x08) != 0;
77
78		if has_subgroup && has_subgroup_object {
79			return Err(DecodeError::InvalidValue);
80		}
81
82		Ok(Self {
83			has_extensions,
84			has_subgroup,
85			has_subgroup_object,
86			has_end,
87		})
88	}
89}
90
91impl Default for GroupFlags {
92	fn default() -> Self {
93		Self {
94			has_extensions: false,
95			has_subgroup: false,
96			has_subgroup_object: false,
97			has_end: true,
98		}
99	}
100}
101
102#[derive(Debug, Clone, PartialEq, Eq)]
103pub struct GroupHeader {
104	pub track_alias: u64,
105	pub group_id: u64,
106	pub sub_group_id: u64,
107	pub publisher_priority: u8,
108	pub flags: GroupFlags,
109}
110
111impl<V: Clone> Encode<V> for GroupHeader {
112	fn encode<W: bytes::BufMut>(&self, w: &mut W, version: V) {
113		self.flags.encode().encode(w, version.clone());
114		self.track_alias.encode(w, version.clone());
115		self.group_id.encode(w, version.clone());
116
117		if !self.flags.has_subgroup && self.sub_group_id != 0 {
118			panic!("sub_group_id must be 0 if has_subgroup is false");
119		}
120
121		if self.flags.has_subgroup {
122			self.sub_group_id.encode(w, version.clone());
123		}
124
125		// Publisher priority
126		self.publisher_priority.encode(w, version);
127	}
128}
129
130impl<V: Clone> Decode<V> for GroupHeader {
131	fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, DecodeError> {
132		let flags = GroupFlags::decode(u64::decode(r, version.clone())?)?;
133		let track_alias = u64::decode(r, version.clone())?;
134		let group_id = u64::decode(r, version.clone())?;
135
136		let sub_group_id = match flags.has_subgroup {
137			true => u64::decode(r, version.clone())?,
138			false => 0,
139		};
140
141		let publisher_priority = u8::decode(r, version)?;
142
143		Ok(Self {
144			track_alias,
145			group_id,
146			sub_group_id,
147			publisher_priority,
148			flags,
149		})
150	}
151}
152
153#[cfg(test)]
154mod tests {
155	use super::*;
156
157	// Test table from draft-ietf-moq-transport-14 Section 10.4.2 Table 7
158	#[test]
159	fn test_group_flags_spec_table() {
160		// Type 0x10: No subgroup field, Subgroup ID = 0, No extensions, No end
161		let flags = GroupFlags::decode(0x10).unwrap();
162		assert!(!flags.has_subgroup);
163		assert!(!flags.has_subgroup_object);
164		assert!(!flags.has_extensions);
165		assert!(!flags.has_end);
166		assert_eq!(flags.encode(), 0x10);
167
168		// Type 0x11: No subgroup field, Subgroup ID = 0, Extensions, No end
169		let flags = GroupFlags::decode(0x11).unwrap();
170		assert!(!flags.has_subgroup);
171		assert!(!flags.has_subgroup_object);
172		assert!(flags.has_extensions);
173		assert!(!flags.has_end);
174		assert_eq!(flags.encode(), 0x11);
175
176		// Type 0x12: No subgroup field, Subgroup ID = First Object ID, No extensions, No end
177		let flags = GroupFlags::decode(0x12).unwrap();
178		assert!(!flags.has_subgroup);
179		assert!(flags.has_subgroup_object);
180		assert!(!flags.has_extensions);
181		assert!(!flags.has_end);
182		assert_eq!(flags.encode(), 0x12);
183
184		// Type 0x13: No subgroup field, Subgroup ID = First Object ID, Extensions, No end
185		let flags = GroupFlags::decode(0x13).unwrap();
186		assert!(!flags.has_subgroup);
187		assert!(flags.has_subgroup_object);
188		assert!(flags.has_extensions);
189		assert!(!flags.has_end);
190		assert_eq!(flags.encode(), 0x13);
191
192		// Type 0x14: Subgroup field present, No extensions, No end
193		let flags = GroupFlags::decode(0x14).unwrap();
194		assert!(flags.has_subgroup);
195		assert!(!flags.has_subgroup_object);
196		assert!(!flags.has_extensions);
197		assert!(!flags.has_end);
198		assert_eq!(flags.encode(), 0x14);
199
200		// Type 0x15: Subgroup field present, Extensions, No end
201		let flags = GroupFlags::decode(0x15).unwrap();
202		assert!(flags.has_subgroup);
203		assert!(!flags.has_subgroup_object);
204		assert!(flags.has_extensions);
205		assert!(!flags.has_end);
206		assert_eq!(flags.encode(), 0x15);
207
208		// Type 0x18: No subgroup field, Subgroup ID = 0, No extensions, End of group
209		let flags = GroupFlags::decode(0x18).unwrap();
210		assert!(!flags.has_subgroup);
211		assert!(!flags.has_subgroup_object);
212		assert!(!flags.has_extensions);
213		assert!(flags.has_end);
214		assert_eq!(flags.encode(), 0x18);
215
216		// Type 0x19: No subgroup field, Subgroup ID = 0, Extensions, End of group
217		let flags = GroupFlags::decode(0x19).unwrap();
218		assert!(!flags.has_subgroup);
219		assert!(!flags.has_subgroup_object);
220		assert!(flags.has_extensions);
221		assert!(flags.has_end);
222		assert_eq!(flags.encode(), 0x19);
223
224		// Type 0x1A: No subgroup field, Subgroup ID = First Object ID, No extensions, End of group
225		let flags = GroupFlags::decode(0x1A).unwrap();
226		assert!(!flags.has_subgroup);
227		assert!(flags.has_subgroup_object);
228		assert!(!flags.has_extensions);
229		assert!(flags.has_end);
230		assert_eq!(flags.encode(), 0x1A);
231
232		// Type 0x1B: No subgroup field, Subgroup ID = First Object ID, Extensions, End of group
233		let flags = GroupFlags::decode(0x1B).unwrap();
234		assert!(!flags.has_subgroup);
235		assert!(flags.has_subgroup_object);
236		assert!(flags.has_extensions);
237		assert!(flags.has_end);
238		assert_eq!(flags.encode(), 0x1B);
239
240		// Type 0x1C: Subgroup field present, No extensions, End of group
241		let flags = GroupFlags::decode(0x1C).unwrap();
242		assert!(flags.has_subgroup);
243		assert!(!flags.has_subgroup_object);
244		assert!(!flags.has_extensions);
245		assert!(flags.has_end);
246		assert_eq!(flags.encode(), 0x1C);
247
248		// Type 0x1D: Subgroup field present, Extensions, End of group
249		let flags = GroupFlags::decode(0x1D).unwrap();
250		assert!(flags.has_subgroup);
251		assert!(!flags.has_subgroup_object);
252		assert!(flags.has_extensions);
253		assert!(flags.has_end);
254		assert_eq!(flags.encode(), 0x1D);
255
256		// Invalid: Both has_subgroup and has_subgroup_object (would be 0x16)
257		assert!(GroupFlags::decode(0x16).is_err());
258	}
259}