diff --git a/examples/repl.rs b/examples/repl.rs index c5170af..1f8b99d 100644 --- a/examples/repl.rs +++ b/examples/repl.rs @@ -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(); diff --git a/src/conversion.rs b/src/conversion.rs index 426b817..15edf6b 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -38,9 +38,9 @@ impl<'lua> FromLua<'lua> for LuaTable<'lua> { fn from_lua(value: LuaValue<'lua>, _: &'lua Lua) -> LuaResult> { 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> { 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> { 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> { 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 { match value { LuaValue::UserData(ud) => Ok(*ud.borrow::()?), - _ => 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 { match v { LuaValue::LightUserData(ud) => Ok(ud), - _ => Err( - LuaConversionError::FromLua( - "cannot convert lua value to lightuserdata".to_owned(), - ).into(), - ), + _ => Err(LuaError::FromLuaConversionError( + "cannot convert lua value to lightuserdata".to_owned(), + )), } } } @@ -246,10 +240,9 @@ impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Vec { 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( - "cannot convert lua value to table for HashMap".to_owned(), - ).into(), - ) + Err(LuaError::FromLuaConversionError( + "cannot convert lua value to table for HashMap".to_owned(), + )) } } } @@ -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( - "cannot convert lua value to table for BTreeMap".to_owned(), - ).into(), - ) + Err(LuaError::FromLuaConversionError( + "cannot convert lua value to table for BTreeMap".to_owned(), + )) } } } diff --git a/src/error.rs b/src/error.rs index a1a651c..89289ea 100644 --- a/src/error.rs +++ b/src/error.rs @@ -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 = Result; 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 for LuaError { - fn from(err: LuaSyntaxError) -> LuaError { - LuaError::SyntaxError(err) - } -} - -impl From for LuaError { - fn from(err: LuaConversionError) -> LuaError { - LuaError::ConversionError(err) - } -} - -impl From for LuaError { - fn from(err: LuaUserDataError) -> LuaError { - LuaError::UserDataError(err) - } -} diff --git a/src/lua.rs b/src/lua.rs index e9b3737..538fe90 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -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 LuaUserDataMethods { let userdata = userdata.borrow::()?; 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 LuaUserDataMethods { 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(&self) -> LuaResult { match self.inspect(|_: &RefCell| 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(&self) -> LuaResult> { 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(&self) -> LuaResult> { 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::()? 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)); @@ -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( - "cannot convert lua value to string".to_owned(), - ).into(), - ) + Err(LuaError::FromLuaConversionError( + "cannot convert lua value to string".to_owned(), + )) } 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( - "cannot convert lua value to integer".to_owned(), - ).into(), - ) + Err(LuaError::FromLuaConversionError( + "cannot convert lua value to integer".to_owned(), + )) } 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( - "cannot convert lua value to number".to_owned(), - ).into(), - ) + Err(LuaError::FromLuaConversionError( + "cannot convert lua value to number".to_owned(), + )) } else { ffi::lua_pop(self.state, 1); Ok(n) diff --git a/src/tests.rs b/src/tests.rs index f33c722..ff0dda1 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -68,7 +68,7 @@ fn test_eval() { assert_eq!(lua.eval::("false == false").unwrap(), true); assert_eq!(lua.eval::("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"), } diff --git a/src/util.rs b/src/util.rs index 99dbb08..a02f574 100644 --- a/src/util.rs +++ b/src/util.rs @@ -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("") { - 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>); // 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(), + )) }) }