use core::convert::TryFrom;
use core::fmt;
use std::borrow::Cow;
use derive_more::{AsMut, AsRef, Deref, DerefMut};
use crate::Error;
#[derive(
AsMut, AsRef, Deref, DerefMut, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default,
)]
pub struct Codecs<'a> {
list: Vec<Cow<'a, str>>,
}
impl<'a> Codecs<'a> {
#[inline]
#[must_use]
pub const fn new() -> Self { Self { list: Vec::new() } }
#[must_use]
pub fn into_owned(self) -> Codecs<'static> {
Codecs {
list: self
.list
.into_iter()
.map(|v| Cow::Owned(v.into_owned()))
.collect(),
}
}
}
impl<'a, T> From<Vec<T>> for Codecs<'a>
where
T: Into<Cow<'a, str>>,
{
fn from(value: Vec<T>) -> Self {
Self {
list: value.into_iter().map(Into::into).collect(),
}
}
}
macro_rules! implement_from {
($($size:expr),*) => {
$(
#[allow(clippy::reversed_empty_ranges)]
impl<'a> From<[&'a str; $size]> for Codecs<'a> {
fn from(value: [&'a str; $size]) -> Self {
Self {
list: {
let mut result = Vec::with_capacity($size);
for i in 0..$size {
result.push(Cow::Borrowed(value[i]))
}
result
},
}
}
}
#[allow(clippy::reversed_empty_ranges)]
impl<'a> From<&[&'a str; $size]> for Codecs<'a> {
fn from(value: &[&'a str; $size]) -> Self {
Self {
list: {
let mut result = Vec::with_capacity($size);
for i in 0..$size {
result.push(Cow::Borrowed(value[i]))
}
result
},
}
}
}
)*
};
}
implement_from!(
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20
);
impl<'a> fmt::Display for Codecs<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(codec) = self.list.first() {
write!(f, "{}", codec)?;
for codec in self.list.iter().skip(1) {
write!(f, ",{}", codec)?;
}
}
Ok(())
}
}
impl<'a> TryFrom<&'a str> for Codecs<'a> {
type Error = Error;
fn try_from(input: &'a str) -> Result<Self, Self::Error> {
Ok(Self {
list: input.split(',').map(|s| s.into()).collect(),
})
}
}
impl<'a> TryFrom<Cow<'a, str>> for Codecs<'a> {
type Error = Error;
fn try_from(input: Cow<'a, str>) -> Result<Self, Self::Error> {
match input {
Cow::Owned(o) => Ok(Codecs::try_from(o.as_str())?.into_owned()),
Cow::Borrowed(b) => Self::try_from(b),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_from() {
assert_eq!(Codecs::from(Vec::<&str>::new()), Codecs::new());
}
#[test]
fn test_display() {
assert_eq!(
Codecs::from(["mp4a.40.2", "avc1.4d401e"]).to_string(),
"mp4a.40.2,avc1.4d401e".to_string()
);
}
#[test]
fn test_parser() {
assert_eq!(
Codecs::try_from("mp4a.40.2,avc1.4d401e").unwrap(),
Codecs::from(["mp4a.40.2", "avc1.4d401e"])
);
}
}