diff --git a/lofty/src/tag/item.rs b/lofty/src/tag/item.rs index 11a86ff1..56e2df88 100644 --- a/lofty/src/tag/item.rs +++ b/lofty/src/tag/item.rs @@ -828,18 +828,36 @@ impl TagItem { /// Set a language for the [`TagItem`] /// + /// The default language is empty. + /// /// NOTE: This will not be reflected in most tag formats. pub fn set_lang(&mut 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`] /// + /// The default description is empty. + /// /// NOTE: This will not be reflected in most tag formats. pub fn set_description(&mut self, description: String) { 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`] pub fn key(&self) -> &ItemKey { &self.item_key diff --git a/lofty/src/tag/mod.rs b/lofty/src/tag/mod.rs index ef99b66e..1ac58693 100644 --- a/lofty/src/tag/mod.rs +++ b/lofty/src/tag/mod.rs @@ -405,11 +405,52 @@ impl Tag { /// Removes all items with the specified [`ItemKey`], and returns them pub fn take(&mut self, key: &ItemKey) -> impl Iterator + '_ { + 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::>(); + /// 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 + '_ { // TODO: drain_filter - let mut split_idx = 0_usize; + let mut split_idx = 0; 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); split_idx += 1; }