use std::fmt;
use std::sync::Arc;
use std::result::Result;
use std::error::Error;
#[derive(Debug, Clone)]
pub enum LuaError {
SyntaxError(String),
IncompleteStatement(String),
RuntimeError(String),
ErrorError(String),
ToLuaConversionError(String),
FromLuaConversionError(String),
CoroutineInactive,
UserDataTypeMismatch,
UserDataBorrowError,
UserDataBorrowMutError,
CallbackError(String, Arc<LuaError>),
ExternalError(Arc<Error + Send + Sync>),
}
pub type LuaResult<T> = Result<T, LuaError>;
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<T: 'static + Error + Send + Sync>(err: T) -> LuaError {
LuaError::ExternalError(Arc::new(err))
}
}
pub trait LuaExternalError {
fn to_lua_err(self) -> LuaError;
}
impl<E> LuaExternalError for E
where
E: Into<Box<Error + Send + Sync>>,
{
fn to_lua_err(self) -> LuaError {
#[derive(Debug)]
struct WrapError(Box<Error + Send + Sync>);
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<T> {
fn to_lua_err(self) -> LuaResult<T>;
}
impl<T, E> LuaExternalResult<T> for Result<T, E>
where
E: LuaExternalError,
{
fn to_lua_err(self) -> LuaResult<T> {
self.map_err(|e| e.to_lua_err())
}
}