mp4san 0.5.3

An MP4 file sanitizer.
Documentation
#![allow(missing_docs)]

use crate::error::Result;

use super::error::{ParseResultExt, WhileParsingField};
use super::{BoxType, Boxes, BoxesValidator, ParseBox, ParseError, ParsedBox, TrakBox};

#[derive(Clone, Debug, ParseBox, ParsedBox)]
#[box_type = "moov"]
pub struct MoovBox {
    children: Boxes<MoovChildrenValidator>,
}

pub(crate) struct MoovChildrenValidator;

const NAME: BoxType = BoxType::MOOV;

impl MoovBox {
    #[cfg(test)]
    pub(crate) fn with_children<C: Into<Boxes<MoovChildrenValidator>>>(children: C) -> Self {
        Self { children: children.into() }
    }

    pub fn traks(&mut self) -> impl Iterator<Item = Result<&mut TrakBox, ParseError>> + '_ {
        self.children
            .get_mut()
            .map(|result| result.while_parsing_child(NAME, BoxType::TRAK))
    }
}

impl BoxesValidator for MoovChildrenValidator {
    fn validate<V>(children: &Boxes<V>) -> Result<(), ParseError> {
        ensure_attach!(
            children.box_types().any(|box_type| box_type == BoxType::TRAK),
            ParseError::MissingRequiredBox(BoxType::TRAK),
            WhileParsingField(NAME, "children"),
        );
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use bytes::BytesMut;

    use crate::parse::Mp4Box;

    use super::*;

    fn test_trak() -> Mp4Box<TrakBox> {
        Mp4Box::with_data(TrakBox::with_children(vec![]).into()).unwrap()
    }

    #[test]
    fn roundtrip() {
        let mut data = BytesMut::new();
        MoovBox::with_children(vec![test_trak().into()]).put_buf(&mut data);
        MoovBox::parse(&mut data).unwrap();
    }

    #[test]
    fn no_traks() {
        let mut data = BytesMut::new();
        MoovBox::with_children(vec![]).put_buf(&mut data);
        let err = MoovBox::parse(&mut data).unwrap_err();
        assert!(
            matches!(err.get_ref(), ParseError::MissingRequiredBox(BoxType::TRAK)),
            "{err}",
        );
    }
}