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 pub has_extensions: bool,
29
30 pub has_subgroup: bool,
32
33 pub has_subgroup_object: bool,
37
38 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; 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 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]
159 fn test_group_flags_spec_table() {
160 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 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 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 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 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 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 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 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 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 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 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 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 assert!(GroupFlags::decode(0x16).is_err());
258 }
259}