traits: Move {Split,Merge}Tag to lofty::tag

This commit is contained in:
Serial 2024-04-14 12:46:16 -04:00 committed by Alex
parent e8fdbf4cdd
commit bf6e83876d
12 changed files with 90 additions and 88 deletions

View file

@ -7,8 +7,9 @@ use crate::config::WriteOptions;
use crate::error::{LoftyError, Result};
use crate::id3::v2::util::pairs::{format_number_pair, set_number, NUMBER_PAIR_KEYS};
use crate::tag::item::ItemValueRef;
use crate::tag::{try_parse_year, Accessor, ItemKey, ItemValue, Tag, TagExt, TagItem, TagType};
use crate::traits::{MergeTag, SplitTag};
use crate::tag::{
try_parse_year, Accessor, ItemKey, ItemValue, MergeTag, SplitTag, Tag, TagExt, TagItem, TagType,
};
use std::borrow::Cow;
use std::fs::File;

View file

@ -1,8 +1,7 @@
use crate::config::WriteOptions;
use crate::error::{LoftyError, Result};
use crate::id3::v1::constants::GENRES;
use crate::tag::{Accessor, ItemKey, ItemValue, Tag, TagExt, TagItem, TagType};
use crate::traits::{MergeTag, SplitTag};
use crate::tag::{Accessor, ItemKey, ItemValue, MergeTag, SplitTag, Tag, TagExt, TagItem, TagType};
use std::borrow::Cow;
use std::fs::File;

View file

@ -18,8 +18,9 @@ use crate::id3::v2::util::pairs::{
};
use crate::id3::v2::KeyValueFrame;
use crate::picture::{Picture, PictureType, TOMBSTONE_PICTURE};
use crate::tag::{try_parse_year, Accessor, ItemKey, ItemValue, Tag, TagExt, TagItem, TagType};
use crate::traits::{MergeTag, SplitTag};
use crate::tag::{
try_parse_year, Accessor, ItemKey, ItemValue, MergeTag, SplitTag, Tag, TagExt, TagItem, TagType,
};
use crate::util::text::{decode_text, TextDecodeOptions, TextEncoding};
use std::borrow::Cow;

View file

@ -2,8 +2,7 @@ use crate::config::WriteOptions;
use crate::error::{LoftyError, Result};
use crate::iff::chunk::Chunks;
use crate::macros::err;
use crate::tag::{Accessor, ItemKey, ItemValue, Tag, TagExt, TagItem, TagType};
use crate::traits::{MergeTag, SplitTag};
use crate::tag::{Accessor, ItemKey, ItemValue, MergeTag, SplitTag, Tag, TagExt, TagItem, TagType};
use std::borrow::Cow;
use std::fs::File;

View file

@ -3,8 +3,9 @@ mod write;
use crate::config::WriteOptions;
use crate::error::{LoftyError, Result};
use crate::tag::{try_parse_year, Accessor, ItemKey, ItemValue, Tag, TagExt, TagItem, TagType};
use crate::traits::{MergeTag, SplitTag};
use crate::tag::{
try_parse_year, Accessor, ItemKey, ItemValue, MergeTag, SplitTag, Tag, TagExt, TagItem, TagType,
};
use std::borrow::Cow;
use std::fs::File;

View file

@ -194,6 +194,5 @@ pub mod prelude {
pub use crate::error::LoftyError;
pub use crate::file::{AudioFile, TaggedFileExt};
pub use crate::tag::{Accessor, ItemKey, TagExt};
pub use crate::traits::{MergeTag, SplitTag};
pub use crate::tag::{Accessor, ItemKey, MergeTag, SplitTag, TagExt};
}

View file

@ -9,8 +9,9 @@ use crate::config::WriteOptions;
use crate::error::LoftyError;
use crate::mp4::ilst::atom::AtomDataStorage;
use crate::picture::{Picture, PictureType, TOMBSTONE_PICTURE};
use crate::tag::{try_parse_year, Accessor, ItemKey, ItemValue, Tag, TagExt, TagItem, TagType};
use crate::traits::{MergeTag, SplitTag};
use crate::tag::{
try_parse_year, Accessor, ItemKey, ItemValue, MergeTag, SplitTag, Tag, TagExt, TagItem, TagType,
};
use atom::{AdvisoryRating, Atom, AtomData};
use std::borrow::Cow;

View file

@ -6,8 +6,9 @@ use crate::ogg::picture_storage::OggPictureStorage;
use crate::ogg::write::OGGFormat;
use crate::picture::{Picture, PictureInformation};
use crate::probe::Probe;
use crate::tag::{try_parse_year, Accessor, ItemKey, ItemValue, Tag, TagExt, TagItem, TagType};
use crate::traits::{MergeTag, SplitTag};
use crate::tag::{
try_parse_year, Accessor, ItemKey, ItemValue, MergeTag, SplitTag, Tag, TagExt, TagItem, TagType,
};
use std::borrow::Cow;
use std::fs::File;

View file

@ -2,8 +2,9 @@
mod accessor;
pub(crate) mod item;
mod split_merge_tag;
mod tag_ext;
mod tag_type;
mod tagext;
pub(crate) mod utils;
use crate::config::WriteOptions;
@ -11,7 +12,6 @@ use crate::error::{LoftyError, Result};
use crate::macros::err;
use crate::picture::{Picture, PictureType};
use crate::probe::Probe;
use crate::traits::{MergeTag, SplitTag};
use std::borrow::Cow;
use std::fs::File;
@ -21,8 +21,9 @@ use std::path::Path;
// Exports
pub use accessor::Accessor;
pub use item::{ItemKey, ItemValue, TagItem};
pub use split_merge_tag::{MergeTag, SplitTag};
pub use tag_ext::TagExt;
pub use tag_type::TagType;
pub use tagext::TagExt;
macro_rules! impl_accessor {
($($item_key:ident => $name:tt),+) => {

View file

@ -0,0 +1,68 @@
use super::Tag;
/// Split (and merge) tags.
///
/// Useful and required for implementing lossless read/modify/write round trips.
/// Its counterpart `MergeTag` is used for recombining the results later.
///
/// # Example
///
/// ```rust,no_run
/// use lofty::config::{ParseOptions, WriteOptions};
/// use lofty::mpeg::MpegFile;
/// use lofty::prelude::*;
///
/// // Read the tag from a file
/// # fn main() -> lofty::error::Result<()> {
/// # let mut file = std::fs::OpenOptions::new().write(true).open("/path/to/file.mp3")?;
/// # let parse_options = ParseOptions::default();
/// let mut mpeg_file = <MpegFile as AudioFile>::read_from(&mut file, parse_options)?;
/// let mut id3v2 = mpeg_file
/// .id3v2_mut()
/// .map(std::mem::take)
/// .unwrap_or_default();
///
/// // Split: ID3v2 -> [`lofty::Tag`]
/// let (mut remainder, mut tag) = id3v2.split_tag();
///
/// // Modify the metadata in the generic [`lofty::Tag`], independent
/// // of the underlying tag and file format.
/// tag.insert_text(ItemKey::TrackTitle, "Track Title".to_owned());
/// tag.remove_key(&ItemKey::Composer);
///
/// // ID3v2 <- [`lofty::Tag`]
/// let id3v2 = remainder.merge_tag(tag);
///
/// // Write the changes back into the file
/// mpeg_file.set_id3v2(id3v2);
/// mpeg_file.save_to(&mut file, WriteOptions::default())?;
///
/// # Ok(()) }
/// ```
pub trait SplitTag {
/// The remainder of the split operation that is not represented
/// in the resulting `Tag`.
type Remainder: MergeTag;
/// Extract and split generic contents into a [`Tag`].
///
/// Returns the remaining content that cannot be represented in the
/// resulting `Tag` in `Self::Remainder`. This is useful if the
/// modified [`Tag`] is merged later using [`MergeTag::merge_tag`].
fn split_tag(self) -> (Self::Remainder, Tag);
}
/// The counterpart of [`SplitTag`].
pub trait MergeTag {
/// The resulting tag.
type Merged: SplitTag;
/// Merge a generic [`Tag`] back into the remainder of [`SplitTag::split_tag`].
///
/// Restores the original representation merged with the contents of
/// `tag` for further processing, e.g. writing back into a file.
///
/// Multi-valued items in `tag` with identical keys might get lost
/// depending on the support for multi-valued fields in `self`.
fn merge_tag(self, tag: Tag) -> Self::Merged;
}

View file

@ -1,72 +1,3 @@
use crate::tag::Tag;
/// Split (and merge) tags.
///
/// Useful and required for implementing lossless read/modify/write round trips.
/// Its counterpart `MergeTag` is used for recombining the results later.
///
/// # Example
///
/// ```rust,no_run
/// use lofty::config::{ParseOptions, WriteOptions};
/// use lofty::mpeg::MpegFile;
/// use lofty::prelude::*;
///
/// // Read the tag from a file
/// # fn main() -> lofty::error::Result<()> {
/// # let mut file = std::fs::OpenOptions::new().write(true).open("/path/to/file.mp3")?;
/// # let parse_options = ParseOptions::default();
/// let mut mpeg_file = <MpegFile as AudioFile>::read_from(&mut file, parse_options)?;
/// let mut id3v2 = mpeg_file
/// .id3v2_mut()
/// .map(std::mem::take)
/// .unwrap_or_default();
///
/// // Split: ID3v2 -> [`lofty::Tag`]
/// let (mut remainder, mut tag) = id3v2.split_tag();
///
/// // Modify the metadata in the generic [`lofty::Tag`], independent
/// // of the underlying tag and file format.
/// tag.insert_text(ItemKey::TrackTitle, "Track Title".to_owned());
/// tag.remove_key(&ItemKey::Composer);
///
/// // ID3v2 <- [`lofty::Tag`]
/// let id3v2 = remainder.merge_tag(tag);
///
/// // Write the changes back into the file
/// mpeg_file.set_id3v2(id3v2);
/// mpeg_file.save_to(&mut file, WriteOptions::default())?;
///
/// # Ok(()) }
/// ```
pub trait SplitTag {
/// The remainder of the split operation that is not represented
/// in the resulting `Tag`.
type Remainder: MergeTag;
/// Extract and split generic contents into a [`Tag`].
///
/// Returns the remaining content that cannot be represented in the
/// resulting `Tag` in `Self::Remainder`. This is useful if the
/// modified [`Tag`] is merged later using [`MergeTag::merge_tag`].
fn split_tag(self) -> (Self::Remainder, Tag);
}
/// The counterpart of [`SplitTag`].
pub trait MergeTag {
/// The resulting tag.
type Merged: SplitTag;
/// Merge a generic [`Tag`] back into the remainder of [`SplitTag::split_tag`].
///
/// Restores the original representation merged with the contents of
/// `tag` for further processing, e.g. writing back into a file.
///
/// Multi-valued items in `tag` with identical keys might get lost
/// depending on the support for multi-valued fields in `self`.
fn merge_tag(self, tag: Tag) -> Self::Merged;
}
// TODO: https://github.com/rust-lang/rust/issues/59359
pub(crate) trait SeekStreamLen: std::io::Seek {
fn stream_len(&mut self) -> crate::error::Result<u64> {