1use alloc::sync::Arc;
15use alloc::vec::Vec;
16use core::fmt;
17
18use zencodec::time::{FrameDuration, Timestamp};
19
20#[derive(Clone, Debug)]
22#[non_exhaustive]
23pub enum PacketPayload {
24 Owned(Vec<u8>),
26 Shared {
28 bytes: Arc<[u8]>,
30 start: usize,
32 len: usize,
34 },
35 Accounted(zencodec_io::storage::SharedStorage<u8>),
38}
39
40impl PacketPayload {
41 pub fn as_bytes(&self) -> &[u8] {
43 match self {
44 Self::Owned(v) => v,
45 Self::Shared { bytes, start, len } => &bytes[*start..*start + *len],
46 Self::Accounted(bytes) => bytes.as_slice(),
47 }
48 }
49
50 pub fn len(&self) -> usize {
52 self.as_bytes().len()
53 }
54
55 pub fn is_empty(&self) -> bool {
57 self.len() == 0
58 }
59
60 pub fn into_vec(self) -> Vec<u8> {
65 match self {
66 Self::Owned(v) => v,
67 Self::Shared { .. } | Self::Accounted(_) => self.as_bytes().to_vec(),
68 }
69 }
70}
71
72#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
80pub enum RandomAccess {
81 Yes,
83 No,
85 #[default]
87 Unknown,
88}
89
90#[derive(Clone, Debug)]
94pub struct PacketAddition {
95 id: u32,
96 payload: PacketPayload,
97}
98
99impl PacketAddition {
100 pub fn new(id: u32, payload: PacketPayload) -> Self {
102 Self { id, payload }
103 }
104
105 pub fn id(&self) -> u32 {
107 self.id
108 }
109
110 pub fn payload(&self) -> &PacketPayload {
112 &self.payload
113 }
114}
115
116#[derive(Clone, Copy, Debug, PartialEq, Eq)]
125#[non_exhaustive]
126pub struct Discard {
127 pub start: Option<FrameDuration>,
129 pub end: Option<FrameDuration>,
131}
132
133impl Discard {
134 pub const fn start(d: FrameDuration) -> Self {
136 Self {
137 start: Some(d),
138 end: None,
139 }
140 }
141
142 pub const fn end(d: FrameDuration) -> Self {
144 Self {
145 start: None,
146 end: Some(d),
147 }
148 }
149
150 pub const fn with_end(mut self, d: FrameDuration) -> Self {
152 self.end = Some(d);
153 self
154 }
155}
156
157#[derive(Clone, Debug)]
163pub struct Packet {
164 payload: Option<PacketPayload>,
165 track: u32,
166 pts: Option<Timestamp>,
167 dts: Option<Timestamp>,
168 duration_ticks: Option<u64>,
169 random_access: RandomAccess,
170 config_epoch: u32,
171 ordinal: Option<u64>,
172 input_offset: Option<u64>,
173 discard: Option<Discard>,
174 additions: Vec<PacketAddition>,
175}
176
177#[derive(Clone, Copy, Debug, PartialEq, Eq)]
179#[non_exhaustive]
180pub enum PacketError {
181 Empty,
183 OutOfRange,
185}
186
187impl fmt::Display for PacketError {
188 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189 f.write_str(match self {
190 Self::Empty => "packet payload is empty",
191 Self::OutOfRange => "shared payload range is outside its buffer",
192 })
193 }
194}
195
196impl core::error::Error for PacketError {}
197
198impl Packet {
199 #[cfg(feature = "std")]
200 pub(crate) fn map_payloads(
201 mut self,
202 mut map: impl FnMut(&PacketPayload) -> Result<PacketPayload, crate::staged::Cause>,
203 ) -> Result<Self, crate::staged::Cause> {
204 if let Some(payload) = &self.payload {
205 self.payload = Some(map(payload)?);
206 }
207 for addition in &mut self.additions {
208 addition.payload = map(&addition.payload)?;
209 }
210 Ok(self)
211 }
212
213 #[cfg(feature = "std")]
214 pub(crate) fn accounted(
215 mut self,
216 budget: &zencodec::storage::StorageBudget,
217 ) -> Result<Self, zencodec::storage::StorageError> {
218 let copy = |source: &[u8]| {
219 let mut bytes = budget.bytes(source.len())?;
220 bytes.as_mut_slice().copy_from_slice(source);
221 Ok::<_, zencodec::storage::StorageError>(PacketPayload::Accounted(bytes.freeze()))
222 };
223 if let Some(payload) = &self.payload {
224 self.payload = Some(copy(payload.as_bytes())?);
225 }
226 for addition in &mut self.additions {
227 addition.payload = copy(addition.payload.as_bytes())?;
228 }
229 Ok(self)
230 }
231
232 fn with_payload(payload: PacketPayload) -> Self {
233 Self {
234 payload: Some(payload),
235 track: 0,
236 pts: None,
237 dts: None,
238 duration_ticks: None,
239 random_access: RandomAccess::Unknown,
240 config_epoch: 0,
241 ordinal: None,
242 input_offset: None,
243 discard: None,
244 additions: Vec::new(),
245 }
246 }
247
248 pub fn from_vec(bytes: Vec<u8>) -> Result<Self, PacketError> {
254 if bytes.is_empty() {
255 return Err(PacketError::Empty);
256 }
257 Ok(Self::with_payload(PacketPayload::Owned(bytes)))
258 }
259
260 pub fn from_accounted(
263 bytes: zencodec_io::storage::SharedStorage<u8>,
264 ) -> Result<Self, PacketError> {
265 if bytes.is_empty() {
266 return Err(PacketError::Empty);
267 }
268 Ok(Self::with_payload(PacketPayload::Accounted(bytes)))
269 }
270
271 pub fn from_shared(bytes: Arc<[u8]>, start: usize, len: usize) -> Result<Self, PacketError> {
278 if len == 0 {
279 return Err(PacketError::Empty);
280 }
281 if start.checked_add(len).is_none_or(|end| end > bytes.len()) {
282 return Err(PacketError::OutOfRange);
283 }
284 Ok(Self::with_payload(PacketPayload::Shared {
285 bytes,
286 start,
287 len,
288 }))
289 }
290
291 pub fn with_track(mut self, track: u32) -> Self {
295 self.track = track;
296 self
297 }
298
299 pub fn with_pts(mut self, pts: Timestamp) -> Self {
301 self.pts = Some(pts);
302 self
303 }
304
305 pub fn with_dts(mut self, dts: Timestamp) -> Self {
308 self.dts = Some(dts);
309 self
310 }
311
312 pub fn with_duration_ticks(mut self, ticks: u64) -> Self {
315 self.duration_ticks = Some(ticks);
316 self
317 }
318
319 pub fn with_random_access(mut self, ra: RandomAccess) -> Self {
321 self.random_access = ra;
322 self
323 }
324
325 pub fn with_config_epoch(mut self, epoch: u32) -> Self {
327 self.config_epoch = epoch;
328 self
329 }
330
331 pub fn with_ordinal(mut self, ordinal: u64) -> Self {
333 self.ordinal = Some(ordinal);
334 self
335 }
336
337 pub fn with_input_offset(mut self, offset: u64) -> Self {
339 self.input_offset = Some(offset);
340 self
341 }
342
343 pub fn with_discard(mut self, discard: Discard) -> Self {
345 self.discard = Some(discard);
346 self
347 }
348
349 pub fn with_addition(mut self, addition: PacketAddition) -> Self {
351 self.additions.push(addition);
352 self
353 }
354
355 pub fn bytes(&self) -> &[u8] {
357 self.payload.as_ref().map_or(&[], PacketPayload::as_bytes)
358 }
359
360 pub fn len(&self) -> usize {
362 self.bytes().len()
363 }
364
365 pub fn is_empty(&self) -> bool {
367 self.len() == 0
368 }
369
370 pub fn is_taken(&self) -> bool {
372 self.payload.is_none()
373 }
374
375 pub fn take(&mut self) -> Option<PacketPayload> {
378 self.payload.take()
379 }
380
381 pub fn track(&self) -> u32 {
383 self.track
384 }
385
386 pub fn pts(&self) -> Option<Timestamp> {
388 self.pts
389 }
390
391 pub fn dts(&self) -> Option<Timestamp> {
393 self.dts
394 }
395
396 pub fn decode_time(&self) -> Option<Timestamp> {
398 self.dts.or(self.pts)
399 }
400
401 pub fn duration_ticks(&self) -> Option<u64> {
403 self.duration_ticks
404 }
405
406 pub fn random_access(&self) -> RandomAccess {
408 self.random_access
409 }
410
411 pub fn config_epoch(&self) -> u32 {
413 self.config_epoch
414 }
415
416 pub fn ordinal(&self) -> Option<u64> {
418 self.ordinal
419 }
420
421 pub fn input_offset(&self) -> Option<u64> {
423 self.input_offset
424 }
425
426 pub fn discard(&self) -> Option<Discard> {
428 self.discard
429 }
430
431 pub fn additions(&self) -> &[PacketAddition] {
433 &self.additions
434 }
435}
436
437#[cfg(all(test, feature = "std"))]
438mod accounted_tests {
439 use super::*;
440 use alloc::vec;
441 use zencodec::{storage::StorageBudget, time::TimeBase};
442 #[test]
443 fn staging_preserves_packet_and_additions_and_releases_partial_admission() {
444 let original = Packet::from_vec(vec![1, 2, 3])
445 .unwrap()
446 .with_track(7)
447 .with_pts(Timestamp::new(19, TimeBase::MILLIS))
448 .with_dts(Timestamp::new(17, TimeBase::MILLIS))
449 .with_duration_ticks(2)
450 .with_config_epoch(3)
451 .with_ordinal(9)
452 .with_input_offset(123)
453 .with_random_access(RandomAccess::Yes)
454 .with_addition(PacketAddition::new(6, PacketPayload::Owned(vec![4, 5])));
455 let small = StorageBudget::new(4, 8);
456 assert!(original.clone().accounted(&small).is_err());
457 assert_eq!(small.reserved_bytes(), 0);
458 assert_eq!(small.reserved_objects(), 0);
459 let budget = StorageBudget::new(5, 2);
460 let output = original.clone().accounted(&budget).unwrap();
461 assert_eq!(output.bytes(), original.bytes());
462 assert_eq!(output.track(), original.track());
463 assert_eq!(output.pts(), original.pts());
464 assert_eq!(output.dts(), original.dts());
465 assert_eq!(output.duration_ticks(), original.duration_ticks());
466 assert_eq!(output.config_epoch(), original.config_epoch());
467 assert_eq!(output.ordinal(), original.ordinal());
468 assert_eq!(output.input_offset(), original.input_offset());
469 assert_eq!(output.random_access(), original.random_access());
470 assert_eq!(output.additions()[0].id(), 6);
471 assert_eq!(output.additions()[0].payload().as_bytes(), &[4, 5]);
472 assert_eq!(budget.reserved_bytes(), 5);
473 let retained = output.clone();
474 drop(output);
475 assert_eq!(budget.reserved_bytes(), 5);
476 drop(retained);
477 assert_eq!(budget.reserved_bytes(), 0);
478 }
479}