Skip to content

Commit 84bbc45

Browse files
committed
EBML: add generic conversion to MatroskaTagRef
1 parent d99f902 commit 84bbc45

File tree

6 files changed

+58
-42
lines changed

6 files changed

+58
-42
lines changed

lofty/src/ebml/tag/generic.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use super::{Language, MatroskaTag, SimpleTag, TargetType, TOMBSTONE_SIMPLE_TAG};
66
use crate::tag::items::Lang;
77
use crate::tag::{ItemKey, ItemValue, Tag, TagItem, TagType};
88

9+
use std::borrow::Cow;
910
use std::collections::HashMap;
1011
use std::sync::LazyLock;
1112

@@ -203,7 +204,7 @@ fn split_simple_tags(
203204

204205
pub(super) fn merge_tag(tag: Tag, mut matroska_tag: MatroskaTag) -> MatroskaTag {
205206
for item in tag.items {
206-
let Some((simple_tag, target_type)) = simple_tag_for_item(item) else {
207+
let Some((simple_tag, target_type)) = simple_tag_for_item(Cow::Owned(item)) else {
207208
continue;
208209
};
209210

@@ -215,30 +216,33 @@ pub(super) fn merge_tag(tag: Tag, mut matroska_tag: MatroskaTag) -> MatroskaTag
215216
matroska_tag
216217
}
217218

218-
fn simple_tag_for_item(item: TagItem) -> Option<(SimpleTag<'static>, TargetType)> {
219+
pub(super) fn simple_tag_for_item(
220+
item: Cow<'_, TagItem>,
221+
) -> Option<(SimpleTag<'static>, TargetType)> {
222+
if !matches!(item.item_value, ItemValue::Text(_) | ItemValue::Locator(_)) {
223+
return None;
224+
}
225+
226+
let (target_type, simple_tag_name) = REVERSE_MAPPINGS.get(&item.item_key).copied()?;
227+
219228
let TagItem {
220229
mut lang,
221-
item_key,
222230
item_value: ItemValue::Text(text) | ItemValue::Locator(text),
223231
..
224-
} = item
232+
} = item.into_owned()
225233
else {
226234
return None;
227235
};
228236

229-
let Some((target_type, simple_tag_name)) = REVERSE_MAPPINGS.get(&item_key) else {
230-
return None;
231-
};
232-
233237
// Matroska uses "und" for unknown languages
234238
if lang == *b"XXX" {
235239
lang = *b"und";
236240
}
237241

238242
let lang_str = std::str::from_utf8(lang.as_slice()).unwrap_or("und");
239243

240-
let mut simple_tag = SimpleTag::new(simple_tag_name.to_string(), text);
244+
let mut simple_tag = SimpleTag::new((*simple_tag_name).to_string(), text);
241245
simple_tag.language = Language::Iso639_2(lang_str.to_string());
242246

243-
Some((simple_tag, *target_type))
247+
Some((simple_tag, target_type))
244248
}

lofty/src/ebml/tag/mod.rs

+30-17
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::tag::companion_tag::CompanionTag;
2323
use crate::tag::{Accessor, MergeTag, SplitTag, TagExt, TagType};
2424

2525
use std::borrow::Cow;
26+
use std::collections::HashMap;
2627
use std::io::Write;
2728
use std::ops::Deref;
2829

@@ -405,39 +406,51 @@ impl From<crate::tag::Tag> for MatroskaTag {
405406
}
406407
}
407408

408-
pub(crate) struct MatroskaTagRef<'a, I, S>
409+
pub(crate) struct MatroskaTagRef<'a, I>
409410
where
410-
I: Iterator<Item = TagRef<'a, S>>,
411-
S: Iterator<Item = Cow<'a, SimpleTag<'a>>> + 'a,
411+
I: Iterator<Item = TagRef<'a>>,
412412
{
413-
tags: I,
413+
pub(crate) tags: I,
414414
}
415415

416-
impl<'a, I, S> From<&'a crate::tag::Tag> for MatroskaTagRef<'a, I, S>
417-
where
418-
I: Iterator<Item = TagRef<'a, S>>,
419-
S: Iterator<Item = Cow<'a, SimpleTag<'a>>>,
420-
{
421-
fn from(_tag: &'a crate::tag::Tag) -> Self {
422-
todo!()
416+
pub(crate) fn simple_tags_for_tag(tag: &crate::tag::Tag) -> impl Iterator<Item = TagRef<'static>> {
417+
let mut mapped_tags: HashMap<TargetType, Vec<Cow<'static, SimpleTag<'static>>>> =
418+
HashMap::new();
419+
for item in &tag.items {
420+
if let Some((simple_tag, target_type)) = generic::simple_tag_for_item(Cow::Borrowed(item)) {
421+
mapped_tags
422+
.entry(target_type)
423+
.or_default()
424+
.push(Cow::Owned(simple_tag))
425+
}
423426
}
427+
428+
mapped_tags
429+
.into_iter()
430+
.map(|(target_type, simple_tags)| TagRef {
431+
targets: TargetDescriptor::Basic(target_type),
432+
simple_tags: Box::new(simple_tags.into_iter()),
433+
})
424434
}
425435

426-
impl<'a, I, S> MatroskaTagRef<'a, I, S>
436+
impl<'a, I> MatroskaTagRef<'a, I>
427437
where
428-
I: Iterator<Item = TagRef<'a, S>>,
429-
S: Iterator<Item = Cow<'a, SimpleTag<'a>>>,
438+
I: Iterator<Item = TagRef<'a>>,
430439
{
431440
pub(crate) fn write_to<F>(&mut self, _file: &mut F, _write_options: WriteOptions) -> Result<()>
432441
where
433442
F: FileLike,
434443
LoftyError: From<<F as Truncate>::Error>,
435444
LoftyError: From<<F as Length>::Error>,
436445
{
437-
todo!()
446+
todo!("Writing matroska tags")
438447
}
439448

440-
fn dump_to<W: Write>(&self, _writer: &mut W, _write_options: WriteOptions) -> Result<()> {
441-
todo!()
449+
pub(crate) fn dump_to<W: Write>(
450+
&self,
451+
_writer: &mut W,
452+
_write_options: WriteOptions,
453+
) -> Result<()> {
454+
todo!("Dumping matroska tags")
442455
}
443456
}

lofty/src/ebml/tag/tag.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,7 @@ impl Tag<'static> {
122122
}
123123
}
124124

125-
pub(crate) struct TagRef<'a, I>
126-
where
127-
I: Iterator<Item = Cow<'a, SimpleTag<'a>>>,
128-
{
125+
pub(crate) struct TagRef<'a> {
129126
pub(crate) targets: TargetDescriptor<'a>,
130-
pub(crate) simple_tags: &'a mut I,
127+
pub(crate) simple_tags: Box<dyn Iterator<Item = Cow<'a, SimpleTag<'a>>>>,
131128
}

lofty/src/ebml/tag/write/elements/tags.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
use crate::ebml::tag::write::{write_element, ElementWriterCtx, WriteableElement};
2-
use crate::ebml::{ElementId, SimpleTag, TagRef};
2+
use crate::ebml::{ElementId, TagRef};
33
use crate::io::FileLike;
44

5-
use std::borrow::Cow;
65
use std::io::Cursor;
76

8-
impl<'a, I> WriteableElement for TagRef<'a, I>
9-
where
10-
I: Iterator<Item = Cow<'a, SimpleTag<'a>>>,
11-
{
7+
impl WriteableElement for TagRef<'_> {
128
const ID: ElementId = ElementId(0x7373);
139

1410
fn write_element<F: FileLike>(

lofty/src/tag/utils.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,10 @@ pub(crate) fn dump_tag<W: Write>(
9999
}
100100
}
101101
.dump_to(writer, write_options),
102-
TagType::Matroska => {
103-
todo!("Dump EBML tags")
104-
},
102+
TagType::Matroska => ebml::tag::MatroskaTagRef {
103+
tags: ebml::tag::simple_tags_for_tag(tag),
104+
}
105+
.dump_to(writer, write_options),
105106
_ => Ok(()),
106107
}
107108
}

lofty_attr/src/internal.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,12 @@ pub(crate) fn init_write_lookup(
5151
.write_to(file, write_options)
5252
});
5353

54-
insert!(map, Matroska, { todo!("Generated Matroska tag writer") });
54+
insert!(map, Matroska, {
55+
lofty::ebml::tag::MatroskaTagRef {
56+
tags: lofty::ebml::tag::simple_tags_for_tag(tag),
57+
}
58+
.write_to(file, write_options)
59+
});
5560

5661
insert!(map, Id3v1, {
5762
Into::<lofty::id3::v1::tag::Id3v1TagRef<'_>>::into(tag).write_to(file, write_options)

0 commit comments

Comments
 (0)