use std::error;
use std::ffi::{CStr, NulError};
use std::fmt;
use std::io;
use std::ptr;
use std::str::Utf8Error;
use libc::c_char;
use ffi::fwifc_get_last_error;
use file::Channel;
#[derive(Debug)]
pub enum Error {
BadArg(String),
EndOfFile(String),
InvalidChannel(u32),
Io(io::Error),
MissingChannel(Channel),
MissingIndex(String),
NoCalibrationTableForChannel(Channel),
NotImplemented(String),
Nul(NulError),
Runtime(String),
NeedSingleReferencePeak(usize),
Utf8(Utf8Error),
UnknownCode(i32),
UnknownException(String),
UnsupportedFormat(String),
}
impl Error {
pub fn from_i32(code: i32) -> Error {
match code {
-1 => Error::EndOfFile(last_error().to_string()),
0 => panic!("Refusing to create an error with code zero"),
1 => Error::BadArg(last_error().to_string()),
2 => Error::UnsupportedFormat(last_error().to_string()),
3 => Error::MissingIndex(last_error().to_string()),
4 => Error::UnknownException(last_error().to_string()),
5 => Error::NotImplemented(last_error().to_string()),
6 => Error::Runtime(last_error().to_string()),
_ => Error::UnknownCode(code),
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::BadArg(_) => "bad argument",
Error::EndOfFile(_) => "end of file",
Error::Io(ref err) => err.description(),
Error::InvalidChannel(_) => "invalid channel",
Error::MissingChannel(_) => "missing channel",
Error::MissingIndex(_) => "missing index",
Error::NeedSingleReferencePeak(_) => "zero or more than one reference peaks",
Error::NoCalibrationTableForChannel(_) => "no calibration table for channel",
Error::NotImplemented(_) => "not implemented",
Error::Nul(ref err) => err.description(),
Error::Runtime(_) => "runtime error",
Error::Utf8(ref err) => err.description(),
Error::UnknownCode(_) => "unknown code",
Error::UnknownException(_) => "unknown exception",
Error::UnsupportedFormat(_) => "unsupported format",
}
}
fn cause(&self) -> Option<&error::Error> {
match *self {
Error::Io(ref err) => Some(err),
Error::Nul(ref err) => Some(err),
Error::Utf8(ref err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::BadArg(ref msg) => write!(f, "Bad argument: {}", msg),
Error::EndOfFile(ref msg) => write!(f, "End of file: {}", msg),
Error::Io(ref err) => write!(f, "IO error: {}", err),
Error::InvalidChannel(u8) => write!(f, "Invalid channel: {}", u8),
Error::MissingChannel(ref channel) => write!(f, "Missing channel: {}", channel),
Error::MissingIndex(ref msg) => write!(f, "Missing index: {}", msg),
Error::NeedSingleReferencePeak(n) => write!(f, "Wanted one reference peak, got {}", n),
Error::NoCalibrationTableForChannel(channel) => {
write!(f, "No calibration table for channel: {}", channel)
}
Error::NotImplemented(ref msg) => write!(f, "Not implemented: {}", msg),
Error::Nul(ref err) => write!(f, "Nul error: {}", err),
Error::Runtime(ref msg) => write!(f, "Runtime error: {}", msg),
Error::Utf8(ref err) => write!(f, "Utf8 error: {}", err),
Error::UnknownCode(code) => write!(f, "Unknown code: {}", code),
Error::UnknownException(ref msg) => write!(f, "Unknown exception: {}", msg),
Error::UnsupportedFormat(ref msg) => write!(f, "Unsupported format: {}", msg),
}
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Error {
Error::Io(err)
}
}
impl From<NulError> for Error {
fn from(err: NulError) -> Error {
Error::Nul(err)
}
}
impl From<Utf8Error> for Error {
fn from(err: Utf8Error) -> Error {
Error::Utf8(err)
}
}
pub fn last_error() -> &'static str {
unsafe {
let mut message: *const c_char = ptr::null_mut();
let result = fwifc_get_last_error(&mut message);
if result != 0 {
panic!("Non-zero return code from `fwifc_get_last_error`: {}",
result);
}
CStr::from_ptr(message).to_str().unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_error_expected() {
let message = last_error();
assert_eq!("(no error)", message);
}
}