use crate::error::Result;
use crate::id3::v2::{FrameFlags, FrameHeader, FrameId};
use crate::util::text::{TextDecodeOptions, TextEncoding, decode_text};
use crate::config::WriteOptions;
use std::borrow::Cow;
use std::hash::Hash;
use std::io::Read;
#[derive(Clone, Debug, Eq)]
pub struct UrlLinkFrame<'a> {
pub(crate) header: FrameHeader<'a>,
pub(crate) content: Cow<'a, str>,
}
impl PartialEq for UrlLinkFrame<'_> {
fn eq(&self, other: &Self) -> bool {
self.header.id == other.header.id
}
}
impl Hash for UrlLinkFrame<'_> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.header.id.hash(state);
}
}
impl<'a> UrlLinkFrame<'a> {
pub fn new(id: FrameId<'a>, content: impl Into<Cow<'a, str>>) -> Self {
UrlLinkFrame {
header: FrameHeader::new(id, FrameFlags::default()),
content: content.into(),
}
}
pub fn id(&self) -> &FrameId<'_> {
&self.header.id
}
pub fn flags(&self) -> FrameFlags {
self.header.flags
}
pub fn set_flags(&mut self, flags: FrameFlags) {
self.header.flags = flags;
}
pub fn parse<R>(
reader: &mut R,
id: FrameId<'a>,
frame_flags: FrameFlags,
) -> Result<Option<Self>>
where
R: Read,
{
let url = decode_text(
reader,
TextDecodeOptions::new()
.encoding(TextEncoding::Latin1)
.terminated(true),
)?;
if url.bytes_read == 0 {
return Ok(None);
}
let header = FrameHeader::new(id, frame_flags);
Ok(Some(UrlLinkFrame {
header,
content: Cow::Owned(url.content),
}))
}
pub fn as_bytes(&self, write_options: WriteOptions) -> Result<Vec<u8>> {
TextEncoding::Latin1
.encode(&self.content, false, write_options.lossy_text_encoding)
.map_err(Into::into)
}
pub fn url(&self) -> &str {
&self.content
}
pub fn set_url(&mut self, url: impl Into<Cow<'a, str>>) -> bool {
let url = url.into();
if TextEncoding::verify_latin1(&url) {
self.content = url;
return true;
}
false
}
}
impl UrlLinkFrame<'static> {
pub(crate) fn downgrade(&self) -> UrlLinkFrame<'_> {
UrlLinkFrame {
header: self.header.downgrade(),
content: Cow::Borrowed(&self.content),
}
}
}