diff --git a/Cargo.toml b/Cargo.toml index 3f8fad4..dfe78c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ builtin-lua = ["gcc"] [dependencies] libc = { version = "0.2" } +failure = { version = "0.1.1" } [build-dependencies] gcc = { version = "0.3.52", optional = true } diff --git a/src/error.rs b/src/error.rs index 28f95eb..9145dbe 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,8 +1,9 @@ use std::fmt; use std::sync::Arc; -use std::error::Error as StdError; use std::result::Result as StdResult; +use failure; + /// Error type returned by `rlua` methods. #[derive(Debug, Clone)] pub enum Error { @@ -107,7 +108,7 @@ pub enum Error { /// Returning `Err(ExternalError(...))` from a Rust callback will raise the error as a Lua /// error. The Rust code that originally invoked the Lua code then receives a `CallbackError`, /// from which the original error (and a stack traceback) can be recovered. - ExternalError(Arc), + ExternalError(Arc), } /// A specialized `Result` type used by `rlua`'s API. @@ -160,37 +161,28 @@ impl fmt::Display for Error { } } -impl StdError for Error { - fn description(&self) -> &str { +impl failure::Fail for Error { + fn cause(&self) -> Option<&failure::Fail> { match *self { - Error::SyntaxError { .. } => "syntax error", - Error::RuntimeError(_) => "runtime error", - Error::GarbageCollectorError(_) => "garbage collector error", - Error::RecursiveCallbackError => "callback called recursively", - Error::ExpiredUserData => "access of userdata which has already been garbage collected", - Error::ToLuaConversionError { .. } => "conversion error to lua", - Error::FromLuaConversionError { .. } => "conversion error from lua", - Error::CoroutineInactive => "attempt to resume inactive coroutine", - Error::UserDataTypeMismatch => "userdata type mismatch", - Error::UserDataBorrowError => "userdata already mutably borrowed", - Error::UserDataBorrowMutError => "userdata already borrowed", - Error::CallbackError { .. } => "callback error", - Error::ExternalError(ref err) => err.description(), + Error::CallbackError { ref cause, .. } => Some(cause.as_ref()), + // Error::cause simply returns the contained Fail type, which we are already displaying + // and returning the backtrace for, no need to repeat it as the cause. + Error::ExternalError(ref err) => err.cause().cause(), + _ => None, } } - fn cause(&self) -> Option<&StdError> { + fn backtrace(&self) -> Option<&failure::Backtrace> { match *self { - Error::CallbackError { ref cause, .. } => Some(cause.as_ref()), - Error::ExternalError(ref err) => err.cause(), + Error::ExternalError(ref err) => Some(err.backtrace()), _ => None, } } } impl Error { - pub fn external(err: T) -> Error { - Error::ExternalError(Arc::new(err)) + pub fn external>(err: T) -> Error { + Error::ExternalError(Arc::new(err.into())) } } @@ -200,34 +192,10 @@ pub trait ExternalError { impl ExternalError for E where - E: Into>, + E: Into, { fn to_lua_err(self) -> Error { - struct WrapError(Box); - - impl fmt::Debug for WrapError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } - } - - impl fmt::Display for WrapError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } - } - - impl StdError for WrapError { - fn description(&self) -> &str { - self.0.description() - } - - fn cause(&self) -> Option<&StdError> { - self.0.cause() - } - } - - Error::external(WrapError(self.into())) + Error::external(self) } } diff --git a/src/lib.rs b/src/lib.rs index 4f69581..caf3659 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,8 @@ // warnings at all. #![doc(test(attr(deny(warnings))))] +#[cfg_attr(test, macro_use)] +extern crate failure; extern crate libc; mod ffi; diff --git a/src/tests.rs b/src/tests.rs index e73bbd8..f24748f 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -318,7 +318,7 @@ fn test_result_conversions() { let err = lua.create_function(|_, ()| { Ok(Err::( - "only through failure can we succeed".to_lua_err(), + format_err!("only through failure can we succeed").to_lua_err(), )) }).unwrap(); let ok = lua.create_function(|_, ()| Ok(Ok::<_, Error>("!".to_owned()))) diff --git a/src/userdata.rs b/src/userdata.rs index 08ea583..98ec717 100644 --- a/src/userdata.rs +++ b/src/userdata.rs @@ -477,7 +477,7 @@ mod tests { if index.to_str()? == "inner" { Ok(data.0) } else { - Err("no such custom index".to_lua_err()) + Err(format_err!("no such custom index").to_lua_err()) } }); }