From ea77a8cf9c012fcd877d842fec85b0b5a442952c Mon Sep 17 00:00:00 2001 From: "Jakob L. Kreuze" Date: Sun, 7 Aug 2022 20:47:54 -0400 Subject: Import modifications to `mpd` crate --- vendored/mpd/src/status.rs | 310 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 vendored/mpd/src/status.rs (limited to 'vendored/mpd/src/status.rs') diff --git a/vendored/mpd/src/status.rs b/vendored/mpd/src/status.rs new file mode 100644 index 0000000..08c7278 --- /dev/null +++ b/vendored/mpd/src/status.rs @@ -0,0 +1,310 @@ +//! The module defines MPD status data structures + +use crate::convert::FromIter; +use crate::error::{Error, ParseError}; +use crate::song::{Id, QueuePlace}; + +use rustc_serialize::{Encodable, Encoder}; +use std::fmt; +use std::str::FromStr; +use std::time::Duration; + +/// MPD status +#[derive(Debug, PartialEq, Clone, Default)] +pub struct Status { + /// volume (0-100, or -1 if volume is unavailable (e.g. for HTTPD output type) + pub volume: i8, + /// repeat mode + pub repeat: bool, + /// random mode + pub random: bool, + /// single mode + pub single: bool, + /// consume mode + pub consume: bool, + /// queue version number + pub queue_version: u32, + /// queue length + pub queue_len: u32, + /// playback state + pub state: State, + /// currently playing song place in the queue + pub song: Option, + /// next song to play place in the queue + pub nextsong: Option, + /// time current song played, and total song duration (in seconds resolution) + pub time: Option<(Duration, Duration)>, + /// elapsed play time current song played (in milliseconds resolution) + pub elapsed: Option, + /// current song duration + pub duration: Option, + /// current song bitrate, kbps + pub bitrate: Option, + /// crossfade timeout, seconds + pub crossfade: Option, + /// mixramp threshold, dB + pub mixrampdb: f32, + /// mixramp duration, seconds + pub mixrampdelay: Option, + /// current audio playback format + pub audio: Option, + /// current DB updating job number (if DB updating is in progress) + pub updating_db: Option, + /// last player error (if happened, can be reset with `clearerror()` method) + pub error: Option, + /// replay gain mode + pub replaygain: Option, +} + +impl Encodable for Status { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { + e.emit_struct("Status", 21, |e| { + e.emit_struct_field("volume", 0, |e| self.volume.encode(e))?; + e.emit_struct_field("repeat", 1, |e| self.repeat.encode(e))?; + e.emit_struct_field("random", 2, |e| self.random.encode(e))?; + e.emit_struct_field("single", 3, |e| self.single.encode(e))?; + e.emit_struct_field("consume", 4, |e| self.consume.encode(e))?; + e.emit_struct_field("queue_version", 5, |e| self.queue_version.encode(e))?; + e.emit_struct_field("queue_len", 6, |e| self.queue_len.encode(e))?; + e.emit_struct_field("state", 7, |e| self.state.encode(e))?; + e.emit_struct_field("song", 8, |e| self.song.encode(e))?; + e.emit_struct_field("nextsong", 9, |e| self.nextsong.encode(e))?; + e.emit_struct_field("time", 10, |e| { + e.emit_option(|e| match self.time { + Some(p) => { + e.emit_option_some(|e| { + e.emit_tuple(2, |e| { + e.emit_tuple_arg(0, |e| p.0.as_secs().encode(e))?; + e.emit_tuple_arg(1, |e| p.1.as_secs().encode(e))?; + Ok(()) + }) + }) + } + None => e.emit_option_none(), + }) + })?; + e.emit_struct_field("elapsed", 11, |e| { + e.emit_option(|e| match self.elapsed { + Some(d) => e.emit_option_some(|e| d.as_secs().encode(e)), + None => e.emit_option_none(), + }) + + })?; + e.emit_struct_field("duration", 12, |e| { + e.emit_option(|e| match self.duration { + Some(d) => e.emit_option_some(|e| d.as_secs().encode(e)), + None => e.emit_option_none(), + }) + })?; + e.emit_struct_field("bitrate", 13, |e| self.bitrate.encode(e))?; + e.emit_struct_field("crossfade", 14, |e| { + e.emit_option(|e| match self.crossfade { + Some(d) => e.emit_option_some(|e| d.as_secs().encode(e)), + None => e.emit_option_none(), + }) + })?; + e.emit_struct_field("mixrampdb", 15, |e| self.mixrampdb.encode(e))?; + e.emit_struct_field("mixrampdelay", 16, |e| { + e.emit_option(|e| match self.mixrampdelay { + Some(d) => e.emit_option_some(|e| d.as_secs().encode(e)), + None => e.emit_option_none(), + }) + })?; + e.emit_struct_field("audio", 17, |e| self.audio.encode(e))?; + e.emit_struct_field("updating_db", 18, |e| self.updating_db.encode(e))?; + e.emit_struct_field("error", 19, |e| self.error.encode(e))?; + e.emit_struct_field("replaygain", 20, |e| self.replaygain.encode(e))?; + Ok(()) + }) + + } +} + +impl FromIter for Status { + fn from_iter>>(iter: I) -> Result { + let mut result = Status::default(); + + for res in iter { + let line = res?; + match &*line.0 { + "volume" => result.volume = line.1.parse()?, + + "repeat" => result.repeat = &*line.1 == "1", + "random" => result.random = &*line.1 == "1", + "single" => result.single = &*line.1 == "1", + "consume" => result.consume = &*line.1 == "1", + + "playlist" => result.queue_version = line.1.parse()?, + "playlistlength" => result.queue_len = line.1.parse()?, + "state" => result.state = line.1.parse()?, + "songid" => { + match result.song { + None => { + result.song = Some(QueuePlace { + id: Id(line.1.parse()?), + pos: 0, + prio: 0, + }) + } + Some(ref mut place) => place.id = Id(line.1.parse()?), + } + } + "song" => { + match result.song { + None => { + result.song = Some(QueuePlace { + pos: line.1.parse()?, + id: Id(0), + prio: 0, + }) + } + Some(ref mut place) => place.pos = line.1.parse()?, + } + } + "nextsongid" => { + match result.nextsong { + None => { + result.nextsong = Some(QueuePlace { + id: Id(line.1.parse()?), + pos: 0, + prio: 0, + }) + } + Some(ref mut place) => place.id = Id(line.1.parse()?), + } + } + "nextsong" => { + match result.nextsong { + None => { + result.nextsong = Some(QueuePlace { + pos: line.1.parse()?, + id: Id(0), + prio: 0, + }) + } + Some(ref mut place) => place.pos = line.1.parse()?, + } + } + "time" => { + let mut splits = line.1.splitn(2, ':').map(|v| v.parse().map_err(ParseError::BadInteger).map(Duration::from_secs)); + result.time = match (splits.next(), splits.next()) { + (Some(Ok(a)), Some(Ok(b))) => Ok(Some((a, b))), + (Some(Err(e)), _) | + (_, Some(Err(e))) => Err(e), + _ => Ok(None), + }?; + } + // TODO" => float errors don't work on stable + "elapsed" => result.elapsed = line.1.parse::().ok().map(|v| Duration::from_millis((v * 1000.0) as u64)), + "duration" => result.duration = line.1.parse::().ok().map(|v| Duration::from_millis((v * 1000.0) as u64)), + "bitrate" => result.bitrate = Some(line.1.parse()?), + "xfade" => result.crossfade = Some(Duration::from_secs(line.1.parse()?)), + // "mixrampdb" => 0.0, //get_field!(map, "mixrampdb"), + // "mixrampdelay" => None, //get_field!(map, opt "mixrampdelay").map(|v: f64| Duration::milliseconds((v * 1000.0) as i64)), + "audio" => result.audio = Some(line.1.parse()?), + "updating_db" => result.updating_db = Some(line.1.parse()?), + "error" => result.error = Some(line.1.to_owned()), + "replay_gain_mode" => result.replaygain = Some(line.1.parse()?), + _ => (), + } + } + + Ok(result) + } +} + +/// Audio playback format +#[derive(Debug, Copy, Clone, PartialEq, RustcEncodable)] +pub struct AudioFormat { + /// sample rate, kbps + pub rate: u32, + /// sample resolution in bits, can be 0 for floating point resolution + pub bits: u8, + /// number of channels + pub chans: u8, +} + +impl FromStr for AudioFormat { + type Err = ParseError; + fn from_str(s: &str) -> Result { + let mut it = s.split(':'); + Ok(AudioFormat { + rate: it.next().ok_or(ParseError::NoRate).and_then(|v| v.parse().map_err(ParseError::BadRate))?, + bits: it.next().ok_or(ParseError::NoBits) + .and_then(|v| if &*v == "f" { + Ok(0) + } else { + v.parse().map_err(ParseError::BadBits) + })?, + chans: it.next().ok_or(ParseError::NoChans).and_then(|v| v.parse().map_err(ParseError::BadChans))?, + }) + } +} + +/// Playback state +#[derive(Debug, Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)] +pub enum State { + /// player stopped + Stop, + /// player is playing + Play, + /// player paused + Pause, +} + +impl Default for State { + fn default() -> State { + State::Stop + } +} + +impl FromStr for State { + type Err = ParseError; + fn from_str(s: &str) -> Result { + match s { + "stop" => Ok(State::Stop), + "play" => Ok(State::Play), + "pause" => Ok(State::Pause), + _ => Err(ParseError::BadState(s.to_owned())), + } + } +} + +/// Replay gain mode +#[derive(Debug, Clone, Copy, PartialEq, RustcEncodable, RustcDecodable)] +pub enum ReplayGain { + /// off + Off, + /// track + Track, + /// album + Album, + /// auto + Auto, +} + +impl FromStr for ReplayGain { + type Err = ParseError; + fn from_str(s: &str) -> Result { + use self::ReplayGain::*; + match s { + "off" => Ok(Off), + "track" => Ok(Track), + "album" => Ok(Album), + "auto" => Ok(Auto), + _ => Err(ParseError::BadValue(s.to_owned())), + } + } +} + +impl fmt::Display for ReplayGain { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::ReplayGain::*; + f.write_str(match *self { + Off => "off", + Track => "track", + Album => "album", + Auto => "auto", + }) + } +} -- cgit v1.3