use crate::mp4::AtomIdent;
use crate::picture::Picture;
use std::fmt::{Debug, Formatter};
#[derive(PartialEq, Clone)]
pub(super) enum AtomDataStorage {
Single(AtomData),
Multiple(Vec<AtomData>),
}
impl AtomDataStorage {
pub(super) fn first_mut(&mut self) -> &mut AtomData {
match self {
AtomDataStorage::Single(val) => val,
AtomDataStorage::Multiple(data) => data.first_mut().expect("not empty"),
}
}
}
impl Debug for AtomDataStorage {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self {
AtomDataStorage::Single(v) => write!(f, "{:?}", v),
AtomDataStorage::Multiple(v) => f.debug_list().entries(v.iter()).finish(),
}
}
}
impl<'a> IntoIterator for &'a AtomDataStorage {
type Item = &'a AtomData;
type IntoIter = AtomDataStorageIter<'a>;
fn into_iter(self) -> Self::IntoIter {
let cap = match self {
AtomDataStorage::Single(_) => 0,
AtomDataStorage::Multiple(v) => v.len(),
};
Self::IntoIter {
storage: Some(self),
idx: 0,
cap,
}
}
}
pub(super) struct AtomDataStorageIter<'a> {
storage: Option<&'a AtomDataStorage>,
idx: usize,
cap: usize,
}
impl<'a> Iterator for AtomDataStorageIter<'a> {
type Item = &'a AtomData;
fn next(&mut self) -> Option<Self::Item> {
match self.storage {
Some(AtomDataStorage::Single(data)) => {
self.storage = None;
Some(data)
},
Some(AtomDataStorage::Multiple(data)) => {
if self.idx == self.cap {
self.storage = None;
return None;
}
let ret = &data[self.idx];
self.idx += 1;
Some(ret)
},
_ => None,
}
}
}
#[derive(PartialEq, Clone)]
pub struct Atom<'a> {
pub(crate) ident: AtomIdent<'a>,
pub(super) data: AtomDataStorage,
}
impl<'a> Atom<'a> {
#[must_use]
pub const fn new(ident: AtomIdent<'a>, data: AtomData) -> Self {
Self {
ident,
data: AtomDataStorage::Single(data),
}
}
pub fn from_collection(ident: AtomIdent<'a>, mut data: Vec<AtomData>) -> Option<Self> {
let data = match data.len() {
0 => return None,
1 => AtomDataStorage::Single(data.swap_remove(0)),
_ => AtomDataStorage::Multiple(data),
};
Some(Self { ident, data })
}
pub fn ident(&self) -> &AtomIdent<'_> {
&self.ident
}
pub fn data(&self) -> impl Iterator<Item = &AtomData> {
(&self.data).into_iter()
}
pub fn push_data(&mut self, data: AtomData) {
match self.data {
AtomDataStorage::Single(ref s) => {
self.data = AtomDataStorage::Multiple(vec![s.clone(), data])
},
AtomDataStorage::Multiple(ref mut m) => m.push(data),
}
}
pub(crate) fn unknown_implicit(ident: AtomIdent<'_>, data: Vec<u8>) -> Self {
Self {
ident: ident.into_owned(),
data: AtomDataStorage::Single(AtomData::Unknown { code: 0, data }),
}
}
pub(crate) fn text(ident: AtomIdent<'_>, data: String) -> Self {
Self {
ident: ident.into_owned(),
data: AtomDataStorage::Single(AtomData::UTF8(data)),
}
}
pub(crate) fn into_owned(self) -> Atom<'static> {
let Self { ident, data } = self;
Atom {
ident: ident.into_owned(),
data,
}
}
}
impl Debug for Atom<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Atom")
.field("ident", &self.ident)
.field("data", &self.data)
.finish()
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum AtomData {
UTF8(String),
UTF16(String),
Picture(Picture),
SignedInteger(i32),
UnsignedInteger(u32),
Bool(bool),
Unknown {
code: u32,
data: Vec<u8>,
},
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AdvisoryRating {
Inoffensive,
Explicit,
Clean,
}
impl AdvisoryRating {
pub fn as_u8(&self) -> u8 {
match self {
AdvisoryRating::Inoffensive => 0,
AdvisoryRating::Explicit => 1,
AdvisoryRating::Clean => 2,
}
}
}
impl TryFrom<u8> for AdvisoryRating {
type Error = u8;
fn try_from(input: u8) -> Result<Self, Self::Error> {
match input {
0 => Ok(Self::Inoffensive),
1 | 4 => Ok(Self::Explicit),
2 => Ok(Self::Clean),
value => Err(value),
}
}
}