From 8f485244db0ad744b96d688c8d41d6f53414415f Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Sat, 2 Nov 2024 00:57:56 -0400 Subject: [PATCH] EBML: add generic conversion to `MatroskaTagRef` --- lofty/src/ebml/tag/generic.rs | 24 +++++++----- lofty/src/ebml/tag/mod.rs | 47 +++++++++++++++-------- lofty/src/ebml/tag/tag.rs | 7 +--- lofty/src/ebml/tag/write/elements/tags.rs | 8 +--- lofty/src/tag/utils.rs | 7 ++-- lofty_attr/src/internal.rs | 7 +++- 6 files changed, 58 insertions(+), 42 deletions(-) diff --git a/lofty/src/ebml/tag/generic.rs b/lofty/src/ebml/tag/generic.rs index 071f2ec4..6a1bb075 100644 --- a/lofty/src/ebml/tag/generic.rs +++ b/lofty/src/ebml/tag/generic.rs @@ -6,6 +6,7 @@ use super::{Language, MatroskaTag, SimpleTag, TargetType, TOMBSTONE_SIMPLE_TAG}; use crate::tag::items::Lang; use crate::tag::{ItemKey, ItemValue, Tag, TagItem, TagType}; +use std::borrow::Cow; use std::collections::HashMap; use std::sync::LazyLock; @@ -203,7 +204,7 @@ fn split_simple_tags( pub(super) fn merge_tag(tag: Tag, mut matroska_tag: MatroskaTag) -> MatroskaTag { for item in tag.items { - let Some((simple_tag, target_type)) = simple_tag_for_item(item) else { + let Some((simple_tag, target_type)) = simple_tag_for_item(Cow::Owned(item)) else { continue; }; @@ -215,21 +216,24 @@ pub(super) fn merge_tag(tag: Tag, mut matroska_tag: MatroskaTag) -> MatroskaTag matroska_tag } -fn simple_tag_for_item(item: TagItem) -> Option<(SimpleTag<'static>, TargetType)> { +pub(super) fn simple_tag_for_item( + item: Cow<'_, TagItem>, +) -> Option<(SimpleTag<'static>, TargetType)> { + if !matches!(item.item_value, ItemValue::Text(_) | ItemValue::Locator(_)) { + return None; + } + + let (target_type, simple_tag_name) = REVERSE_MAPPINGS.get(&item.item_key).copied()?; + let TagItem { mut lang, - item_key, item_value: ItemValue::Text(text) | ItemValue::Locator(text), .. - } = item + } = item.into_owned() else { return None; }; - let Some((target_type, simple_tag_name)) = REVERSE_MAPPINGS.get(&item_key) else { - return None; - }; - // Matroska uses "und" for unknown languages if lang == *b"XXX" { lang = *b"und"; @@ -237,8 +241,8 @@ fn simple_tag_for_item(item: TagItem) -> Option<(SimpleTag<'static>, TargetType) let lang_str = std::str::from_utf8(lang.as_slice()).unwrap_or("und"); - let mut simple_tag = SimpleTag::new(simple_tag_name.to_string(), text); + let mut simple_tag = SimpleTag::new((*simple_tag_name).to_string(), text); simple_tag.language = Language::Iso639_2(lang_str.to_string()); - Some((simple_tag, *target_type)) + Some((simple_tag, target_type)) } diff --git a/lofty/src/ebml/tag/mod.rs b/lofty/src/ebml/tag/mod.rs index 8fa36c84..3345e90d 100644 --- a/lofty/src/ebml/tag/mod.rs +++ b/lofty/src/ebml/tag/mod.rs @@ -23,6 +23,7 @@ use crate::tag::companion_tag::CompanionTag; use crate::tag::{Accessor, MergeTag, SplitTag, TagExt, TagType}; use std::borrow::Cow; +use std::collections::HashMap; use std::io::Write; use std::ops::Deref; @@ -405,28 +406,36 @@ impl From for MatroskaTag { } } -pub(crate) struct MatroskaTagRef<'a, I, S> +pub(crate) struct MatroskaTagRef<'a, I> where - I: Iterator>, - S: Iterator>> + 'a, + I: Iterator>, { - tags: I, + pub(crate) tags: I, } -impl<'a, I, S> From<&'a crate::tag::Tag> for MatroskaTagRef<'a, I, S> -where - I: Iterator>, - S: Iterator>>, -{ - fn from(_tag: &'a crate::tag::Tag) -> Self { - todo!() +pub(crate) fn simple_tags_for_tag(tag: &crate::tag::Tag) -> impl Iterator> { + let mut mapped_tags: HashMap>>> = + HashMap::new(); + for item in &tag.items { + if let Some((simple_tag, target_type)) = generic::simple_tag_for_item(Cow::Borrowed(item)) { + mapped_tags + .entry(target_type) + .or_default() + .push(Cow::Owned(simple_tag)) + } } + + mapped_tags + .into_iter() + .map(|(target_type, simple_tags)| TagRef { + targets: TargetDescriptor::Basic(target_type), + simple_tags: Box::new(simple_tags.into_iter()), + }) } -impl<'a, I, S> MatroskaTagRef<'a, I, S> +impl<'a, I> MatroskaTagRef<'a, I> where - I: Iterator>, - S: Iterator>>, + I: Iterator>, { pub(crate) fn write_to(&mut self, _file: &mut F, _write_options: WriteOptions) -> Result<()> where @@ -434,10 +443,14 @@ where LoftyError: From<::Error>, LoftyError: From<::Error>, { - todo!() + todo!("Writing matroska tags") } - fn dump_to(&self, _writer: &mut W, _write_options: WriteOptions) -> Result<()> { - todo!() + pub(crate) fn dump_to( + &self, + _writer: &mut W, + _write_options: WriteOptions, + ) -> Result<()> { + todo!("Dumping matroska tags") } } diff --git a/lofty/src/ebml/tag/tag.rs b/lofty/src/ebml/tag/tag.rs index 42c2c487..8ecf2f82 100644 --- a/lofty/src/ebml/tag/tag.rs +++ b/lofty/src/ebml/tag/tag.rs @@ -122,10 +122,7 @@ impl Tag<'static> { } } -pub(crate) struct TagRef<'a, I> -where - I: Iterator>>, -{ +pub(crate) struct TagRef<'a> { pub(crate) targets: TargetDescriptor<'a>, - pub(crate) simple_tags: &'a mut I, + pub(crate) simple_tags: Box>>>, } diff --git a/lofty/src/ebml/tag/write/elements/tags.rs b/lofty/src/ebml/tag/write/elements/tags.rs index 0e15575d..d960a38e 100644 --- a/lofty/src/ebml/tag/write/elements/tags.rs +++ b/lofty/src/ebml/tag/write/elements/tags.rs @@ -1,14 +1,10 @@ use crate::ebml::tag::write::{write_element, ElementWriterCtx, WriteableElement}; -use crate::ebml::{ElementId, SimpleTag, TagRef}; +use crate::ebml::{ElementId, TagRef}; use crate::io::FileLike; -use std::borrow::Cow; use std::io::Cursor; -impl<'a, I> WriteableElement for TagRef<'a, I> -where - I: Iterator>>, -{ +impl WriteableElement for TagRef<'_> { const ID: ElementId = ElementId(0x7373); fn write_element( diff --git a/lofty/src/tag/utils.rs b/lofty/src/tag/utils.rs index b03046d6..bd14d24a 100644 --- a/lofty/src/tag/utils.rs +++ b/lofty/src/tag/utils.rs @@ -99,9 +99,10 @@ pub(crate) fn dump_tag( } } .dump_to(writer, write_options), - TagType::Matroska => { - todo!("Dump EBML tags") - }, + TagType::Matroska => ebml::tag::MatroskaTagRef { + tags: ebml::tag::simple_tags_for_tag(tag), + } + .dump_to(writer, write_options), _ => Ok(()), } } diff --git a/lofty_attr/src/internal.rs b/lofty_attr/src/internal.rs index 123e3dab..f178c7e2 100644 --- a/lofty_attr/src/internal.rs +++ b/lofty_attr/src/internal.rs @@ -51,7 +51,12 @@ pub(crate) fn init_write_lookup( .write_to(file, write_options) }); - insert!(map, Matroska, { todo!("Generated Matroska tag writer") }); + insert!(map, Matroska, { + lofty::ebml::tag::MatroskaTagRef { + tags: lofty::ebml::tag::simple_tags_for_tag(tag), + } + .write_to(file, write_options) + }); insert!(map, Id3v1, { Into::>::into(tag).write_to(file, write_options)