use crate::config::WriteOptions;
use crate::error::{FileEncodingError, TagEncodingError, UnsupportedTagError};
use crate::io::{FileLike, VerifiedFile};
use crate::tag::{Accessor, Tag, TagSupport, TagType};
use std::path::Path;
#[expect(private_bounds, reason = "`TagWriteExt` is internal")]
pub trait TagExt: Accessor + TagWriteExt + Into<Tag> + Sized + private::Sealed {
type RefKey<'a>
where
Self: 'a;
#[doc(hidden)]
fn tag_type(&self) -> TagType;
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,
write_options: WriteOptions,
) -> std::result::Result<(), FileEncodingError> {
TagExt::save_to(
self,
&mut std::fs::OpenOptions::new()
.read(true)
.write(true)
.open(path)?,
write_options,
)
}
fn save_to<F>(
&self,
file: &mut F,
write_options: WriteOptions,
) -> std::result::Result<(), FileEncodingError>
where
F: FileLike,
{
let file = VerifiedFile::new(file, write_options.parse_options)?;
let support = file.format().tag_support(self.tag_type());
if support == TagSupport::Unsupported || (!support.is_writable() && !self.is_empty()) {
return Err(FileEncodingError::from(UnsupportedTagError).with_format(file.format()));
}
let format = file.format();
<Self as TagWriteExt>::save_to(self, file, write_options).map_err(|e| e.with_format(format))
}
#[allow(clippy::missing_errors_doc)]
fn dump_to<W: std::io::Write>(
&self,
writer: &mut W,
write_options: WriteOptions,
) -> std::result::Result<(), TagEncodingError>;
fn remove_from_path<P: AsRef<Path>>(
&self,
path: P,
write_options: WriteOptions,
) -> std::result::Result<(), FileEncodingError> {
self.tag_type().remove_from_path(path, write_options)
}
fn remove_from<F>(
&self,
file: &mut F,
write_options: WriteOptions,
) -> std::result::Result<(), FileEncodingError>
where
F: FileLike,
{
self.tag_type().remove_from(file, write_options)
}
fn clear(&mut self);
}
pub(crate) trait TagWriteExt {
fn save_to<F>(
&self,
file: VerifiedFile<'_, F>,
write_options: WriteOptions,
) -> std::result::Result<(), FileEncodingError>
where
F: FileLike;
}
mod private {
use crate::ape::ApeTag;
use crate::id3::v1::Id3v1Tag;
use crate::id3::v2::Id3v2Tag;
use crate::iff::aiff::AiffTextChunks;
use crate::iff::wav::RiffInfoList;
use crate::mp4::Ilst;
use crate::ogg::tag::VorbisComments;
use crate::tag::Tag;
pub trait Sealed {}
impl Sealed for AiffTextChunks {}
impl Sealed for ApeTag {}
impl Sealed for Id3v1Tag {}
impl Sealed for Id3v2Tag {}
impl Sealed for Ilst {}
impl Sealed for RiffInfoList {}
impl Sealed for Tag {}
impl Sealed for VorbisComments {}
}