Crate isobmff_derive

Source
Expand description

Derive helper macro for the isobmff crate.

Use this macro to implement the IsoBox trait as well as the resptive implementations of the Deserialize, DeserializeSeed, Serialize, and IsoSized traits.

§Usage

This derive macro can only be used on structs with named fields.

All field types must implement the Deserialize and Serialize traits from the scuffle_bytes_util crate. If that cannot be guaranteed, you should use the from field attribute. (See below)

§Struct Attributes

AttributeDescriptionRequired
box_typeThe FourCC box type of the box. Provide as a byte array of size 4 ([u8; 4]).Yes
crate_pathThe path to the isobmff crate. Defaults to ::isobmff.No
skip_implA list of impls that should be skipped by the code generation. (i.e. you want to implement them manually). Defaults to none.No

§Field Attributes

AttributeDescriptionRequired
fromIf specified, the provided type is parsed and then converted to the expected type using the From trait.No
repeatedRepeted fields are read repeatedly until the reader reaches EOF. There can only be one repeated field which should also appear as the last field in the struct.No
nested_boxCan be used to make other boxes part of the box. The reader will read all boxes after the actual payload (the other fields) was read. Use nested_box(collect) to read optional/multiple boxes. Use nested_box(collect_unknown) to capture any unknown boxes.No

§Example

use isobmff::IsoBox;

#[derive(IsoBox)]
#[iso_box(box_type = b"myb1")]
pub struct MyCustomBox {
    pub foo: u32,
    pub bar: u8,
    #[iso_box(repeated)]
    pub baz: Vec<i16>,
}

The macro will generate code equivalent to this:

use isobmff::{BoxHeader, BoxType, IsoBox, IsoSized};
use scuffle_bytes_util::IoResultExt;
use scuffle_bytes_util::zero_copy::{Deserialize, DeserializeSeed, Serialize, ZeroCopyReader};

impl IsoBox for MyCustomBox {
    const TYPE: BoxType = BoxType::FourCc(*b"myb1");
}

impl<'a> Deserialize<'a> for MyCustomBox {
    fn deserialize<R>(mut reader: R) -> std::io::Result<Self>
    where
        R: ZeroCopyReader<'a>,
    {
        let seed = BoxHeader::deserialize(&mut reader)?;

        if let Some(size) = BoxHeader::payload_size(&seed) {
            Self::deserialize_seed(reader.take(size), seed)
        } else {
            Self::deserialize_seed(reader, seed)
        }
    }
}

impl<'a> DeserializeSeed<'a, BoxHeader> for MyCustomBox {
    fn deserialize_seed<R>(mut reader: R, seed: BoxHeader) -> std::io::Result<Self>
    where
        R: ZeroCopyReader<'a>,
    {
        let foo = u32::deserialize(&mut reader)?;
        let bar = u8::deserialize(&mut reader)?;

        let baz = {
            if let Some(payload_size) = seed.payload_size() {
                let mut payload_reader = reader.take(payload_size);
                std::iter::from_fn(|| {
                    i16::deserialize(&mut payload_reader).eof_to_none().transpose()
                }).collect::<Result<Vec<_>, std::io::Error>>()?
            } else {
                std::iter::from_fn(|| {
                    i16::deserialize(&mut reader).eof_to_none().transpose()
                }).collect::<Result<Vec<_>, std::io::Error>>()?
            }
        };

        Ok(Self { foo, bar, baz })
    }
}

impl Serialize for MyCustomBox {
    fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
    where
        W: std::io::Write,
    {
        self.serialize_box_header(&mut writer)?;

        self.foo.serialize(&mut writer)?;
        self.bar.serialize(&mut writer)?;
        for item in &self.baz {
            item.serialize(&mut writer)?;
        }

        Ok(())
    }
}

impl IsoSized for MyCustomBox {
    fn size(&self) -> usize {
        Self::add_header_size(self.foo.size() + self.bar.size() + self.baz.size())
    }
}

§License

This project is licensed under the MIT or Apache-2.0 license. You can choose between one of them if you use this work.

SPDX-License-Identifier: MIT OR Apache-2.0

Derive Macros§

IsoBox
Derive helper macro for the isobmff crate.