use super::{utilities::fmt_path, Error, VectorError};
use serde::Deserialize;
use std::{fs::read_to_string, num::NonZero};
use toml::from_str;
#[cfg_attr(any(debug_assertions, feature = "debug"), derive(Debug))]
#[cfg_attr(
any(debug_assertions, feature = "traits"),
derive(PartialEq, Eq, PartialOrd, Ord),
derive(Hash)
)]
#[derive(Deserialize)]
pub struct SerDePlaylist {
pub(crate) song: Vec<SerDeTrack>,
pub(crate) time: Option<isize>,
pub(crate) vary: Option<bool>,
}
#[cfg_attr(any(debug_assertions, feature = "debug"), derive(Debug))]
#[cfg_attr(
any(debug_assertions, feature = "traits"),
derive(PartialEq, Eq, PartialOrd, Ord),
derive(Hash)
)]
#[derive(Deserialize)]
#[derive(Clone)]
pub struct SerDeTrack {
pub(crate) file: Box<str>,
pub(crate) time: Option<isize>,
}
impl SerDePlaylist {
#[inline(always)]
pub fn song_get(&self) -> &Vec<SerDeTrack> {
&self.song
}
#[inline(always)]
pub fn song_get_mut(&mut self) -> &mut Vec<SerDeTrack> {
&mut self.song
}
#[inline(always)]
pub fn song_take(self) -> Vec<SerDeTrack> {
self.song
}
#[inline(always)]
pub fn time_set(&mut self, value: isize) {
self.time = NonZero::<isize>::new(value).map(NonZero::get)
}
#[inline(always)]
pub fn time_unset(&mut self) {
self.time_set(0)
}
#[inline(always)]
pub fn vary_set(&mut self, state: bool) {
self.vary = state.then_some(true);
}
#[inline(always)]
pub fn vary_unset(&mut self) {
self.vary_set(false)
}
#[inline]
pub fn try_from_paths(
iterator: impl IntoIterator<Item = String>,
) -> Result<Vec<Self>, Error> {
let mut rest = Vec::with_capacity(8);
let mut outliers = SerDePlaylist {
song: Vec::with_capacity(8),
time: None,
vary: None,
};
for path in iterator {
match read_to_string(fmt_path(&path)?) {
Ok(contents) => rest.push(Self::try_from_contents(contents)?),
Err(_) => outliers
.song
.push(SerDeTrack {
file: path.into_boxed_str(),
time: None,
}),
}
}
rest.push(outliers);
Ok(rest.into_iter()
.filter(|list| !list.is_empty())
.collect())
}
#[inline]
pub fn flatten(lists: Vec<Self>) -> Result<Self, Error> {
let repeats = lists
.iter()
.min_by_key(|Self { time, .. }| time.unwrap_or_default())
.ok_or(VectorError::Empty)?
.time
.unwrap_or_default();
let shuffle = lists
.iter()
.find_map(|Self { vary, .. }| match vary {
Some(false) | None => Some(false),
Some(true) => None,
})
.ok_or(VectorError::Empty)?;
let tracks: Vec<SerDeTrack> = lists
.into_iter()
.flat_map(|list| list.song)
.collect();
Ok(Self {
vary: Some(shuffle),
song: tracks,
time: Some(repeats),
})
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.song
.is_empty()
}
#[inline(always)]
fn try_from_contents(contents: String) -> Result<Self, Error> {
from_str(&contents).map_err(Error::from)
}
}
impl SerDeTrack {
#[inline(always)]
pub fn set_time(&mut self, value: isize) {
self.time = Some(value)
}
#[inline(always)]
pub fn unset_time(&mut self) {
self.time = None
}
}