1use std::io::Read;
2
3use crate::*;
4
5pub trait Atom: Sized {
7 const KIND: FourCC;
8
9 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self>;
10 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()>;
11
12 #[cfg(test)]
13 fn assert_encode_decode(&self)
14 where
15 Self: std::fmt::Debug + PartialEq,
16 {
17 let mut buf = Vec::new();
18 Self::encode(self, &mut buf).unwrap();
19
20 let mut cursor = std::io::Cursor::new(&buf);
21 let decoded = Self::decode(&mut cursor).unwrap();
22
23 assert_eq!(self, &decoded, "different decoded result");
24 }
25}
26
27impl<T: Atom> Encode for T {
28 fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
29 let start = buf.len();
30
31 0u32.encode(buf)?;
33 Self::KIND.encode(buf)?;
34 self.encode_body(buf)?;
35
36 let size: u32 = (buf.len() - start)
39 .try_into()
40 .map_err(|_| Error::TooLarge(T::KIND))?;
41
42 buf.set_slice(start, &size.to_be_bytes());
43
44 Ok(())
45 }
46}
47
48impl<T: Atom> Decode for T {
49 fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
50 Self::decode_maybe(buf)?.ok_or(Error::OutOfBounds)
51 }
52}
53
54impl<T: Atom> DecodeMaybe for T {
55 fn decode_maybe<B: Buf>(buf: &mut B) -> Result<Option<Self>> {
56 let header = match Header::decode_maybe(buf)? {
57 Some(header) => header,
58 None => return Ok(None),
59 };
60
61 let size = header.size.unwrap_or(buf.remaining());
62 if size > buf.remaining() {
63 return Ok(None);
64 }
65
66 let body = &mut buf.slice(size);
67
68 let atom = match Self::decode_body(body) {
69 Ok(atom) => atom,
70 Err(Error::OutOfBounds) => return Err(Error::OverDecode(T::KIND)),
71 Err(Error::ShortRead) => return Err(Error::UnderDecode(T::KIND)),
72 Err(err) => return Err(err),
73 };
74
75 if body.has_remaining() {
76 return Err(Error::UnderDecode(T::KIND));
77 }
78
79 buf.advance(size);
80
81 Ok(Some(atom))
82 }
83}
84
85impl<T: Atom> ReadFrom for T {
86 fn read_from<R: Read>(r: &mut R) -> Result<Self> {
87 <Option<T> as ReadFrom>::read_from(r)?.ok_or(Error::MissingBox(T::KIND))
88 }
89}
90
91impl<T: Atom> ReadFrom for Option<T> {
92 fn read_from<R: Read>(r: &mut R) -> Result<Self> {
93 let header = match <Option<Header> as ReadFrom>::read_from(r)? {
94 Some(header) => header,
95 None => return Ok(None),
96 };
97
98 let body = &mut header.read_body(r)?;
99
100 let atom = match T::decode_body(body) {
101 Ok(atom) => atom,
102 Err(Error::OutOfBounds) => return Err(Error::OverDecode(T::KIND)),
103 Err(Error::ShortRead) => return Err(Error::UnderDecode(T::KIND)),
104 Err(err) => return Err(err),
105 };
106
107 if body.has_remaining() {
108 return Err(Error::UnderDecode(T::KIND));
109 }
110
111 Ok(Some(atom))
112 }
113}
114
115impl<T: Atom> ReadUntil for T {
116 fn read_until<R: Read>(r: &mut R) -> Result<Self> {
117 <Option<T> as ReadUntil>::read_until(r)?.ok_or(Error::MissingBox(T::KIND))
118 }
119}
120
121impl<T: Atom> ReadUntil for Option<T> {
122 fn read_until<R: Read>(r: &mut R) -> Result<Self> {
123 while let Some(header) = <Option<Header> as ReadFrom>::read_from(r)? {
124 if header.kind == T::KIND {
125 let body = &mut header.read_body(r)?;
126 return Ok(Some(T::decode_atom(&header, body)?));
127 }
128 }
129
130 Ok(None)
131 }
132}
133
134impl<T: Atom> DecodeAtom for T {
135 fn decode_atom<B: Buf>(header: &Header, buf: &mut B) -> Result<T> {
136 if header.kind != T::KIND {
137 return Err(Error::UnexpectedBox(header.kind));
138 }
139
140 let size = header.size.unwrap_or(buf.remaining());
141 if size > buf.remaining() {
142 return Err(Error::OutOfBounds);
143 }
144
145 let body = &mut buf.slice(size);
146
147 let atom = match T::decode_body(body) {
148 Ok(atom) => atom,
149 Err(Error::OutOfBounds) => return Err(Error::OverDecode(T::KIND)),
150 Err(Error::ShortRead) => return Err(Error::UnderDecode(T::KIND)),
151 Err(err) => return Err(err),
152 };
153
154 if body.has_remaining() {
155 return Err(Error::UnderDecode(T::KIND));
156 }
157
158 buf.advance(size);
159
160 Ok(atom)
161 }
162}
163
164impl<T: Atom> ReadAtom for T {
165 fn read_atom<R: Read>(header: &Header, r: &mut R) -> Result<Self> {
166 if header.kind != T::KIND {
167 return Err(Error::UnexpectedBox(header.kind));
168 }
169
170 let body = &mut header.read_body(r)?;
171 Self::decode_atom(header, body)
172 }
173}
174
175macro_rules! nested {
185 (required: [$($required:ident),*$(,)?], optional: [$($optional:ident),*$(,)?], multiple: [$($multiple:ident),*$(,)?],) => {
186 paste::paste! {
187 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
188 $( let mut [<$required:lower>] = None;)*
189 $( let mut [<$optional:lower>] = None;)*
190 $( let mut [<$multiple:lower>] = Vec::new();)*
191
192 while let Some(atom) = Any::decode_maybe(buf)? {
193 match atom {
194 $(Any::$required(atom) => {
195 if [<$required:lower>].is_some() {
196 return Err(Error::DuplicateBox($required::KIND));
197 }
198 [<$required:lower>] = Some(atom);
199 },)*
200 $(Any::$optional(atom) => {
201 if [<$optional:lower>].is_some() {
202 return Err(Error::DuplicateBox($optional::KIND));
203 }
204 [<$optional:lower>] = Some(atom);
205 },)*
206 $(Any::$multiple(atom) => {
207 [<$multiple:lower>].push(atom);
208 },)*
209 Any::Unknown(kind, _) => {
210 tracing::warn!("unknown box: {:?}", kind);
211 },
212 _ => return Err(Error::UnexpectedBox(atom.kind())),
213 }
214 }
215
216 Ok(Self {
217 $([<$required:lower>]: [<$required:lower>].ok_or(Error::MissingBox($required::KIND))? ,)*
218 $([<$optional:lower>],)*
219 $([<$multiple:lower>],)*
220 })
221 }
222
223 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
224 $( self.[<$required:lower>].encode(buf)?; )*
225 $( self.[<$optional:lower>].encode(buf)?; )*
226 $( self.[<$multiple:lower>].encode(buf)?; )*
227
228 Ok(())
229 }
230 }
231 };
232}
233
234pub(crate) use nested;