use std::borrow::Cow;
macro_rules! accessor_trait {
($([$($name:tt)+] < $($ty:ty),+ >),+ $(,)?) => {
pub trait Accessor {
$(
accessor_trait! { @GETTER [$($name)+] $($ty),+ }
accessor_trait! { @SETTER [$($name)+] $($ty),+ }
accessor_trait! { @REMOVE [$($name)+] $($ty),+ }
)+
}
};
(@GETTER [$($name:tt)+] $ty:ty $(, $_ty:tt)?) => {
accessor_trait! { @GET_METHOD [$($name)+] Option<$ty> }
};
(@SETTER [$($name:tt)+] $_ty:ty, $owned_ty:tt) => {
accessor_trait! { @SETTER [$($name)+] $owned_ty }
};
(@SETTER [$($name:tt)+] $ty:ty) => {
accessor_trait! { @SET_METHOD [$($name)+] $ty }
};
(@REMOVE [$($name:tt)+] $_ty:ty, $owned_ty:tt) => {
accessor_trait! { @REMOVE [$($name)+] $owned_ty }
};
(@REMOVE [$($name:tt)+] $ty:ty) => {
accessor_trait! { @REMOVE_METHOD [$($name)+], $ty }
};
(@GET_METHOD [$name:tt $($other:tt)*] Option<$ret_ty:ty>) => {
paste::paste! {
#[doc = "Returns the " $name $(" " $other)*]
#[doc = "assert_eq!(tag." $name $(_ $other)* "(), None);"]
fn [<
$name $(_ $other)*
>] (&self) -> Option<$ret_ty> { None }
}
};
(@SET_METHOD [$name:tt $($other:tt)*] $owned_ty:ty) => {
paste::paste! {
#[doc = "Sets the " $name $(" " $other)*]
#[doc = "tag.set_" $name $(_ $other)* "(value);"]
#[doc = "assert_eq!(tag." $name $(_ $other)* "(), Some(value));"]
fn [<
set_ $name $(_ $other)*
>] (&mut self , _value: $owned_ty) {}
}
};
(@REMOVE_METHOD [$name:tt $($other:tt)*], $ty:ty) => {
paste::paste! {
#[doc = "Removes the " $name $(" " $other)*]
#[doc = "tag.set_" $name $(_ $other)* "(value);"]
#[doc = "assert_eq!(tag." $name $(_ $other)* "(), Some(value));"]
#[doc = "tag.remove_" $name $(_ $other)* "();"]
#[doc = "assert_eq!(tag." $name $(_ $other)* "(), None);"]
fn [<
remove_ $name $(_ $other)*
>] (&mut self) {}
}
};
}
accessor_trait! {
[artist]<Cow<'_, str>, String>, [title ]<Cow<'_, str>, String>,
[album ]<Cow<'_, str>, String>, [genre ]<Cow<'_, str>, String>,
[track ]<u32>, [track total]<u32>,
[disk ]<u32>, [disk total ]<u32>,
[year ]<u32>, [comment ]<Cow<'_, str>, String>,
}
use crate::tag::Tag;
use std::fs::File;
use std::path::Path;
pub trait TagExt: Accessor + Into<Tag> + Sized {
type Err;
type RefKey<'a>
where
Self: 'a;
fn len(&self) -> usize;
fn contains<'a>(&'a self, key: Self::RefKey<'a>) -> bool;
fn is_empty(&self) -> bool;
fn save_to_path<P: AsRef<Path>>(&self, path: P) -> std::result::Result<(), Self::Err>;
fn save_to(&self, file: &mut File) -> std::result::Result<(), Self::Err>;
#[allow(clippy::missing_errors_doc)]
fn dump_to<W: std::io::Write>(&self, writer: &mut W) -> std::result::Result<(), Self::Err>;
fn remove_from_path<P: AsRef<Path>>(&self, path: P) -> std::result::Result<(), Self::Err>;
fn remove_from(&self, file: &mut File) -> std::result::Result<(), Self::Err>;
fn clear(&mut self);
}
pub trait SplitAndMergeTag {
fn split_tag(&mut self) -> Tag;
fn merge_tag(&mut self, tag: Tag);
}
pub(crate) trait SeekStreamLen: std::io::Seek {
fn stream_len(&mut self) -> crate::error::Result<u64> {
use std::io::SeekFrom;
let current_pos = self.stream_position()?;
let len = self.seek(SeekFrom::End(0))?;
self.seek(SeekFrom::Start(current_pos))?;
Ok(len)
}
}
impl<T> SeekStreamLen for T where T: std::io::Seek {}