1#![allow(missing_docs)]
2
3use crate::error::Result;
4
5use super::error::{ParseResultExt, WhileParsingField};
6use super::{BoxType, Boxes, BoxesValidator, ParseBox, ParseError, ParsedBox, TrakBox};
7
8#[derive(Clone, Debug, ParseBox, ParsedBox)]
9#[box_type = "moov"]
10pub struct MoovBox {
11 children: Boxes<MoovChildrenValidator>,
12}
13
14pub(crate) struct MoovChildrenValidator;
15
16const NAME: BoxType = BoxType::MOOV;
17
18impl MoovBox {
19 #[cfg(test)]
20 pub(crate) fn with_children<C: Into<Boxes<MoovChildrenValidator>>>(children: C) -> Self {
21 Self { children: children.into() }
22 }
23
24 pub fn traks(&mut self) -> impl Iterator<Item = Result<&mut TrakBox, ParseError>> + '_ {
25 self.children
26 .get_mut()
27 .map(|result| result.while_parsing_child(NAME, BoxType::TRAK))
28 }
29}
30
31impl BoxesValidator for MoovChildrenValidator {
32 fn validate<V>(children: &Boxes<V>) -> Result<(), ParseError> {
33 ensure_attach!(
34 children.box_types().any(|box_type| box_type == BoxType::TRAK),
35 ParseError::MissingRequiredBox(BoxType::TRAK),
36 WhileParsingField(NAME, "children"),
37 );
38 Ok(())
39 }
40}
41
42#[cfg(test)]
43mod test {
44 use bytes::BytesMut;
45
46 use crate::parse::Mp4Box;
47
48 use super::*;
49
50 fn test_trak() -> Mp4Box<TrakBox> {
51 Mp4Box::with_data(TrakBox::with_children(vec![]).into()).unwrap()
52 }
53
54 #[test]
55 fn roundtrip() {
56 let mut data = BytesMut::new();
57 MoovBox::with_children(vec![test_trak().into()]).put_buf(&mut data);
58 MoovBox::parse(&mut data).unwrap();
59 }
60
61 #[test]
62 fn no_traks() {
63 let mut data = BytesMut::new();
64 MoovBox::with_children(vec![]).put_buf(&mut data);
65 let err = MoovBox::parse(&mut data).unwrap_err();
66 assert!(
67 matches!(err.get_ref(), ParseError::MissingRequiredBox(BoxType::TRAK)),
68 "{err}",
69 );
70 }
71}