scuffle_mp4/boxes/
macros.rs1macro_rules! match_helper {
2 ([size] $expr:expr, $($name:tt,)*) => {
3 match $expr {
4 $(
5 Self::$name(box_) => box_.size(),
6 )*
7 Self::Unknown((_, data)) => {
8 let size = data.len() as u64 + 8;
9 if size > u32::MAX as u64 {
10 size + 8
11 } else {
12 size
13 }
14 }
15 }
16 };
17 ([write] $expr:expr, $writer:expr, $($name:tt,)*) => {
18 match $expr {
19 $(
20 Self::$name(box_) => box_.mux($writer)?,
21 )*
22 Self::Unknown((header, data)) => {
23 let size = data.len() as u64 + 8;
24 if size > u32::MAX as u64 {
25 $writer.write_u32::<byteorder::BigEndian>(1)?;
26 } else {
27 $writer.write_u32::<byteorder::BigEndian>(size as u32)?;
28 }
29 $writer.write_all(&header.box_type)?;
30 if size > u32::MAX as u64 {
31 $writer.write_u64::<byteorder::BigEndian>(size)?;
32 }
33 $writer.write_all(data)?;
34 }
35 }
36 };
37 ([parse] $expr:expr, $header:expr, $data:expr, $($name:tt,)*) => {
38 match $expr {
39 $(
40 &$name::NAME => Ok(Self::$name(Box::new(<$name>::demux($header, $data)?))),
41 )*
42 _ => Ok(Self::Unknown(($header, $data))),
43 }
44 };
45}
46
47macro_rules! as_fn {
48 ($($type:tt,)*) => {
49 $(
50 paste! {
51 #[allow(dead_code)]
52 pub fn [<as_ $type:lower>](&self) -> Option<&$type> {
53 match self {
54 Self::$type(box_) => Some(box_),
55 _ => None,
56 }
57 }
58 }
59 )*
60 };
61}
62
63macro_rules! impl_from {
64 ($($type:tt,)*) => {
65 $(
66 impl From<$type> for DynBox {
67 fn from(box_: $type) -> Self {
68 Self::$type(Box::new(box_))
69 }
70 }
71 )*
72 };
73}
74
75macro_rules! impl_box {
76 ($($type:tt,)*) => {
77 #[derive(Debug, Clone, PartialEq)]
78 pub enum DynBox {
79 $(
80 $type(Box<$type>),
81 )*
82 Unknown((BoxHeader, Bytes)),
83 }
84
85 impl DynBox {
86 pub fn size(&self) -> u64 {
87 match_helper!(
88 [size] self,
89 $($type,)*
90 )
91 }
92
93 pub fn mux<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
94 match_helper!(
95 [write] self, writer,
96 $($type,)*
97 );
98
99 Ok(())
100 }
101
102 pub fn demux(reader: &mut io::Cursor<Bytes>) -> io::Result<Self> {
103 let (header, data) = BoxHeader::demux(reader)?;
104
105 match_helper!(
106 [parse] & header.box_type,
107 header,
108 data,
109 $($type,)*
110 )
111 }
112
113 pub fn name(&self) -> &str {
114 match self {
115 $(
116 Self::$type(_) => std::str::from_utf8(&$type::NAME).expect("invalid utf8"),
117 )*
118 Self::Unknown((header, _)) => std::str::from_utf8(&header.box_type).unwrap_or("unknown"),
119 }
120 }
121
122 as_fn!(
123 $($type,)*
124 );
125 }
126
127
128 impl_from!(
129 $($type,)*
130 );
131 };
132}