use std::fmt;
use std::str::FromStr;
use super::AudioRepetition;
use crate::arguments::{ArgumentScanner, Arguments, ExpectArg, FromArgs};
use crate::parse::{StringVariant, UnrecognizedVariant};
#[derive(Copy, Clone, Default, PartialEq, Eq)]
enum AudioContinuation {
Restart = 0,
#[default]
Continue,
}
impl StringVariant for AudioContinuation {
const VARIANTS: &[&str] = &["0", "1"];
}
impl FromStr for AudioContinuation {
type Err = UnrecognizedVariant<Self>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"0" => Ok(Self::Restart),
"1" => Ok(Self::Continue),
_ => Err(Self::Err::new(s)),
}
}
}
impl fmt::Display for AudioContinuation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Restart => 0,
Self::Continue => 1,
}
.fmt(f)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Music<S = String> {
pub fname: S,
pub volume: u8,
pub repeat: AudioRepetition,
pub continual: bool,
pub class: Option<S>,
pub url: Option<S>,
}
impl<S: Default> Default for Music<S> {
fn default() -> Self {
Self {
fname: S::default(),
volume: 100,
repeat: AudioRepetition::default(),
continual: false,
class: None,
url: None,
}
}
}
impl<S: AsRef<str>> Music<S> {
pub fn is_off(&self) -> bool {
self.fname.as_ref().eq_ignore_ascii_case("off") && self.url.is_none()
}
}
impl<S> Music<S> {
pub fn map_text<T, F>(self, mut f: F) -> Music<T>
where
F: FnMut(S) -> T,
{
Music {
fname: f(self.fname),
volume: self.volume,
repeat: self.repeat,
continual: self.continual,
class: self.class.map(&mut f),
url: self.url.map(f),
}
}
}
impl_into_owned!(Music);
impl<S: AsRef<str>> Music<S> {
pub fn borrow_text(&self) -> Music<&str> {
Music {
fname: self.fname.as_ref(),
volume: self.volume,
repeat: self.repeat,
continual: self.continual,
class: self.class.as_ref().map(AsRef::as_ref),
url: self.url.as_ref().map(AsRef::as_ref),
}
}
}
impl_partial_eq!(Music);
impl<'a> Music<&'a str> {
pub fn from_msp(source: &'a str) -> crate::Result<Self> {
Arguments::parse(source)?.into_scan().parse()
}
}
impl<'a, S: AsRef<str>> FromArgs<'a, S> for Music<S> {
fn from_args<A: ArgumentScanner<'a, Decoded = S>>(mut scanner: A) -> crate::Result<Self> {
let fname = scanner.get_next_or("fname")?.expect_some("fname")?;
let volume = scanner.get_next_or("v")?.expect_number()?.unwrap_or(100);
let repeat = scanner
.get_next_or("l")?
.expect_number()?
.unwrap_or_default();
let continual =
scanner.get_next_or("c")?.expect_variant()? == Some(AudioContinuation::Continue);
let class = scanner.get_next_or("t")?;
let url = scanner.get_next_or("u")?;
scanner.expect_end()?;
Ok(Self {
fname,
volume,
repeat,
continual,
class,
url,
})
}
}
impl_from_str!(Music);
impl<S: AsRef<str>> fmt::Display for Music<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Music {
fname,
volume,
repeat,
continual,
class,
url,
} = self.borrow_text();
crate::display::ElementFormatter {
name: "MUSIC",
arguments: &[
&fname,
&(volume, 100),
&(repeat, AudioRepetition::default()),
&(u8::from(continual), 0),
&class,
&url,
],
keywords: &[],
}
.fmt(f)
}
}