Simplification of error types

The multi-level error types were a mistake.  Probably should have waited on the
cargo version bump, oh well.
This commit is contained in:
kyren 2017-06-25 04:25:48 -04:00
parent 8548fbd263
commit bf9bf849c2
6 changed files with 102 additions and 197 deletions

View File

@ -32,7 +32,7 @@ fn main() {
);
break;
}
Err(LuaError::SyntaxError(LuaSyntaxError::IncompleteStatement(_))) => {
Err(LuaError::IncompleteStatement(_)) => {
// continue reading input and append it to `line`
write!(stdout, ">> ").unwrap();
stdout.flush().unwrap();

View File

@ -38,9 +38,9 @@ impl<'lua> FromLua<'lua> for LuaTable<'lua> {
fn from_lua(value: LuaValue<'lua>, _: &'lua Lua) -> LuaResult<LuaTable<'lua>> {
match value {
LuaValue::Table(table) => Ok(table),
_ => Err(
LuaConversionError::FromLua("cannot convert lua value to table".to_owned()).into(),
),
_ => Err(LuaError::FromLuaConversionError(
"cannot convert lua value to table".to_owned(),
)),
}
}
}
@ -55,10 +55,9 @@ impl<'lua> FromLua<'lua> for LuaFunction<'lua> {
fn from_lua(value: LuaValue<'lua>, _: &'lua Lua) -> LuaResult<LuaFunction<'lua>> {
match value {
LuaValue::Function(table) => Ok(table),
_ => Err(
LuaConversionError::FromLua("cannot convert lua value to function".to_owned())
.into(),
),
_ => Err(LuaError::FromLuaConversionError(
"cannot convert lua value to function".to_owned(),
)),
}
}
}
@ -73,10 +72,9 @@ impl<'lua> FromLua<'lua> for LuaThread<'lua> {
fn from_lua(value: LuaValue<'lua>, _: &'lua Lua) -> LuaResult<LuaThread<'lua>> {
match value {
LuaValue::Thread(t) => Ok(t),
_ => Err(
LuaConversionError::FromLua("cannot convert lua value to thread".to_owned())
.into(),
),
_ => Err(LuaError::FromLuaConversionError(
"cannot convert lua value to thread".to_owned(),
)),
}
}
}
@ -91,10 +89,9 @@ impl<'lua> FromLua<'lua> for LuaUserData<'lua> {
fn from_lua(value: LuaValue<'lua>, _: &'lua Lua) -> LuaResult<LuaUserData<'lua>> {
match value {
LuaValue::UserData(ud) => Ok(ud),
_ => Err(
LuaConversionError::FromLua("cannot convert lua value to userdata".to_owned())
.into(),
),
_ => Err(LuaError::FromLuaConversionError(
"cannot convert lua value to userdata".to_owned(),
)),
}
}
}
@ -109,10 +106,9 @@ impl<'lua, T: LuaUserDataType + Copy> FromLua<'lua> for T {
fn from_lua(value: LuaValue<'lua>, _: &'lua Lua) -> LuaResult<T> {
match value {
LuaValue::UserData(ud) => Ok(*ud.borrow::<T>()?),
_ => Err(
LuaConversionError::FromLua("cannot convert lua value to userdata".to_owned())
.into(),
),
_ => Err(LuaError::FromLuaConversionError(
"cannot convert lua value to userdata".to_owned(),
)),
}
}
}
@ -162,11 +158,9 @@ impl<'lua> FromLua<'lua> for LightUserData {
fn from_lua(v: LuaValue, _: &'lua Lua) -> LuaResult<Self> {
match v {
LuaValue::LightUserData(ud) => Ok(ud),
_ => Err(
LuaConversionError::FromLua(
_ => Err(LuaError::FromLuaConversionError(
"cannot convert lua value to lightuserdata".to_owned(),
).into(),
),
)),
}
}
}
@ -246,10 +240,9 @@ impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Vec<T> {
if let LuaValue::Table(table) = value {
table.sequence_values().collect()
} else {
Err(
LuaConversionError::FromLua("cannot convert lua value to table for Vec".to_owned())
.into(),
)
Err(LuaError::FromLuaConversionError(
"cannot convert lua value to table for Vec".to_owned(),
))
}
}
}
@ -265,11 +258,9 @@ impl<'lua, K: Eq + Hash + FromLua<'lua>, V: FromLua<'lua>> FromLua<'lua> for Has
if let LuaValue::Table(table) = value {
table.pairs().collect()
} else {
Err(
LuaConversionError::FromLua(
Err(LuaError::FromLuaConversionError(
"cannot convert lua value to table for HashMap".to_owned(),
).into(),
)
))
}
}
}
@ -285,11 +276,9 @@ impl<'lua, K: Ord + FromLua<'lua>, V: FromLua<'lua>> FromLua<'lua> for BTreeMap<
if let LuaValue::Table(table) = value {
table.pairs().collect()
} else {
Err(
LuaConversionError::FromLua(
Err(LuaError::FromLuaConversionError(
"cannot convert lua value to table for BTreeMap".to_owned(),
).into(),
)
))
}
}
}

View File

@ -2,59 +2,35 @@ use std::fmt;
use std::sync::Arc;
use std::result::Result;
use std::error::Error;
use std::ffi::NulError;
use std::str::Utf8Error;
#[derive(Debug, Clone)]
pub enum LuaSyntaxError {
/// A generic syntax error
Syntax(String),
/// A syntax error due to an incomplete statement, useful for implementing a
/// Lua REPL.
IncompleteStatement(String),
}
#[derive(Debug, Clone)]
pub enum LuaConversionError {
/// A generic Rust -> Lua type conversion error.
ToLua(String),
/// A generic Lua -> Rust type conversion error.
FromLua(String),
/// A Lua string was not valid utf8 on conversion to a rust String.
Utf8Error(Utf8Error),
/// A rust String contained a NUL character, and thus was not convertible to
/// a Lua string.
NulError(NulError),
}
#[derive(Debug, Clone)]
pub enum LuaUserDataError {
/// A `LuaUserData` borrow failed because the expected type was not the
/// contained type.
TypeMismatch,
/// A `LuaUserData` immutable borrow failed because it was already borrowed
/// mutably.
BorrowError,
/// A `LuaUserData` mutable borrow failed because it was already borrowed.
BorrowMutError,
}
#[derive(Debug, Clone)]
pub enum LuaError {
/// Lua syntax error, aka LUA_ERRSYNTAX.
SyntaxError(LuaSyntaxError),
/// Lua runtime error, aka LUA_ERRRUN.
/// 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.
/// Lua error from inside an error handler, aka `LUA_ERRERR`.
ErrorError(String),
/// An error resulting from a Lua <-> Rust type conversion
ConversionError(LuaConversionError),
/// Insufficient Lua stack space.
/// A generic Rust -> Lua conversion error.
ToLuaConversionError(String),
/// A generic Lua -> Rust conversion error.
FromLuaConversionError(String),
/// Insufficient Lua stack space, only generated from rust when calling
/// `lua_checkstack`.
StackOverflow,
/// A `LuaThread` was resumed and the coroutine was no longer active.
CoroutineInactive,
/// A `LuaUserData` borrow of the internal value failed.
UserDataError(LuaUserDataError),
/// 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.
@ -69,42 +45,23 @@ 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(LuaSyntaxError::Syntax(ref msg)) => {
write!(fmt, "Lua syntax error: {}", msg)
&LuaError::SyntaxError(ref msg) => write!(fmt, "Lua syntax error: {}", msg),
&LuaError::IncompleteStatement(ref msg) => {
write!(fmt, "Lua syntax error (incomplete statement): {}", msg)
}
&LuaError::SyntaxError(LuaSyntaxError::IncompleteStatement(ref msg)) => {
write!(fmt, "Lua syntax error: {}", msg)
}
&LuaError::RuntimeError(ref msg) => write!(fmt, "Lua runtime error: {}", msg),
&LuaError::ErrorError(ref msg) => write!(fmt, "Lua error in error handler: {}", msg),
&LuaError::ConversionError(LuaConversionError::ToLua(ref msg)) => {
&LuaError::ToLuaConversionError(ref msg) => {
write!(fmt, "Error converting rust type to lua: {}", msg)
}
&LuaError::ConversionError(LuaConversionError::FromLua(ref msg)) => {
&LuaError::FromLuaConversionError(ref msg) => {
write!(fmt, "Error converting lua type to rust: {}", msg)
}
&LuaError::ConversionError(LuaConversionError::Utf8Error(ref msg)) => {
write!(fmt, "Error converting lua string to rust: {}", msg)
}
&LuaError::ConversionError(LuaConversionError::NulError(ref msg)) => {
write!(fmt, "Error converting rust string to lua: {}", msg)
}
&LuaError::StackOverflow => write!(fmt, "Lua out of stack space"),
&LuaError::CoroutineInactive => write!(fmt, "Cannot resume inactive coroutine"),
&LuaError::UserDataError(LuaUserDataError::TypeMismatch) => {
write!(fmt, "Userdata not expected type")
}
&LuaError::UserDataError(LuaUserDataError::BorrowError) => {
write!(fmt, "Userdata already mutably borrowed")
}
&LuaError::UserDataError(LuaUserDataError::BorrowMutError) => {
write!(fmt, "Userdata already borrowed")
}
&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)
}
@ -116,36 +73,17 @@ impl fmt::Display for LuaError {
impl Error for LuaError {
fn description(&self) -> &str {
match self {
&LuaError::SyntaxError(LuaSyntaxError::Syntax(_)) => "lua syntax error",
&LuaError::SyntaxError(LuaSyntaxError::IncompleteStatement(_)) => {
"lua incomplete statement"
}
&LuaError::SyntaxError(_) => "lua syntax error",
&LuaError::IncompleteStatement(_) => "lua incomplete statement",
&LuaError::RuntimeError(_) => "lua runtime error",
&LuaError::ErrorError(_) => "lua error handling error",
&LuaError::ConversionError(LuaConversionError::ToLua(_)) => "conversion error to lua",
&LuaError::ConversionError(LuaConversionError::FromLua(_)) => {
"conversion error from lua"
}
&LuaError::ConversionError(LuaConversionError::Utf8Error(_)) => {
"lua string utf8 conversion error"
}
&LuaError::ConversionError(LuaConversionError::NulError(_)) => "string contains null",
&LuaError::ToLuaConversionError(_) => "conversion error to lua",
&LuaError::FromLuaConversionError(_) => "conversion error from lua",
&LuaError::StackOverflow => "lua stack overflow",
&LuaError::CoroutineInactive => "lua coroutine inactive",
&LuaError::UserDataError(LuaUserDataError::TypeMismatch) => {
"lua userdata type mismatch"
}
&LuaError::UserDataError(LuaUserDataError::BorrowError) => {
"lua userdata already borrowed"
}
&LuaError::UserDataError(LuaUserDataError::BorrowMutError) => {
"lua userdata already mutably borrowed"
}
&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(),
}
@ -206,21 +144,3 @@ where
self.map_err(|e| e.to_lua_err())
}
}
impl From<LuaSyntaxError> for LuaError {
fn from(err: LuaSyntaxError) -> LuaError {
LuaError::SyntaxError(err)
}
}
impl From<LuaConversionError> for LuaError {
fn from(err: LuaConversionError) -> LuaError {
LuaError::ConversionError(err)
}
}
impl From<LuaUserDataError> for LuaError {
fn from(err: LuaUserDataError) -> LuaError {
LuaError::UserDataError(err)
}
}

View File

@ -203,7 +203,7 @@ impl<'lua> LuaString<'lua> {
assert_eq!(ffi::lua_type(lua.state, -1), ffi::LUA_TSTRING);
let s = CStr::from_ptr(ffi::lua_tostring(lua.state, -1))
.to_str()
.map_err(|e| LuaConversionError::Utf8Error(e))?;
.map_err(|e| LuaError::FromLuaConversionError(e.to_string()))?;
ffi::lua_pop(lua.state, 1);
Ok(s)
})
@ -851,11 +851,10 @@ impl<T: LuaUserDataType> LuaUserDataMethods<T> {
let userdata = userdata.borrow::<T>()?;
method(lua, &userdata, args)
} else {
Err(
LuaConversionError::FromLua(
"No userdata supplied as first argument to method".to_owned(),
).into(),
)
Err(LuaError::FromLuaConversionError(
"No userdata supplied as first argument to method"
.to_owned(),
))
})
}
@ -870,7 +869,7 @@ impl<T: LuaUserDataType> LuaUserDataMethods<T> {
method(lua, &mut userdata, args)
} else {
Err(
LuaConversionError::FromLua(
LuaError::FromLuaConversionError(
"No userdata supplied as first argument to method".to_owned(),
).into(),
)
@ -896,7 +895,7 @@ impl<'lua> LuaUserData<'lua> {
pub fn is<T: LuaUserDataType>(&self) -> LuaResult<bool> {
match self.inspect(|_: &RefCell<T>| Ok(())) {
Ok(_) => Ok(true),
Err(LuaError::UserDataError(LuaUserDataError::TypeMismatch)) => Ok(false),
Err(LuaError::UserDataTypeMismatch) => Ok(false),
Err(err) => Err(err),
}
}
@ -905,7 +904,7 @@ impl<'lua> LuaUserData<'lua> {
pub fn borrow<T: LuaUserDataType>(&self) -> LuaResult<Ref<T>> {
self.inspect(|cell| {
Ok(
cell.try_borrow().map_err(|_| LuaUserDataError::BorrowError)?,
cell.try_borrow().map_err(|_| LuaError::UserDataBorrowError)?,
)
})
}
@ -915,7 +914,7 @@ impl<'lua> LuaUserData<'lua> {
pub fn borrow_mut<T: LuaUserDataType>(&self) -> LuaResult<RefMut<T>> {
self.inspect(|cell| {
Ok(cell.try_borrow_mut().map_err(
|_| LuaUserDataError::BorrowError,
|_| LuaError::UserDataBorrowMutError,
)?)
})
}
@ -932,11 +931,12 @@ impl<'lua> LuaUserData<'lua> {
lua.push_ref(lua.state, &self.0);
let userdata = ffi::lua_touserdata(lua.state, -1);
assert!(!userdata.is_null());
if ffi::lua_getmetatable(lua.state, -1) == 0 {
return Err(LuaUserDataError::TypeMismatch.into());
}
assert!(!userdata.is_null());
assert!(
ffi::lua_getmetatable(lua.state, -1) != 0,
"LuaUserData missing metatable"
);
ffi::lua_rawgeti(
lua.state,
@ -944,7 +944,7 @@ impl<'lua> LuaUserData<'lua> {
lua.userdata_metatable::<T>()? as ffi::lua_Integer,
);
if ffi::lua_rawequal(lua.state, -1, -2) == 0 {
return Err(LuaUserDataError::TypeMismatch.into());
return Err(LuaError::UserDataTypeMismatch);
}
let res = func(&*(userdata as *const RefCell<T>));
@ -1062,7 +1062,7 @@ impl Lua {
self.state,
if let Some(name) = name {
let name = CString::new(name.to_owned()).map_err(|e| {
LuaConversionError::NulError(e)
LuaError::ToLuaConversionError(e.to_string())
})?;
ffi::luaL_loadbuffer(
self.state,
@ -1257,11 +1257,9 @@ impl Lua {
check_stack(self.state, 1)?;
self.push_value(self.state, v);
if ffi::lua_tostring(self.state, -1).is_null() {
Err(
LuaConversionError::FromLua(
Err(LuaError::FromLuaConversionError(
"cannot convert lua value to string".to_owned(),
).into(),
)
))
} else {
Ok(LuaString(self.pop_ref(self.state)))
}
@ -1284,11 +1282,9 @@ impl Lua {
let mut isint = 0;
let i = ffi::lua_tointegerx(self.state, -1, &mut isint);
if isint == 0 {
Err(
LuaConversionError::FromLua(
Err(LuaError::FromLuaConversionError(
"cannot convert lua value to integer".to_owned(),
).into(),
)
))
} else {
ffi::lua_pop(self.state, 1);
Ok(i)
@ -1312,11 +1308,9 @@ impl Lua {
let mut isnum = 0;
let n = ffi::lua_tonumberx(self.state, -1, &mut isnum);
if isnum == 0 {
Err(
LuaConversionError::FromLua(
Err(LuaError::FromLuaConversionError(
"cannot convert lua value to number".to_owned(),
).into(),
)
))
} else {
ffi::lua_pop(self.state, 1);
Ok(n)

View File

@ -68,7 +68,7 @@ fn test_eval() {
assert_eq!(lua.eval::<bool>("false == false").unwrap(), true);
assert_eq!(lua.eval::<i32>("return 1 + 2").unwrap(), 3);
match lua.eval::<()>("if true then") {
Err(LuaError::SyntaxError(LuaSyntaxError::IncompleteStatement(_))) => {}
Err(LuaError::IncompleteStatement(_)) => {}
r => panic!("expected IncompleteStatement, got {:?}", r),
}
}
@ -530,12 +530,12 @@ fn test_error() {
assert!(return_string_error.call::<_, LuaError>(()).is_ok());
match lua.eval::<()>("if youre happy and you know it syntax error") {
Err(LuaError::SyntaxError(LuaSyntaxError::Syntax(_))) => {}
Err(LuaError::SyntaxError(_)) => {}
Err(_) => panic!("error is not LuaSyntaxError::Syntax kind"),
_ => panic!("error not returned"),
}
match lua.eval::<()>("function i_will_finish_what_i()") {
Err(LuaError::SyntaxError(LuaSyntaxError::IncompleteStatement(_))) => {}
Err(LuaError::IncompleteStatement(_)) => {}
Err(_) => panic!("error is not LuaSyntaxError::IncompleteStatement kind"),
_ => panic!("error not returned"),
}

View File

@ -8,7 +8,7 @@ use std::os::raw::{c_char, c_int, c_void};
use std::panic::{catch_unwind, resume_unwind, UnwindSafe};
use ffi;
use error::{LuaResult, LuaSyntaxError, LuaUserDataError, LuaError};
use error::{LuaResult, LuaError};
macro_rules! cstr {
($s:expr) => (
@ -149,9 +149,9 @@ pub unsafe fn handle_error(state: *mut ffi::lua_State, err: c_int) -> LuaResult<
// This seems terrible, but as far as I can tell, this is exactly what the stock lua
// repl does.
if err_string.ends_with("<eof>") {
LuaSyntaxError::IncompleteStatement(err_string).into()
LuaError::IncompleteStatement(err_string)
} else {
LuaSyntaxError::Syntax(err_string).into()
LuaError::SyntaxError(err_string)
}
}
ffi::LUA_ERRERR => LuaError::ErrorError(err_string),
@ -343,17 +343,19 @@ pub struct WrappedPanic(pub Option<Box<Any + Send>>);
// Pushes a WrappedError::Error to the top of the stack
pub unsafe fn push_wrapped_error(state: *mut ffi::lua_State, err: LuaError) {
unsafe extern "C" fn error_tostring(state: *mut ffi::lua_State) -> c_int {
callback_error(state, || {
if !is_wrapped_error(state, -1) {
return Err(LuaUserDataError::TypeMismatch.into());
}
callback_error(state, || if is_wrapped_error(state, -1) {
let userdata = ffi::lua_touserdata(state, -1);
let error = &*(userdata as *const WrappedError);
push_string(state, &error.0.to_string());
ffi::lua_remove(state, -2);
Ok(1)
} else {
Err(LuaError::FromLuaConversionError(
"internal error: userdata mismatch in LuaError metamethod"
.to_owned(),
))
})
}