use std::fmt; use std::sync::Arc; use std::result::Result; use std::error::Error; #[derive(Debug, Clone)] pub enum LuaError { /// Lua syntax error, aka `LUA_ERRSYNTAX` that is NOT an incomplete /// statement. SyntaxError(String), /// Lua syntax error that IS an incomplete statement. Useful for /// implementing a REPL. IncompleteStatement(String), /// Lua runtime error, aka `LUA_ERRRUN`. RuntimeError(String), /// Lua error from inside an error handler, aka `LUA_ERRERR`. ErrorError(String), /// A generic Rust -> Lua conversion error. ToLuaConversionError(String), /// A generic Lua -> Rust conversion error. FromLuaConversionError(String), /// A `LuaThread` was resumed and the coroutine was no longer active. CoroutineInactive, /// A `LuaUserData` is not the expected type in a borrow. UserDataTypeMismatch, /// A `LuaUserData` immutable borrow failed because it is already borrowed /// mutably. UserDataBorrowError, /// A `LuaUserData` mutable borrow failed because it is already borrowed. UserDataBorrowMutError, /// Lua error that originated as a LuaError in a callback. The first field /// is the lua error as a string, the second field is the Arc holding the /// original LuaError. CallbackError(String, Arc), /// Any custom external error type, mostly useful for returning external /// error types from callbacks. ExternalError(Arc), } pub type LuaResult = Result; impl fmt::Display for LuaError { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { match self { &LuaError::SyntaxError(ref msg) => write!(fmt, "Lua syntax error: {}", msg), &LuaError::IncompleteStatement(ref msg) => { write!(fmt, "Lua syntax error (incomplete statement): {}", msg) } &LuaError::RuntimeError(ref msg) => write!(fmt, "Lua runtime error: {}", msg), &LuaError::ErrorError(ref msg) => write!(fmt, "Lua error in error handler: {}", msg), &LuaError::ToLuaConversionError(ref msg) => { write!(fmt, "Error converting rust type to lua: {}", msg) } &LuaError::FromLuaConversionError(ref msg) => { write!(fmt, "Error converting lua type to rust: {}", msg) } &LuaError::CoroutineInactive => write!(fmt, "Cannot resume inactive coroutine"), &LuaError::UserDataTypeMismatch => write!(fmt, "Userdata not expected type"), &LuaError::UserDataBorrowError => write!(fmt, "Userdata already mutably borrowed"), &LuaError::UserDataBorrowMutError => write!(fmt, "Userdata already borrowed"), &LuaError::CallbackError(ref msg, _) => { write!(fmt, "Error during lua callback: {}", msg) } &LuaError::ExternalError(ref err) => err.fmt(fmt), } } } impl Error for LuaError { fn description(&self) -> &str { match self { &LuaError::SyntaxError(_) => "lua syntax error", &LuaError::IncompleteStatement(_) => "lua incomplete statement", &LuaError::RuntimeError(_) => "lua runtime error", &LuaError::ErrorError(_) => "lua error handling error", &LuaError::ToLuaConversionError(_) => "conversion error to lua", &LuaError::FromLuaConversionError(_) => "conversion error from lua", &LuaError::CoroutineInactive => "lua coroutine inactive", &LuaError::UserDataTypeMismatch => "lua userdata type mismatch", &LuaError::UserDataBorrowError => "lua userdata already mutably borrowed", &LuaError::UserDataBorrowMutError => "lua userdata already borrowed", &LuaError::CallbackError(_, _) => "lua callback error", &LuaError::ExternalError(ref err) => err.description(), } } fn cause(&self) -> Option<&Error> { match self { &LuaError::CallbackError(_, ref cause) => Some(cause.as_ref()), &LuaError::ExternalError(ref err) => err.cause(), _ => None, } } } impl LuaError { pub fn external(err: T) -> LuaError { LuaError::ExternalError(Arc::new(err)) } } pub trait LuaExternalError { fn to_lua_err(self) -> LuaError; } impl LuaExternalError for E where E: Into>, { fn to_lua_err(self) -> LuaError { #[derive(Debug)] struct WrapError(Box); impl fmt::Display for WrapError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) } } impl Error for WrapError { fn description(&self) -> &str { self.0.description() } } LuaError::external(WrapError(self.into())) } } pub trait LuaExternalResult { fn to_lua_err(self) -> LuaResult; } impl LuaExternalResult for Result where E: LuaExternalError, { fn to_lua_err(self) -> LuaResult { self.map_err(|e| e.to_lua_err()) } }