Add Tag::take_filter()

This commit is contained in:
Uwe Klotz 2024-07-03 02:34:22 +02:00 committed by Alex
parent fcb5446922
commit a523db78d1
2 changed files with 61 additions and 2 deletions

View file

@ -828,18 +828,36 @@ impl TagItem {
/// Set a language for the [`TagItem`] /// Set a language for the [`TagItem`]
/// ///
/// The default language is empty.
///
/// NOTE: This will not be reflected in most tag formats. /// NOTE: This will not be reflected in most tag formats.
pub fn set_lang(&mut self, lang: Lang) { pub fn set_lang(&mut self, lang: Lang) {
self.lang = lang; self.lang = lang;
} }
/// Returns a reference to the language of the [`TagItem`]
///
/// NOTE: This will not be reflected in most tag formats.
pub fn lang(&self) -> &Lang {
&self.lang
}
/// Set a description for the [`TagItem`] /// Set a description for the [`TagItem`]
/// ///
/// The default description is empty.
///
/// NOTE: This will not be reflected in most tag formats. /// NOTE: This will not be reflected in most tag formats.
pub fn set_description(&mut self, description: String) { pub fn set_description(&mut self, description: String) {
self.description = description; self.description = description;
} }
/// Returns a reference to the description of the [`TagItem`]
///
/// NOTE: This will not be reflected in most tag formats.
pub fn description(&self) -> &str {
&self.description
}
/// Returns a reference to the [`ItemKey`] /// Returns a reference to the [`ItemKey`]
pub fn key(&self) -> &ItemKey { pub fn key(&self) -> &ItemKey {
&self.item_key &self.item_key

View file

@ -405,11 +405,52 @@ impl Tag {
/// Removes all items with the specified [`ItemKey`], and returns them /// Removes all items with the specified [`ItemKey`], and returns them
pub fn take(&mut self, key: &ItemKey) -> impl Iterator<Item = TagItem> + '_ { pub fn take(&mut self, key: &ItemKey) -> impl Iterator<Item = TagItem> + '_ {
self.take_filter(key, |_| true)
}
/// Removes selected items with the specified [`ItemKey`], and returns them
///
/// Only takes items for which `filter()` returns `true`. All other items are retained.
///
/// # Examples
///
/// ```
/// use lofty::tag::{ItemKey, ItemValue, Tag, TagItem, TagType};
///
/// let mut tag = Tag::new(TagType::Id3v2);
/// tag.push(TagItem::new(
/// ItemKey::Comment,
/// ItemValue::Text("comment without description".to_owned()),
/// ));
/// let mut item = TagItem::new(
/// ItemKey::Comment,
/// ItemValue::Text("comment with description".to_owned()),
/// );
/// item.set_description("description".to_owned());
/// tag.push(item);
/// assert_eq!(tag.get_strings(&ItemKey::Comment).count(), 2);
///
/// // Extract all comment items with an empty description.
/// let comments = tag
/// .take_filter(&ItemKey::Comment, |item| item.description().is_empty())
/// .filter_map(|item| item.into_value().into_string())
/// .collect::<Vec<_>>();
/// assert_eq!(comments, vec!["comment without description".to_owned()]);
///
/// // The comments that didn't match the filter are still present.
/// assert_eq!(tag.get_strings(&ItemKey::Comment).count(), 1);
/// ```
pub fn take_filter(
&mut self,
key: &ItemKey,
mut filter: impl FnMut(&TagItem) -> bool,
) -> impl Iterator<Item = TagItem> + '_ {
// TODO: drain_filter // TODO: drain_filter
let mut split_idx = 0_usize; let mut split_idx = 0;
for read_idx in 0..self.items.len() { for read_idx in 0..self.items.len() {
if self.items[read_idx].key() == key { let item = &self.items[read_idx];
if item.key() == key && filter(item) {
self.items.swap(split_idx, read_idx); self.items.swap(split_idx, read_idx);
split_idx += 1; split_idx += 1;
} }