use std::collections::BTreeMap;
use educe::Educe;
use unicase::UniCase;
use crate::{IDTag, LyricsError};
#[derive(Debug, Clone, Educe)]
#[educe(Default(new), PartialEq, Eq, PartialOrd, Ord)]
pub struct Metadata {
tags: BTreeMap<UniCase<String>, IDTag>,
}
impl Metadata {
#[inline]
fn key<L: AsRef<str>>(label: L) -> UniCase<String> {
UniCase::new(label.as_ref().trim().to_string())
}
#[inline]
pub fn insert(&mut self, tag: IDTag) -> Option<IDTag> {
self.tags.insert(Self::key(tag.label()), tag)
}
#[inline]
pub fn set<L: Into<String>, T: Into<String>>(
&mut self,
label: L,
text: T,
) -> Result<Option<IDTag>, LyricsError> {
Ok(self.insert(IDTag::from_string(label, text)?))
}
#[inline]
pub fn get<L: AsRef<str>>(&self, label: L) -> Option<&IDTag> {
self.tags.get(&Self::key(label))
}
#[inline]
pub fn get_text<L: AsRef<str>>(&self, label: L) -> Option<&str> {
self.get(label).map(IDTag::text)
}
#[inline]
pub fn remove<L: AsRef<str>>(&mut self, label: L) -> Option<IDTag> {
self.tags.remove(&Self::key(label))
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = &IDTag> {
self.tags.values()
}
#[inline]
pub fn len(&self) -> usize {
self.tags.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.tags.is_empty()
}
}
impl Metadata {
#[inline]
pub fn title(&self) -> Option<&str> {
self.get_text("ti")
}
#[inline]
pub fn set_title<T: Into<String>>(&mut self, title: T) -> Result<Option<IDTag>, LyricsError> {
self.set("ti", title)
}
#[inline]
pub fn artist(&self) -> Option<&str> {
self.get_text("ar")
}
#[inline]
pub fn set_artist<T: Into<String>>(&mut self, artist: T) -> Result<Option<IDTag>, LyricsError> {
self.set("ar", artist)
}
#[inline]
pub fn album(&self) -> Option<&str> {
self.get_text("al")
}
#[inline]
pub fn set_album<T: Into<String>>(&mut self, album: T) -> Result<Option<IDTag>, LyricsError> {
self.set("al", album)
}
#[inline]
pub fn author(&self) -> Option<&str> {
self.get_text("au")
}
#[inline]
pub fn set_author<T: Into<String>>(&mut self, author: T) -> Result<Option<IDTag>, LyricsError> {
self.set("au", author)
}
#[inline]
pub fn length(&self) -> Option<&str> {
self.get_text("length")
}
#[inline]
pub fn set_length<T: Into<String>>(&mut self, length: T) -> Result<Option<IDTag>, LyricsError> {
self.set("length", length)
}
}