Skip to content

Commit abf6b40

Browse files
committed
MP4: Add Atom::{merge, into_data}
1 parent 903cc9d commit abf6b40

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

src/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ pub enum ErrorKind {
5353

5454
/// Arises when an atom contains invalid data
5555
BadAtom(&'static str),
56+
/// Arises when attempting to use [`Atom::merge`](crate::mp4::Atom::merge) with mismatching identifiers
57+
AtomMismatch,
5658

5759
// Conversions for external errors
5860
/// Errors that arise while parsing OGG pages
@@ -520,6 +522,10 @@ impl Display for LoftyError {
520522
ErrorKind::TextDecode(message) => write!(f, "Text decoding: {message}"),
521523
ErrorKind::Id3v2(ref id3v2_err) => write!(f, "{id3v2_err}"),
522524
ErrorKind::BadAtom(message) => write!(f, "MP4 Atom: {message}"),
525+
ErrorKind::AtomMismatch => write!(
526+
f,
527+
"MP4 Atom: Attempted to use `Atom::merge()` with mismatching identifiers"
528+
),
523529

524530
// Files
525531
ErrorKind::TooMuchData => write!(

src/mp4/ilst/atom.rs

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::error::Result;
2+
use crate::macros::err;
13
use crate::mp4::AtomIdent;
24
use crate::picture::Picture;
35

@@ -29,6 +31,18 @@ impl Debug for AtomDataStorage {
2931
}
3032
}
3133

34+
impl IntoIterator for AtomDataStorage {
35+
type Item = AtomData;
36+
type IntoIter = std::vec::IntoIter<Self::Item>;
37+
38+
fn into_iter(self) -> Self::IntoIter {
39+
match self {
40+
AtomDataStorage::Single(s) => vec![s].into_iter(),
41+
AtomDataStorage::Multiple(v) => v.into_iter(),
42+
}
43+
}
44+
}
45+
3246
impl<'a> IntoIterator for &'a AtomDataStorage {
3347
type Item = &'a AtomData;
3448
type IntoIter = AtomDataStorageIter<'a>;
@@ -118,6 +132,16 @@ impl<'a> Atom<'a> {
118132
(&self.data).into_iter()
119133
}
120134

135+
/// Consumes the atom, returning its [`AtomData`]
136+
///
137+
/// # Examples
138+
///
139+
/// ```rust
140+
/// ```
141+
pub fn into_data(self) -> impl Iterator<Item = AtomData> {
142+
self.data.into_iter()
143+
}
144+
121145
/// Append a value to the atom
122146
pub fn push_data(&mut self, data: AtomData) {
123147
match self.data {
@@ -128,6 +152,49 @@ impl<'a> Atom<'a> {
128152
}
129153
}
130154

155+
/// Merge the data of another atom into this one
156+
///
157+
/// NOTE: Both atoms must have the same identifier
158+
///
159+
/// # Errors
160+
///
161+
/// * `self.ident()` != `other.ident()`
162+
///
163+
/// # Examples
164+
///
165+
/// ```rust
166+
/// use lofty::mp4::{Atom, AtomData, AtomIdent};
167+
///
168+
/// # fn main() -> lofty::Result<()> {
169+
/// // Create an artist atom
170+
/// let mut atom = Atom::new(
171+
/// AtomIdent::Fourcc(*b"\x49ART"),
172+
/// AtomData::UTF8(String::from("foo")),
173+
/// );
174+
///
175+
/// // Create a second and merge it into the first
176+
/// let atom2 = Atom::new(
177+
/// AtomIdent::Fourcc(*b"\x49ART"),
178+
/// AtomData::UTF8(String::from("bar")),
179+
/// );
180+
/// atom.merge(atom2)?;
181+
///
182+
/// // Our first atom now contains the second atom's content
183+
/// assert_eq!(atom.data().count(), 2);
184+
/// # Ok(()) }
185+
/// ```
186+
pub fn merge(&mut self, other: Atom<'_>) -> Result<()> {
187+
if self.ident != other.ident {
188+
err!(AtomMismatch);
189+
}
190+
191+
for data in other.data {
192+
self.push_data(data)
193+
}
194+
195+
Ok(())
196+
}
197+
131198
// Used internally, has no correctness checks
132199
pub(crate) fn unknown_implicit(ident: AtomIdent<'_>, data: Vec<u8>) -> Self {
133200
Self {
@@ -248,7 +315,7 @@ impl AdvisoryRating {
248315
impl TryFrom<u8> for AdvisoryRating {
249316
type Error = u8;
250317

251-
fn try_from(input: u8) -> Result<Self, Self::Error> {
318+
fn try_from(input: u8) -> std::result::Result<Self, Self::Error> {
252319
match input {
253320
0 => Ok(Self::Inoffensive),
254321
1 | 4 => Ok(Self::Explicit),

0 commit comments

Comments
 (0)