isobmff/boxes/
file_delivery_format.rs

1use scuffle_bytes_util::IoResultExt;
2use scuffle_bytes_util::zero_copy::{Deserialize, DeserializeSeed, Serialize};
3
4use crate::{Base64String, BoxHeader, FullBoxHeader, IsoBox, IsoSized, Utf8String};
5
6/// FD item information box
7///
8/// ISO/IEC 14996-12 - 8.13.2
9#[derive(IsoBox, Debug, PartialEq, Eq)]
10#[iso_box(box_type = b"fiin", skip_impl(deserialize_seed, serialize), crate_path = crate)]
11pub struct FDItemInformationBox {
12    /// The full box header.
13    pub full_header: FullBoxHeader,
14    /// Provides a count of the number of entries in the [`partition_entries`](Self::partition_entries) vec.
15    pub entry_count: u16,
16    /// The contained partition entries.
17    pub partition_entries: Vec<PartitionEntry>,
18    /// The contained [`FDSessionGroupBox`]. (optional)
19    pub session_info: Option<FDSessionGroupBox>,
20    /// The contained [`GroupIdToNameBox`]. (optional)
21    pub group_id_to_name: Option<GroupIdToNameBox>,
22}
23
24impl<'a> DeserializeSeed<'a, BoxHeader> for FDItemInformationBox {
25    fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> std::io::Result<Self>
26    where
27        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
28    {
29        let full_header = FullBoxHeader::deserialize(&mut reader)?;
30        let entry_count = u16::deserialize(&mut reader)?;
31
32        let mut partition_entries = Vec::with_capacity(entry_count as usize);
33        for _ in 0..entry_count {
34            partition_entries.push(PartitionEntry::deserialize(&mut reader)?);
35        }
36
37        let session_info = FDSessionGroupBox::deserialize(&mut reader).eof_to_none()?;
38        let group_id_to_name = GroupIdToNameBox::deserialize(&mut reader).eof_to_none()?;
39
40        Ok(Self {
41            full_header,
42            entry_count,
43            partition_entries,
44            session_info,
45            group_id_to_name,
46        })
47    }
48}
49
50impl Serialize for FDItemInformationBox {
51    fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
52    where
53        W: std::io::Write,
54    {
55        self.serialize_box_header(&mut writer)?;
56        self.full_header.serialize(&mut writer)?;
57        self.entry_count.serialize(&mut writer)?;
58
59        for entry in &self.partition_entries {
60            entry.serialize(&mut writer)?;
61        }
62
63        if let Some(ref session_info) = self.session_info {
64            session_info.serialize(&mut writer)?;
65        }
66
67        if let Some(ref group_id_to_name) = self.group_id_to_name {
68            group_id_to_name.serialize(&mut writer)?;
69        }
70
71        Ok(())
72    }
73}
74
75/// FD item information partition entry
76///
77/// ISO/IEC 14996-12 - 8.13.2
78#[derive(IsoBox, Debug, PartialEq, Eq)]
79#[iso_box(box_type = b"paen", crate_path = crate)]
80pub struct PartitionEntry {
81    /// The contained [`FileReservoirBox`]. (optional)
82    #[iso_box(nested_box(collect))]
83    pub file_symbol_locations: Option<FileReservoirBox>,
84    /// The contained [`FilePartitionBox`]. (mandatory)
85    #[iso_box(nested_box)]
86    pub blocks_and_symbols: FilePartitionBox,
87    /// The contained [`FECReservoirBox`]. (optional)
88    #[iso_box(nested_box(collect))]
89    pub fec_symbol_locations: Option<FECReservoirBox>,
90}
91
92/// File partition box
93///
94/// ISO/IEC 14996-12 - 8.13.3
95#[derive(IsoBox, Debug, PartialEq, Eq)]
96#[iso_box(box_type = b"fpar", skip_impl(deserialize_seed, serialize, sized), crate_path = crate)]
97pub struct FilePartitionBox {
98    /// The full box header.
99    pub full_header: FullBoxHeader,
100    /// References the item in the [`ItemLocationBox`](super::ItemLocationBox) that the file partitioning applies to.
101    pub item_id: u32,
102    /// Gives the target ALC/LCT or FLUTE packet payload size of the partitioning
103    /// algorithm. Note that UDP packet payloads are larger, as they also contain ALC/LCT or FLUTE
104    /// headers.
105    pub packet_payload_size: u16,
106    /// Reserved 8 bits, must be set to 0.
107    pub reserved: u8,
108    /// Identifies the FEC encoding scheme using a "Reliable Multicast Transport
109    /// (RMT) FEC Encoding ID" declared at IANA, as defined in IETF RFC 5052. Note that i) value zero
110    /// corresponds to the "Compact No-Code FEC scheme" also known as "Null-FEC" (IETF RFC 3695);
111    /// ii) value one corresponds to the “MBMS FEC” (3GPP TS 26.346); iii) for values in the range of 0
112    /// to 127, inclusive, the FEC scheme is Fully-Specified, whereas for values in the range of 128 to 255,
113    /// inclusive, the FEC scheme is Under-Specified.
114    pub fec_encoding_id: u8,
115    /// Provides a more specific identification of the FEC encoder being used for an
116    /// Under-Specified FEC scheme. This value should be set to zero for Fully-Specified FEC schemes and
117    /// shall be ignored when parsing a file with `FEC_encoding_ID` in the range of 0 to 127, inclusive.
118    /// `FEC_instance_ID` is scoped by the `FEC_encoding_ID`. See IETF RFC 5052 for further details.
119    pub fec_instance_id: u16,
120    /// Gives the maximum number of source symbols per source block.
121    pub max_source_block_length: u16,
122    /// Gives the size (in bytes) of one encoding symbol. All encoding symbols of one
123    /// item have the same length, except the last symbol which may be shorter.
124    pub encoding_symbol_length: u16,
125    /// Gives the maximum number of encoding symbols that can be
126    /// generated for a source block for those FEC schemes in which the maximum number of encoding
127    /// symbols is relevant, such as FEC encoding ID 129 defined in IETF RFC 5052. For those FEC schemes
128    /// in which the maximum number of encoding symbols is not relevant, the semantics of this field is
129    /// unspecified.
130    pub max_number_of_encoding_symbols: u16,
131    /// The scheme-specific object transfer information (FEC-OTI-Scheme-Specific-Info).
132    /// The definition of the information depends on the FEC encoding ID.
133    pub scheme_specific_info: Base64String,
134    /// Gives the number of entries in the list of (`block_count`, `block_size`) pairs that provides a
135    /// partitioning of the source file. Starting from the beginning of the file, each entry indicates how the
136    /// next segment of the file is divided into source blocks and source symbols.
137    pub entry_count: u32,
138    /// `block_count` and `block_size` pairs.
139    pub entries: Vec<FilePartitionBoxEntry>,
140}
141
142impl<'a> DeserializeSeed<'a, BoxHeader> for FilePartitionBox {
143    fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> std::io::Result<Self>
144    where
145        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
146    {
147        let full_header = FullBoxHeader::deserialize(&mut reader)?;
148        let item_id = if full_header.version == 0 {
149            u16::deserialize(&mut reader)? as u32
150        } else {
151            u32::deserialize(&mut reader)?
152        };
153        let packet_payload_size = u16::deserialize(&mut reader)?;
154        let reserved = u8::deserialize(&mut reader)?;
155        let fec_encoding_id = u8::deserialize(&mut reader)?;
156        let fec_instance_id = u16::deserialize(&mut reader)?;
157        let max_source_block_length = u16::deserialize(&mut reader)?;
158        let encoding_symbol_length = u16::deserialize(&mut reader)?;
159        let max_number_of_encoding_symbols = u16::deserialize(&mut reader)?;
160        let scheme_specific_info = Base64String::deserialize(&mut reader)?;
161
162        let entry_count = if full_header.version == 0 {
163            u16::deserialize(&mut reader)? as u32
164        } else {
165            u32::deserialize(&mut reader)?
166        };
167
168        let mut entries = Vec::with_capacity(entry_count as usize);
169        for _ in 0..entry_count {
170            entries.push(FilePartitionBoxEntry::deserialize(&mut reader)?);
171        }
172
173        Ok(Self {
174            full_header,
175            item_id,
176            packet_payload_size,
177            reserved,
178            fec_encoding_id,
179            fec_instance_id,
180            max_source_block_length,
181            encoding_symbol_length,
182            max_number_of_encoding_symbols,
183            scheme_specific_info,
184            entry_count,
185            entries,
186        })
187    }
188}
189
190impl Serialize for FilePartitionBox {
191    fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
192    where
193        W: std::io::Write,
194    {
195        self.serialize_box_header(&mut writer)?;
196        self.full_header.serialize(&mut writer)?;
197        if self.full_header.version == 0 {
198            (self.item_id as u16).serialize(&mut writer)?;
199        } else {
200            self.item_id.serialize(&mut writer)?;
201        }
202        self.packet_payload_size.serialize(&mut writer)?;
203        self.reserved.serialize(&mut writer)?;
204        self.fec_encoding_id.serialize(&mut writer)?;
205        self.fec_instance_id.serialize(&mut writer)?;
206        self.max_source_block_length.serialize(&mut writer)?;
207        self.encoding_symbol_length.serialize(&mut writer)?;
208        self.max_number_of_encoding_symbols.serialize(&mut writer)?;
209        self.scheme_specific_info.serialize(&mut writer)?;
210
211        if self.full_header.version == 0 {
212            (self.entry_count as u16).serialize(&mut writer)?;
213        } else {
214            self.entry_count.serialize(&mut writer)?;
215        }
216
217        for entry in &self.entries {
218            entry.serialize(&mut writer)?;
219        }
220
221        Ok(())
222    }
223}
224
225impl IsoSized for FilePartitionBox {
226    fn size(&self) -> usize {
227        let mut size = self.full_header.size();
228        if self.full_header.version == 0 {
229            size += 2; // item_id
230        } else {
231            size += 4; // item_id
232        }
233        size += self.packet_payload_size.size()
234            + self.reserved.size()
235            + self.fec_encoding_id.size()
236            + self.fec_instance_id.size()
237            + self.max_source_block_length.size()
238            + self.encoding_symbol_length.size()
239            + self.max_number_of_encoding_symbols.size()
240            + self.scheme_specific_info.size();
241        if self.full_header.version == 0 {
242            size += 2; // entry_count
243        } else {
244            size += 4; // entry_count
245        }
246        size += self.entries.size();
247
248        Self::add_header_size(size)
249    }
250}
251
252/// Entry in the [`FilePartitionBox`].
253#[derive(Debug, PartialEq, Eq)]
254pub struct FilePartitionBoxEntry {
255    /// Indicates the number of consecutive source blocks of size `block_size`.
256    pub block_count: u16,
257    /// Indicates the size of a block (in bytes). A `block_size` that is not a multiple of the
258    /// `encoding_symbol_length` symbol size indicates with Compact No-Code FEC that the last source symbols
259    /// includes padding that is not stored in the item. With MBMS FEC (3GPP TS 26.346) the padding
260    /// may extend across multiple symbols but the size of padding should never be more than
261    /// `encoding_symbol_length`.
262    pub block_size: u32,
263}
264
265impl<'a> Deserialize<'a> for FilePartitionBoxEntry {
266    fn deserialize<R>(mut reader: R) -> std::io::Result<Self>
267    where
268        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
269    {
270        let block_count = u16::deserialize(&mut reader)?;
271        let block_size = u32::deserialize(&mut reader)?;
272
273        Ok(Self { block_count, block_size })
274    }
275}
276
277impl Serialize for FilePartitionBoxEntry {
278    fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
279    where
280        W: std::io::Write,
281    {
282        self.block_count.serialize(&mut writer)?;
283        self.block_size.serialize(&mut writer)?;
284        Ok(())
285    }
286}
287
288impl IsoSized for FilePartitionBoxEntry {
289    fn size(&self) -> usize {
290        self.block_count.size() + self.block_size.size()
291    }
292}
293
294/// FEC reservoir box
295///
296/// ISO/IEC 14996-12 - 8.13.4
297#[derive(IsoBox, Debug, PartialEq, Eq)]
298#[iso_box(box_type = b"fecr", skip_impl(deserialize_seed, serialize, sized), crate_path = crate)]
299pub struct FECReservoirBox {
300    /// The full box header.
301    pub full_header: FullBoxHeader,
302    /// Gives the number of entries in the [`entries`](Self::entries) vec. An entry count here should match the
303    /// total number of blocks in the corresponding [`FilePartitionBox`].
304    pub entry_count: u32,
305    /// The contained entries.
306    pub entries: Vec<FECReservoirBoxEntry>,
307}
308
309impl<'a> DeserializeSeed<'a, BoxHeader> for FECReservoirBox {
310    fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> std::io::Result<Self>
311    where
312        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
313    {
314        let full_header = FullBoxHeader::deserialize(&mut reader)?;
315        let entry_count = if full_header.version == 0 {
316            u16::deserialize(&mut reader)? as u32
317        } else {
318            u32::deserialize(&mut reader)?
319        };
320
321        let mut entries = Vec::with_capacity(entry_count as usize);
322        for _ in 0..entry_count {
323            entries.push(FECReservoirBoxEntry::deserialize_seed(&mut reader, full_header.version)?);
324        }
325
326        Ok(Self {
327            full_header,
328            entry_count,
329            entries,
330        })
331    }
332}
333
334impl Serialize for FECReservoirBox {
335    fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
336    where
337        W: std::io::Write,
338    {
339        self.serialize_box_header(&mut writer)?;
340        self.full_header.serialize(&mut writer)?;
341        if self.full_header.version == 0 {
342            (self.entry_count as u16).serialize(&mut writer)?;
343        } else {
344            self.entry_count.serialize(&mut writer)?;
345        }
346
347        for entry in &self.entries {
348            entry.serialize(&mut writer, self.full_header.version)?;
349        }
350
351        Ok(())
352    }
353}
354
355impl IsoSized for FECReservoirBox {
356    fn size(&self) -> usize {
357        let mut size = self.full_header.size();
358        if self.full_header.version == 0 {
359            size += (self.entry_count as u16).size();
360        } else {
361            size += self.entry_count.size();
362        }
363        size += self
364            .entries
365            .iter()
366            .map(|entry| entry.size(self.full_header.version))
367            .sum::<usize>();
368
369        Self::add_header_size(size)
370    }
371}
372
373/// Entry in the [`FECReservoirBox`].
374#[derive(Debug, PartialEq, Eq)]
375pub struct FECReservoirBoxEntry {
376    /// Indicates the location of the FEC reservoir associated with a source block.
377    pub item_id: u32,
378    /// Indicates the number of repair symbols contained in the FEC reservoir.
379    pub symbol_count: u32,
380}
381
382impl<'a> DeserializeSeed<'a, u8> for FECReservoirBoxEntry {
383    fn deserialize_seed<R>(mut reader: R, seed: u8) -> std::io::Result<Self>
384    where
385        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
386    {
387        let item_id = if seed == 0 {
388            u16::deserialize(&mut reader)? as u32
389        } else {
390            u32::deserialize(&mut reader)?
391        };
392        let symbol_count = u32::deserialize(&mut reader)?;
393
394        Ok(Self { item_id, symbol_count })
395    }
396}
397
398impl FECReservoirBoxEntry {
399    fn serialize<W>(&self, mut writer: W, version: u8) -> std::io::Result<()>
400    where
401        W: std::io::Write,
402    {
403        if version == 0 {
404            (self.item_id as u16).serialize(&mut writer)?;
405        } else {
406            self.item_id.serialize(&mut writer)?;
407        }
408        self.symbol_count.serialize(&mut writer)?;
409
410        Ok(())
411    }
412}
413
414impl FECReservoirBoxEntry {
415    /// Returns the size of the entry, depending on the version.
416    pub fn size(&self, version: u8) -> usize {
417        if version == 0 {
418            (self.item_id as u16).size() + self.symbol_count.size()
419        } else {
420            self.item_id.size() + self.symbol_count.size()
421        }
422    }
423}
424
425/// FD session group box
426///
427/// ISO/IEC 14996-12 - 8.13.5
428#[derive(IsoBox, Debug, PartialEq, Eq)]
429#[iso_box(box_type = b"segr", skip_impl(deserialize_seed, serialize), crate_path = crate)]
430pub struct FDSessionGroupBox {
431    /// Specifies the number of session groups.
432    pub num_session_groups: u16,
433    /// The contained session groups.
434    pub session_groups: Vec<FDSessionGroupBoxSessionGroup>,
435}
436
437impl<'a> DeserializeSeed<'a, BoxHeader> for FDSessionGroupBox {
438    fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> std::io::Result<Self>
439    where
440        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
441    {
442        let num_session_groups = u16::deserialize(&mut reader)?;
443
444        let mut session_groups = Vec::with_capacity(num_session_groups as usize);
445        for _ in 0..num_session_groups {
446            session_groups.push(FDSessionGroupBoxSessionGroup::deserialize(&mut reader)?);
447        }
448
449        Ok(Self {
450            num_session_groups,
451            session_groups,
452        })
453    }
454}
455
456impl Serialize for FDSessionGroupBox {
457    fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
458    where
459        W: std::io::Write,
460    {
461        self.serialize_box_header(&mut writer)?;
462        self.num_session_groups.serialize(&mut writer)?;
463
464        for group in &self.session_groups {
465            group.serialize(&mut writer)?;
466        }
467
468        Ok(())
469    }
470}
471
472/// Session group in the [`FDSessionGroupBox`].
473#[derive(Debug, PartialEq, Eq)]
474pub struct FDSessionGroupBoxSessionGroup {
475    /// Gives the number of entries in the following list comprising all file groups that the session
476    /// group complies with. The session group contains all files included in the listed file groups as
477    /// specified by the item information entry of each source file. The FDT for the session group should
478    /// only contain those groups that are listed in this structure.
479    pub entry_count: u8,
480    /// Indicates a file group that the session group complies with.
481    pub group_id: Vec<u32>,
482    /// Specifies the number of channels in the session group.
483    /// The value of `num_channels_in_session_groups` shall be a positive integer.
484    pub num_channels_in_session_group: u16,
485    /// Specifies the track identifier of the FD hint track belonging to a particular session group.
486    /// Note that one FD hint track corresponds to one LCT channel.
487    pub hint_track_id: Vec<u32>,
488}
489
490impl<'a> Deserialize<'a> for FDSessionGroupBoxSessionGroup {
491    fn deserialize<R>(mut reader: R) -> std::io::Result<Self>
492    where
493        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
494    {
495        let entry_count = u8::deserialize(&mut reader)?;
496        let mut group_id = Vec::with_capacity(entry_count as usize);
497        for _ in 0..entry_count {
498            group_id.push(u32::deserialize(&mut reader)?);
499        }
500
501        let num_channels_in_session_group = u16::deserialize(&mut reader)?;
502        let mut hint_track_id = Vec::with_capacity(entry_count as usize);
503        for _ in 0..entry_count {
504            hint_track_id.push(u32::deserialize(&mut reader)?);
505        }
506
507        Ok(Self {
508            entry_count,
509            group_id,
510            num_channels_in_session_group,
511            hint_track_id,
512        })
513    }
514}
515
516impl Serialize for FDSessionGroupBoxSessionGroup {
517    fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
518    where
519        W: std::io::Write,
520    {
521        self.entry_count.serialize(&mut writer)?;
522        for id in &self.group_id {
523            id.serialize(&mut writer)?;
524        }
525
526        self.num_channels_in_session_group.serialize(&mut writer)?;
527        for id in &self.hint_track_id {
528            id.serialize(&mut writer)?;
529        }
530
531        Ok(())
532    }
533}
534
535impl IsoSized for FDSessionGroupBoxSessionGroup {
536    fn size(&self) -> usize {
537        self.entry_count.size()
538            + self.group_id.size()
539            + self.num_channels_in_session_group.size()
540            + self.hint_track_id.size()
541    }
542}
543
544/// Group ID to name box
545///
546/// ISO/IEC 14996-12 - 8.13.6
547#[derive(IsoBox, Debug, PartialEq, Eq)]
548#[iso_box(box_type = b"gitn", skip_impl(deserialize_seed, serialize), crate_path = crate)]
549pub struct GroupIdToNameBox {
550    /// The full box header.
551    pub full_header: FullBoxHeader,
552    /// Gives the number of entries in the [`entries`](Self::entries) vec.
553    pub entry_count: u16,
554    /// The contained entries.
555    pub entries: Vec<GroupIdToNameBoxEntry>,
556}
557
558impl<'a> DeserializeSeed<'a, BoxHeader> for GroupIdToNameBox {
559    fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> std::io::Result<Self>
560    where
561        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
562    {
563        let full_header = FullBoxHeader::deserialize(&mut reader)?;
564        let entry_count = u16::deserialize(&mut reader)?;
565
566        let mut entries = Vec::with_capacity(entry_count as usize);
567        for _ in 0..entry_count {
568            entries.push(GroupIdToNameBoxEntry::deserialize(&mut reader)?);
569        }
570
571        Ok(Self {
572            full_header,
573            entry_count,
574            entries,
575        })
576    }
577}
578
579impl Serialize for GroupIdToNameBox {
580    fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
581    where
582        W: std::io::Write,
583    {
584        self.serialize_box_header(&mut writer)?;
585        self.full_header.serialize(&mut writer)?;
586        self.entry_count.serialize(&mut writer)?;
587
588        for entry in &self.entries {
589            entry.serialize(&mut writer)?;
590        }
591
592        Ok(())
593    }
594}
595
596/// Entry in the [`GroupIdToNameBox`].
597#[derive(Debug, PartialEq, Eq)]
598pub struct GroupIdToNameBoxEntry {
599    /// Indicates a file group.
600    pub group_id: u32,
601    /// The file group name.
602    pub group_name: Utf8String,
603}
604
605impl<'a> Deserialize<'a> for GroupIdToNameBoxEntry {
606    fn deserialize<R>(mut reader: R) -> std::io::Result<Self>
607    where
608        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
609    {
610        Ok(Self {
611            group_id: u32::deserialize(&mut reader)?,
612            group_name: Utf8String::deserialize(&mut reader)?,
613        })
614    }
615}
616
617impl Serialize for GroupIdToNameBoxEntry {
618    fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
619    where
620        W: std::io::Write,
621    {
622        self.group_id.serialize(&mut writer)?;
623        self.group_name.serialize(&mut writer)?;
624        Ok(())
625    }
626}
627
628impl IsoSized for GroupIdToNameBoxEntry {
629    fn size(&self) -> usize {
630        self.group_id.size() + self.group_name.size()
631    }
632}
633
634/// File reservoir box
635///
636/// ISO/IEC 14996-12 - 8.13.7
637#[derive(IsoBox, Debug, PartialEq, Eq)]
638#[iso_box(box_type = b"fire", skip_impl(deserialize_seed, serialize, sized), crate_path = crate)]
639pub struct FileReservoirBox {
640    /// The full box header.
641    pub full_header: FullBoxHeader,
642    /// Gives the number of entries in the [`entries`](Self::entries) vec. An entry count here should match the
643    /// total number or blocks in the corresponding [`FilePartitionBox`].
644    pub entry_count: u32,
645    /// The contained entries.
646    pub entries: Vec<FileReservoirBoxEntry>,
647}
648
649impl<'a> DeserializeSeed<'a, BoxHeader> for FileReservoirBox {
650    fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> std::io::Result<Self>
651    where
652        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
653    {
654        let full_header = FullBoxHeader::deserialize(&mut reader)?;
655        let entry_count = if full_header.version == 0 {
656            u16::deserialize(&mut reader)? as u32
657        } else {
658            u32::deserialize(&mut reader)?
659        };
660
661        let mut entries = Vec::with_capacity(entry_count as usize);
662        for _ in 0..entry_count {
663            entries.push(FileReservoirBoxEntry::deserialize_seed(&mut reader, full_header.version)?);
664        }
665
666        Ok(Self {
667            full_header,
668            entry_count,
669            entries,
670        })
671    }
672}
673
674impl Serialize for FileReservoirBox {
675    fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
676    where
677        W: std::io::Write,
678    {
679        self.serialize_box_header(&mut writer)?;
680        self.full_header.serialize(&mut writer)?;
681        if self.full_header.version == 0 {
682            (self.entry_count as u16).serialize(&mut writer)?;
683        } else {
684            self.entry_count.serialize(&mut writer)?;
685        }
686
687        for entry in &self.entries {
688            entry.serialize(&mut writer, self.full_header.version)?;
689        }
690
691        Ok(())
692    }
693}
694
695impl IsoSized for FileReservoirBox {
696    fn size(&self) -> usize {
697        let mut size = self.full_header.size();
698        if self.full_header.version == 0 {
699            size += (self.entry_count as u16).size();
700        } else {
701            size += self.entry_count.size();
702        }
703        size += self
704            .entries
705            .iter()
706            .map(|entry| entry.size(self.full_header.version))
707            .sum::<usize>();
708
709        Self::add_header_size(size)
710    }
711}
712
713/// Entry in the [`FileReservoirBox`].
714#[derive(Debug, PartialEq, Eq)]
715pub struct FileReservoirBoxEntry {
716    /// Indicates the location of the File reservoir associated with a source block.
717    pub item_id: u32,
718    /// Indicates the number of source symbols contained in the file reservoir.
719    pub symbol_count: u32,
720}
721
722impl<'a> DeserializeSeed<'a, u8> for FileReservoirBoxEntry {
723    fn deserialize_seed<R>(mut reader: R, seed: u8) -> std::io::Result<Self>
724    where
725        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
726    {
727        let item_id = if seed == 0 {
728            u16::deserialize(&mut reader)? as u32
729        } else {
730            u32::deserialize(&mut reader)?
731        };
732        let symbol_count = u32::deserialize(&mut reader)?;
733
734        Ok(Self { item_id, symbol_count })
735    }
736}
737
738impl FileReservoirBoxEntry {
739    fn serialize<W>(&self, mut writer: W, version: u8) -> std::io::Result<()>
740    where
741        W: std::io::Write,
742    {
743        if version == 0 {
744            (self.item_id as u16).serialize(&mut writer)?;
745        } else {
746            self.item_id.serialize(&mut writer)?;
747        }
748        self.symbol_count.serialize(&mut writer)?;
749
750        Ok(())
751    }
752}
753
754impl FileReservoirBoxEntry {
755    /// Returns the size of the entry, depending on the version.
756    pub fn size(&self, version: u8) -> usize {
757        if version == 0 {
758            (self.item_id as u16).size() + self.symbol_count.size()
759        } else {
760            self.item_id.size() + self.symbol_count.size()
761        }
762    }
763}