use std::str::FromStr;
use std::old_io::IoError;
use std::error::{Error, FromError};
use std::fmt;
use rustc_serialize::{Encoder, Encodable};
use utils::ForceEncodable;
#[derive(Debug, Copy, RustcEncodable)]
pub enum MpdErrorCode {
NotList,
Argument,
Password,
Permission,
UnknownCmd,
NoExist,
PlaylistMax,
System,
PlaylistLoad,
UpdateAlready,
PlayerSync,
Exist,
Other(usize)
}
impl FromStr for MpdErrorCode {
fn from_str(s: &str) -> Option<MpdErrorCode> {
match s {
"1" => Some(MpdErrorCode::NotList),
"2" => Some(MpdErrorCode::Argument),
"3" => Some(MpdErrorCode::Password),
"4" => Some(MpdErrorCode::Permission),
"5" => Some(MpdErrorCode::UnknownCmd),
"50" => Some(MpdErrorCode::NoExist),
"51" => Some(MpdErrorCode::PlaylistMax),
"52" => Some(MpdErrorCode::System),
"53" => Some(MpdErrorCode::PlaylistLoad),
"54" => Some(MpdErrorCode::UpdateAlready),
"55" => Some(MpdErrorCode::PlayerSync),
"56" => Some(MpdErrorCode::Exist),
_ => s.parse().map(|v| MpdErrorCode::Other(v))
}
}
}
#[derive(Debug, RustcEncodable)]
pub struct MpdServerError {
pub code: MpdErrorCode,
pub pos: usize,
pub command: String,
pub detail: String
}
#[derive(Debug)]
pub enum MpdError {
Mpd(MpdServerError),
Io(IoError),
}
impl Encodable for MpdError {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
match *self {
MpdError::Mpd(ref err) => err.encode(s),
MpdError::Io(ref err) => {
s.emit_struct("IoError", 3, |s| {
s.emit_struct_field("kind", 0, |s| format!("{:?}", err.kind).encode(s)).and_then(|_|
s.emit_struct_field("desc", 1, |s| err.desc.encode(s))).and_then(|_|
s.emit_struct_field("detail", 2, |s| err.detail.encode(s)))
})
}
}
}
}
impl Error for MpdServerError {
fn description(&self) -> &str {
match self.code {
MpdErrorCode::NotList => "not a list",
MpdErrorCode::Argument => "invalid argument",
MpdErrorCode::Password => "invalid password",
MpdErrorCode::Permission => "access denied",
MpdErrorCode::UnknownCmd => "unknown command",
MpdErrorCode::NoExist => "object not found",
MpdErrorCode::PlaylistMax => "playlist overflow",
MpdErrorCode::System => "system error",
MpdErrorCode::PlaylistLoad => "playlist load error",
MpdErrorCode::UpdateAlready => "database already updating",
MpdErrorCode::PlayerSync => "player sync error",
MpdErrorCode::Exist => "object already exists",
MpdErrorCode::Other(_) => "unknown error",
}
}
}
impl fmt::Display for MpdServerError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.description().fmt(fmt)
}
}
impl Error for MpdError {
fn description(&self) -> &str {
match *self {
MpdError::Io(ref err) => err.description(),
MpdError::Mpd(ref err) => err.description(),
}
}
fn cause(&self) -> Option<&Error> {
match *self {
MpdError::Io(ref err) => Some(err as &Error),
MpdError::Mpd(ref err) => Some(err as &Error),
}
}
}
impl fmt::Display for MpdError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
MpdError::Mpd(ref err) => err.fmt(fmt),
MpdError::Io(ref err) => err.fmt(fmt),
}
}
}
impl FromError<IoError> for MpdError {
fn from_error(err: IoError) -> MpdError {
MpdError::Io(err)
}
}
impl FromError<MpdServerError> for MpdError {
fn from_error(err: MpdServerError) -> MpdError {
MpdError::Mpd(err)
}
}
impl FromStr for MpdServerError {
fn from_str(s: &str) -> Option<MpdServerError> {
if s.starts_with("ACK [") {
let s = &s[5..];
if let (Some(atsign), Some(right_bracket)) = (s.find('@'), s.find(']')) {
if let (Some(code), Some(pos)) = (s[..atsign].parse(), s[atsign + 1..right_bracket].parse()) {
let s = &s[right_bracket + 1..];
if let (Some(left_brace), Some(right_brace)) = (s.find('{'), s.find('}')) {
let command = s[left_brace + 1..right_brace].to_string();
let detail = s[right_brace + 1..].trim().to_string();
return Some(MpdServerError {
code: code,
pos: pos,
command: command,
detail: detail
});
}
}
}
}
None
}
}
pub type MpdResult<T> = Result<T, MpdError>;
impl<T: Encodable> ForceEncodable for MpdResult<T> {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
match *self {
Ok(ref v) => v.encode(s),
Err(ref e) => e.encode(s)
}
}
}