1use crate::error::Result;
2use crate::macros::err;
3use crate::mp4::AtomIdent;
4use crate::mp4::ilst::data_type::DataType;
5use crate::picture::Picture;
6
7use std::fmt::{Debug, Formatter};
8
9#[derive(PartialEq, Clone)]
12pub(super) enum AtomDataStorage {
13 Single(AtomData),
14 Multiple(Vec<AtomData>),
15}
16
17impl AtomDataStorage {
18 pub(super) fn first_mut(&mut self) -> &mut AtomData {
19 match self {
20 AtomDataStorage::Single(val) => val,
21 AtomDataStorage::Multiple(data) => data.first_mut().expect("not empty"),
22 }
23 }
24
25 pub(super) fn is_pictures(&self) -> bool {
26 match self {
27 AtomDataStorage::Single(v) => matches!(v, AtomData::Picture(_)),
28 AtomDataStorage::Multiple(v) => v.iter().all(|p| matches!(p, AtomData::Picture(_))),
29 }
30 }
31
32 pub(super) fn from_vec(mut v: Vec<AtomData>) -> Option<Self> {
33 match v.len() {
34 0 => None,
35 1 => Some(AtomDataStorage::Single(v.remove(0))),
36 _ => Some(AtomDataStorage::Multiple(v)),
37 }
38 }
39}
40
41impl Debug for AtomDataStorage {
42 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
43 match &self {
44 AtomDataStorage::Single(v) => write!(f, "{:?}", v),
45 AtomDataStorage::Multiple(v) => f.debug_list().entries(v.iter()).finish(),
46 }
47 }
48}
49
50impl IntoIterator for AtomDataStorage {
51 type Item = AtomData;
52 type IntoIter = std::vec::IntoIter<Self::Item>;
53
54 fn into_iter(self) -> Self::IntoIter {
55 match self {
56 AtomDataStorage::Single(s) => vec![s].into_iter(),
57 AtomDataStorage::Multiple(v) => v.into_iter(),
58 }
59 }
60}
61
62impl<'a> IntoIterator for &'a AtomDataStorage {
63 type Item = &'a AtomData;
64 type IntoIter = AtomDataStorageIter<'a>;
65
66 fn into_iter(self) -> Self::IntoIter {
67 let cap = match self {
68 AtomDataStorage::Single(_) => 0,
69 AtomDataStorage::Multiple(v) => v.len(),
70 };
71
72 Self::IntoIter {
73 storage: Some(self),
74 idx: 0,
75 cap,
76 }
77 }
78}
79
80pub(super) struct AtomDataStorageIter<'a> {
81 storage: Option<&'a AtomDataStorage>,
82 idx: usize,
83 cap: usize,
84}
85
86impl<'a> Iterator for AtomDataStorageIter<'a> {
87 type Item = &'a AtomData;
88
89 fn next(&mut self) -> Option<Self::Item> {
90 match self.storage {
91 Some(AtomDataStorage::Single(data)) => {
92 self.storage = None;
93 Some(data)
94 },
95 Some(AtomDataStorage::Multiple(data)) => {
96 if self.idx == self.cap {
97 self.storage = None;
98 return None;
99 }
100
101 let ret = &data[self.idx];
102 self.idx += 1;
103
104 Some(ret)
105 },
106 _ => None,
107 }
108 }
109}
110
111#[derive(PartialEq, Clone)]
113pub struct Atom<'a> {
114 pub(crate) ident: AtomIdent<'a>,
115 pub(super) data: AtomDataStorage,
116}
117
118impl<'a> Atom<'a> {
119 #[must_use]
121 pub const fn new(ident: AtomIdent<'a>, data: AtomData) -> Self {
122 Self {
123 ident,
124 data: AtomDataStorage::Single(data),
125 }
126 }
127
128 pub fn from_collection(ident: AtomIdent<'a>, mut data: Vec<AtomData>) -> Option<Self> {
132 let data = match data.len() {
133 0 => return None,
134 1 => AtomDataStorage::Single(data.swap_remove(0)),
135 _ => AtomDataStorage::Multiple(data),
136 };
137
138 Some(Self { ident, data })
139 }
140
141 pub fn ident(&self) -> &AtomIdent<'_> {
143 &self.ident
144 }
145
146 pub fn data(&self) -> impl Iterator<Item = &AtomData> {
148 (&self.data).into_iter()
149 }
150
151 pub fn into_data(self) -> impl Iterator<Item = AtomData> + use<> {
165 self.data.into_iter()
166 }
167
168 pub fn push_data(&mut self, data: AtomData) {
170 match self.data {
171 AtomDataStorage::Single(ref s) => {
172 self.data = AtomDataStorage::Multiple(vec![s.clone(), data])
173 },
174 AtomDataStorage::Multiple(ref mut m) => m.push(data),
175 }
176 }
177
178 pub fn merge(&mut self, other: Atom<'_>) -> Result<()> {
210 if self.ident != other.ident {
211 err!(AtomMismatch);
212 }
213
214 for data in other.data {
215 self.push_data(data)
216 }
217
218 Ok(())
219 }
220
221 pub(crate) fn unknown_implicit(ident: AtomIdent<'_>, data: Vec<u8>) -> Self {
223 Self {
224 ident: ident.into_owned(),
225 data: AtomDataStorage::Single(AtomData::Unknown {
226 code: DataType::Reserved,
227 data,
228 }),
229 }
230 }
231
232 pub(crate) fn text(ident: AtomIdent<'_>, data: String) -> Self {
233 Self {
234 ident: ident.into_owned(),
235 data: AtomDataStorage::Single(AtomData::UTF8(data)),
236 }
237 }
238
239 pub(crate) fn into_owned(self) -> Atom<'static> {
240 let Self { ident, data } = self;
241 Atom {
242 ident: ident.into_owned(),
243 data,
244 }
245 }
246}
247
248impl Debug for Atom<'_> {
249 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
250 f.debug_struct("Atom")
251 .field("ident", &self.ident)
252 .field("data", &self.data)
253 .finish()
254 }
255}
256
257#[derive(Debug, PartialEq, Eq, Clone)]
268pub enum AtomData {
269 UTF8(String),
271 UTF16(String),
273 Picture(Picture),
277 SignedInteger(i32),
287 UnsignedInteger(u32),
291 Bool(bool),
297 Unknown {
303 code: DataType,
305 data: Vec<u8>,
307 },
308}
309
310impl AtomData {
311 pub fn data_type(&self) -> DataType {
337 match self {
338 AtomData::UTF8(_) => DataType::Utf8,
339 AtomData::UTF16(_) => DataType::Utf16,
340 AtomData::SignedInteger(_) | AtomData::Bool(_) => DataType::BeSignedInteger,
341 AtomData::UnsignedInteger(_) => DataType::BeUnsignedInteger,
342 AtomData::Picture(p) => {
343 let Some(mime) = p.mime_type() else {
344 return DataType::Reserved;
345 };
346
347 DataType::from(mime)
348 },
349 AtomData::Unknown { code, .. } => *code,
350 }
351 }
352}