summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/conversion.rs6
-rw-r--r--src/error.rs5
-rw-r--r--src/lib.rs1
-rw-r--r--src/lua.rs201
-rw-r--r--src/tests.rs90
-rw-r--r--src/util.rs143
6 files changed, 265 insertions, 181 deletions
diff --git a/src/conversion.rs b/src/conversion.rs
index 15edf6b..7a65597 100644
--- a/src/conversion.rs
+++ b/src/conversion.rs
@@ -98,7 +98,7 @@ impl<'lua> FromLua<'lua> for LuaUserData<'lua> {
impl<'lua, T: LuaUserDataType> ToLua<'lua> for T {
fn to_lua(self, lua: &'lua Lua) -> LuaResult<LuaValue<'lua>> {
- lua.create_userdata(self).map(LuaValue::UserData)
+ Ok(LuaValue::UserData(lua.create_userdata(self)))
}
}
@@ -167,7 +167,7 @@ impl<'lua> FromLua<'lua> for LightUserData {
impl<'lua> ToLua<'lua> for String {
fn to_lua(self, lua: &'lua Lua) -> LuaResult<LuaValue<'lua>> {
- Ok(LuaValue::String(lua.create_string(&self)?))
+ Ok(LuaValue::String(lua.create_string(&self)))
}
}
@@ -179,7 +179,7 @@ impl<'lua> FromLua<'lua> for String {
impl<'lua, 'a> ToLua<'lua> for &'a str {
fn to_lua(self, lua: &'lua Lua) -> LuaResult<LuaValue<'lua>> {
- Ok(LuaValue::String(lua.create_string(self)?))
+ Ok(LuaValue::String(lua.create_string(self)))
}
}
diff --git a/src/error.rs b/src/error.rs
index 89289ea..e7822c6 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -19,9 +19,6 @@ pub enum LuaError {
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` is not the expected type in a borrow.
@@ -57,7 +54,6 @@ impl fmt::Display for LuaError {
&LuaError::FromLuaConversionError(ref msg) => {
write!(fmt, "Error converting lua type to rust: {}", msg)
}
- &LuaError::StackOverflow => write!(fmt, "Lua out of stack space"),
&LuaError::CoroutineInactive => write!(fmt, "Cannot resume inactive coroutine"),
&LuaError::UserDataTypeMismatch => write!(fmt, "Userdata not expected type"),
&LuaError::UserDataBorrowError => write!(fmt, "Userdata already mutably borrowed"),
@@ -79,7 +75,6 @@ impl Error for LuaError {
&LuaError::ErrorError(_) => "lua error handling error",
&LuaError::ToLuaConversionError(_) => "conversion error to lua",
&LuaError::FromLuaConversionError(_) => "conversion error from lua",
- &LuaError::StackOverflow => "lua stack overflow",
&LuaError::CoroutineInactive => "lua coroutine inactive",
&LuaError::UserDataTypeMismatch => "lua userdata type mismatch",
&LuaError::UserDataBorrowError => "lua userdata already mutably borrowed",
diff --git a/src/lib.rs b/src/lib.rs
index 5c32ae1..ee25344 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,6 +2,7 @@
extern crate hlist_macro;
pub mod ffi;
+#[macro_use]
mod util;
mod error;
mod lua;
diff --git a/src/lua.rs b/src/lua.rs
index 538fe90..d1fee52 100644
--- a/src/lua.rs
+++ b/src/lua.rs
@@ -185,7 +185,7 @@ impl<'lua> LuaString<'lua> {
/// # use rlua::*;
/// # fn main() {
/// let lua = Lua::new();
- /// let globals = lua.globals().unwrap();
+ /// let globals = lua.globals();
///
/// let version: LuaString = globals.get("_VERSION").unwrap();
/// assert!(version.to_str().unwrap().contains("Lua"));
@@ -197,8 +197,8 @@ impl<'lua> LuaString<'lua> {
pub fn to_str(&self) -> LuaResult<&str> {
let lua = self.0.lua;
unsafe {
- stack_guard(lua.state, 0, || {
- check_stack(lua.state, 1)?;
+ stack_err_guard(lua.state, 0, || {
+ check_stack(lua.state, 1);
lua.push_ref(lua.state, &self.0);
assert_eq!(ffi::lua_type(lua.state, -1), ffi::LUA_TSTRING);
let s = CStr::from_ptr(ffi::lua_tostring(lua.state, -1))
@@ -227,7 +227,7 @@ impl<'lua> LuaTable<'lua> {
let key = key.to_lua(lua)?;
let value = value.to_lua(lua)?;
unsafe {
- check_stack(lua.state, 3)?;
+ check_stack(lua.state, 3);
lua.push_ref(lua.state, &self.0);
lua.push_value(lua.state, key);
lua.push_value(lua.state, value);
@@ -248,7 +248,7 @@ impl<'lua> LuaTable<'lua> {
let lua = self.0.lua;
let key = key.to_lua(lua)?;
unsafe {
- check_stack(lua.state, 2)?;
+ check_stack(lua.state, 2);
lua.push_ref(lua.state, &self.0);
lua.push_value(lua.state, key.to_lua(lua)?);
let res = error_guard(lua.state, 2, 0, |state| {
@@ -266,7 +266,7 @@ impl<'lua> LuaTable<'lua> {
let lua = self.0.lua;
let key = key.to_lua(lua)?;
unsafe {
- check_stack(lua.state, 2)?;
+ check_stack(lua.state, 2);
lua.push_ref(lua.state, &self.0);
lua.push_value(lua.state, key);
error_guard(lua.state, 2, 0, |state| {
@@ -282,8 +282,8 @@ impl<'lua> LuaTable<'lua> {
pub fn raw_set<K: ToLua<'lua>, V: ToLua<'lua>>(&self, key: K, value: V) -> LuaResult<()> {
let lua = self.0.lua;
unsafe {
- stack_guard(lua.state, 0, || {
- check_stack(lua.state, 3)?;
+ stack_err_guard(lua.state, 0, || {
+ check_stack(lua.state, 3);
lua.push_ref(lua.state, &self.0);
lua.push_value(lua.state, key.to_lua(lua)?);
lua.push_value(lua.state, value.to_lua(lua)?);
@@ -298,8 +298,8 @@ impl<'lua> LuaTable<'lua> {
pub fn raw_get<K: ToLua<'lua>, V: FromLua<'lua>>(&self, key: K) -> LuaResult<V> {
let lua = self.0.lua;
unsafe {
- stack_guard(lua.state, 0, || {
- check_stack(lua.state, 2)?;
+ stack_err_guard(lua.state, 0, || {
+ check_stack(lua.state, 2);
lua.push_ref(lua.state, &self.0);
lua.push_value(lua.state, key.to_lua(lua)?);
ffi::lua_gettable(lua.state, -2);
@@ -318,7 +318,7 @@ impl<'lua> LuaTable<'lua> {
let lua = self.0.lua;
unsafe {
error_guard(lua.state, 0, 0, |state| {
- check_stack(state, 1)?;
+ check_stack(state, 1);
lua.push_ref(state, &self.0);
Ok(ffi::luaL_len(state, -1))
})
@@ -327,15 +327,15 @@ impl<'lua> LuaTable<'lua> {
/// Returns the result of the Lua `#` operator, without invoking the
/// `__len` metamethod.
- pub fn raw_len(&self) -> LuaResult<LuaInteger> {
+ pub fn raw_len(&self) -> LuaInteger {
let lua = self.0.lua;
unsafe {
stack_guard(lua.state, 0, || {
- check_stack(lua.state, 1)?;
+ check_stack(lua.state, 1);
lua.push_ref(lua.state, &self.0);
let len = ffi::lua_rawlen(lua.state, -1);
ffi::lua_pop(lua.state, 1);
- Ok(len as LuaInteger)
+ len as LuaInteger
})
}
}
@@ -389,9 +389,7 @@ where
let lua = self.table.lua;
unsafe {
- if let Err(e) = check_stack(lua.state, 4) {
- return Some(Err(e));
- }
+ check_stack(lua.state, 4);
lua.push_ref(lua.state, &self.table);
lua.push_ref(lua.state, &next_key);
@@ -446,9 +444,7 @@ where
let lua = self.table.lua;
unsafe {
- if let Err(e) = check_stack(lua.state, 2) {
- return Some(Err(e));
- }
+ check_stack(lua.state, 2);
lua.push_ref(lua.state, &self.table);
match error_guard(
@@ -489,10 +485,10 @@ impl<'lua> LuaFunction<'lua> {
pub fn call<A: ToLuaMulti<'lua>, R: FromLuaMulti<'lua>>(&self, args: A) -> LuaResult<R> {
let lua = self.0.lua;
unsafe {
- stack_guard(lua.state, 0, || {
+ stack_err_guard(lua.state, 0, || {
let args = args.to_lua_multi(lua)?;
let nargs = args.len() as c_int;
- check_stack(lua.state, nargs + 3)?;
+ check_stack(lua.state, nargs + 3);
let stack_start = ffi::lua_gettop(lua.state);
lua.push_ref(lua.state, &self.0);
@@ -532,7 +528,7 @@ impl<'lua> LuaFunction<'lua> {
///
/// # fn main() {
/// let lua = Lua::new();
- /// let globals = lua.globals().unwrap();
+ /// let globals = lua.globals();
///
/// // Bind the argument `123` to Lua's `tostring` function
/// let tostring: LuaFunction = globals.get("tostring").unwrap();
@@ -548,7 +544,7 @@ impl<'lua> LuaFunction<'lua> {
let nargs = ffi::lua_gettop(state);
let nbinds = ffi::lua_tointeger(state, ffi::lua_upvalueindex(2)) as c_int;
- check_stack(state, nbinds + 1).expect("not enough space to handle bound arguments");
+ check_stack(state, nbinds + 1);
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(1));
ffi::lua_insert(state, 1);
@@ -565,11 +561,11 @@ impl<'lua> LuaFunction<'lua> {
let lua = self.0.lua;
unsafe {
- stack_guard(lua.state, 0, || {
+ stack_err_guard(lua.state, 0, || {
let args = args.to_lua_multi(lua)?;
let nargs = args.len() as c_int;
- check_stack(lua.state, nargs + 2)?;
+ check_stack(lua.state, nargs + 2);
lua.push_ref(lua.state, &self.0);
ffi::lua_pushinteger(lua.state, nargs as ffi::lua_Integer);
for arg in args {
@@ -653,8 +649,8 @@ impl<'lua> LuaThread<'lua> {
{
let lua = self.0.lua;
unsafe {
- stack_guard(lua.state, 0, || {
- check_stack(lua.state, 1)?;
+ stack_err_guard(lua.state, 0, || {
+ check_stack(lua.state, 1);
lua.push_ref(lua.state, &self.0);
let thread_state = ffi::lua_tothread(lua.state, -1);
@@ -668,7 +664,7 @@ impl<'lua> LuaThread<'lua> {
let args = args.to_lua_multi(lua)?;
let nargs = args.len() as c_int;
- check_stack(thread_state, nargs)?;
+ check_stack(thread_state, nargs);
for arg in args {
lua.push_value(thread_state, arg);
@@ -690,11 +686,11 @@ impl<'lua> LuaThread<'lua> {
}
/// Gets the status of the thread.
- pub fn status(&self) -> LuaResult<LuaThreadStatus> {
+ pub fn status(&self) -> LuaThreadStatus {
let lua = self.0.lua;
unsafe {
stack_guard(lua.state, 0, || {
- check_stack(lua.state, 1)?;
+ check_stack(lua.state, 1);
lua.push_ref(lua.state, &self.0);
let thread_state = ffi::lua_tothread(lua.state, -1);
@@ -702,11 +698,11 @@ impl<'lua> LuaThread<'lua> {
let status = ffi::lua_status(thread_state);
if status != ffi::LUA_OK && status != ffi::LUA_YIELD {
- Ok(LuaThreadStatus::Error)
+ LuaThreadStatus::Error
} else if status == ffi::LUA_YIELD || ffi::lua_gettop(thread_state) > 0 {
- Ok(LuaThreadStatus::Active)
+ LuaThreadStatus::Active
} else {
- Ok(LuaThreadStatus::Dead)
+ LuaThreadStatus::Dead
}
})
}
@@ -892,12 +888,8 @@ pub struct LuaUserData<'lua>(LuaRef<'lua>);
impl<'lua> LuaUserData<'lua> {
/// Checks whether `T` is the type of this userdata.
- pub fn is<T: LuaUserDataType>(&self) -> LuaResult<bool> {
- match self.inspect(|_: &RefCell<T>| Ok(())) {
- Ok(_) => Ok(true),
- Err(LuaError::UserDataTypeMismatch) => Ok(false),
- Err(err) => Err(err),
- }
+ pub fn is<T: LuaUserDataType>(&self) -> bool {
+ self.inspect(|_: &RefCell<T>| ()).is_some()
}
/// Borrow this userdata out of the internal RefCell that is held in lua.
@@ -906,7 +898,7 @@ impl<'lua> LuaUserData<'lua> {
Ok(
cell.try_borrow().map_err(|_| LuaError::UserDataBorrowError)?,
)
- })
+ }).ok_or(LuaError::UserDataTypeMismatch)?
}
/// Borrow mutably this userdata out of the internal RefCell that is held in
@@ -916,24 +908,25 @@ impl<'lua> LuaUserData<'lua> {
Ok(cell.try_borrow_mut().map_err(
|_| LuaError::UserDataBorrowMutError,
)?)
- })
+ }).ok_or(LuaError::UserDataTypeMismatch)?
}
- fn inspect<'a, T, R, F>(&'a self, func: F) -> LuaResult<R>
+ fn inspect<'a, T, R, F>(&'a self, func: F) -> Option<R>
where
T: LuaUserDataType,
- F: FnOnce(&'a RefCell<T>) -> LuaResult<R>,
+ F: FnOnce(&'a RefCell<T>) -> R,
{
unsafe {
let lua = self.0.lua;
stack_guard(lua.state, 0, move || {
- check_stack(lua.state, 3)?;
+ check_stack(lua.state, 3);
lua.push_ref(lua.state, &self.0);
let userdata = ffi::lua_touserdata(lua.state, -1);
- assert!(!userdata.is_null());
- assert!(
+ lua_assert!(lua.state, !userdata.is_null());
+ lua_assert!(
+ lua.state,
ffi::lua_getmetatable(lua.state, -1) != 0,
"LuaUserData missing metatable"
);
@@ -941,16 +934,17 @@ impl<'lua> LuaUserData<'lua> {
ffi::lua_rawgeti(
lua.state,
ffi::LUA_REGISTRYINDEX,
- lua.userdata_metatable::<T>()? as ffi::lua_Integer,
+ lua.userdata_metatable::<T>() as ffi::lua_Integer,
);
+
if ffi::lua_rawequal(lua.state, -1, -2) == 0 {
- return Err(LuaError::UserDataTypeMismatch);
+ ffi::lua_pop(lua.state, 3);
+ None
+ } else {
+ let res = func(&*(userdata as *const RefCell<T>));
+ ffi::lua_pop(lua.state, 3);
+ Some(res)
}
-
- let res = func(&*(userdata as *const RefCell<T>));
-
- ffi::lua_pop(lua.state, 3);
- res
})
}
}
@@ -980,9 +974,12 @@ impl Lua {
pub fn new() -> Lua {
unsafe {
let state = ffi::luaL_newstate();
- ffi::luaL_openlibs(state);
stack_guard(state, 0, || {
+ ffi::luaL_openlibs(state);
+
+ // Create the userdata registry table
+
ffi::lua_pushlightuserdata(
state,
&LUA_USERDATA_REGISTRY_KEY as *const u8 as *mut c_void,
@@ -1003,10 +1000,9 @@ impl Lua {
ffi::lua_setmetatable(state, -2);
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
- Ok(())
- }).unwrap();
- stack_guard(state, 0, || {
+ // Create the function metatable
+
ffi::lua_pushlightuserdata(
state,
&FUNCTION_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void,
@@ -1023,10 +1019,9 @@ impl Lua {
ffi::lua_rawset(state, -3);
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
- Ok(())
- }).unwrap();
- stack_guard(state, 0, || {
+ // Override pcall / xpcall
+
ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
push_string(state, "pcall");
@@ -1038,8 +1033,7 @@ impl Lua {
ffi::lua_rawset(state, -3);
ffi::lua_pop(state, 1);
- Ok(())
- }).unwrap();
+ });
Lua {
state,
@@ -1057,7 +1051,7 @@ impl Lua {
/// Equivalent to Lua's `load` function.
pub fn load(&self, source: &str, name: Option<&str>) -> LuaResult<LuaFunction> {
unsafe {
- stack_guard(self.state, 0, || {
+ stack_err_guard(self.state, 0, || {
handle_error(
self.state,
if let Some(name) = name {
@@ -1105,7 +1099,7 @@ impl Lua {
/// to. Otherwise, returns the values returned by the chunk (if any).
pub fn eval<'lua, R: FromLuaMulti<'lua>>(&'lua self, source: &str) -> LuaResult<R> {
unsafe {
- stack_guard(self.state, 0, || {
+ stack_err_guard(self.state, 0, || {
// First, try interpreting the lua as an expression by adding
// "return", then as a statement. This is the same thing the
// actual lua repl does.
@@ -1133,23 +1127,23 @@ impl Lua {
}
/// Pass a `&str` slice to Lua, creating and returning a interned Lua string.
- pub fn create_string(&self, s: &str) -> LuaResult<LuaString> {
+ pub fn create_string(&self, s: &str) -> LuaString {
unsafe {
stack_guard(self.state, 0, || {
- check_stack(self.state, 1)?;
+ check_stack(self.state, 1);
ffi::lua_pushlstring(self.state, s.as_ptr() as *const c_char, s.len());
- Ok(LuaString(self.pop_ref(self.state)))
+ LuaString(self.pop_ref(self.state))
})
}
}
/// Creates and returns a new table.
- pub fn create_table(&self) -> LuaResult<LuaTable> {
+ pub fn create_table(&self) -> LuaTable {
unsafe {
stack_guard(self.state, 0, || {
- check_stack(self.state, 1)?;
+ check_stack(self.state, 1);
ffi::lua_newtable(self.state);
- Ok(LuaTable(self.pop_ref(self.state)))
+ LuaTable(self.pop_ref(self.state))
})
}
}
@@ -1162,8 +1156,8 @@ impl Lua {
I: IntoIterator<Item = (K, V)>,
{
unsafe {
- stack_guard(self.state, 0, || {
- check_stack(self.state, 3)?;
+ stack_err_guard(self.state, 0, || {
+ check_stack(self.state, 3);
ffi::lua_newtable(self.state);
for (k, v) in cont {
@@ -1186,7 +1180,7 @@ impl Lua {
}
/// Wraps a Rust function or closure, creating a callable Lua function handle to it.
- pub fn create_function<F>(&self, func: F) -> LuaResult<LuaFunction>
+ pub fn create_function<F>(&self, func: F) -> LuaFunction
where
F: 'static + for<'a> FnMut(&'a Lua, LuaMultiValue<'a>) -> LuaResult<LuaMultiValue<'a>>,
{
@@ -1196,27 +1190,27 @@ impl Lua {
/// Wraps a Lua function into a new thread (or coroutine).
///
/// Equivalent to `coroutine.create`.
- pub fn create_thread<'lua>(&'lua self, func: LuaFunction<'lua>) -> LuaResult<LuaThread<'lua>> {
+ pub fn create_thread<'lua>(&'lua self, func: LuaFunction<'lua>) -> LuaThread<'lua> {
unsafe {
stack_guard(self.state, 0, move || {
- check_stack(self.state, 1)?;
+ check_stack(self.state, 1);
let thread_state = ffi::lua_newthread(self.state);
self.push_ref(thread_state, &func.0);
- Ok(LuaThread(self.pop_ref(self.state)))
+ LuaThread(self.pop_ref(self.state))
})
}
}
/// Create a Lua userdata object from a custom userdata type.
- pub fn create_userdata<T>(&self, data: T) -> LuaResult<LuaUserData>
+ pub fn create_userdata<T>(&self, data: T) -> LuaUserData
where
T: LuaUserDataType,
{
unsafe {
stack_guard(self.state, 0, move || {
- check_stack(self.state, 2)?;
+ check_stack(self.state, 2);
let data = RefCell::new(data);
let data_userdata =
@@ -1227,22 +1221,24 @@ impl Lua {
ffi::lua_rawgeti(
self.state,
ffi::LUA_REGISTRYINDEX,
- self.userdata_metatable::<T>()? as ffi::lua_Integer,
+ self.userdata_metatable::<T>() as ffi::lua_Integer,
);
ffi::lua_setmetatable(self.state, -2);
- Ok(LuaUserData(self.pop_ref(self.state)))
+ LuaUserData(self.pop_ref(self.state))
})
}
}
/// Returns a handle to the global environment.
- pub fn globals(&self) -> LuaResult<LuaTable> {
+ pub fn globals(&self) -> LuaTable {
unsafe {
- check_stack(self.state, 1)?;
- ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
- Ok(LuaTable(self.pop_ref(self.state)))
+ stack_guard(self.state, 0, move || {
+ check_stack(self.state, 1);
+ ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
+ LuaTable(self.pop_ref(self.state))
+ })
}
}
@@ -1254,9 +1250,10 @@ impl Lua {
LuaValue::String(s) => Ok(s),
v => unsafe {
stack_guard(self.state, 0, || {
- check_stack(self.state, 1)?;
+ check_stack(self.state, 1);
self.push_value(self.state, v);
if ffi::lua_tostring(self.state, -1).is_null() {
+ ffi::lua_pop(self.state, 1);
Err(LuaError::FromLuaConversionError(
"cannot convert lua value to string".to_owned(),
))
@@ -1277,16 +1274,16 @@ impl Lua {
LuaValue::Integer(i) => Ok(i),
v => unsafe {
stack_guard(self.state, 0, || {
- check_stack(self.state, 1)?;
+ check_stack(self.state, 1);
self.push_value(self.state, v);
let mut isint = 0;
let i = ffi::lua_tointegerx(self.state, -1, &mut isint);
+ ffi::lua_pop(self.state, 1);
if isint == 0 {
Err(LuaError::FromLuaConversionError(
"cannot convert lua value to integer".to_owned(),
))
} else {
- ffi::lua_pop(self.state, 1);
Ok(i)
}
})
@@ -1303,16 +1300,16 @@ impl Lua {
LuaValue::Number(n) => Ok(n),
v => unsafe {
stack_guard(self.state, 0, || {
- check_stack(self.state, 1)?;
+ check_stack(self.state, 1);
self.push_value(self.state, v);
let mut isnum = 0;
let n = ffi::lua_tonumberx(self.state, -1, &mut isnum);
+ ffi::lua_pop(self.state, 1);
if isnum == 0 {
Err(LuaError::FromLuaConversionError(
"cannot convert lua value to number".to_owned(),
))
} else {
- ffi::lua_pop(self.state, 1);
Ok(n)
}
})
@@ -1345,7 +1342,7 @@ impl Lua {
T::from_lua_multi(value, self)
}
- fn create_callback_function(&self, func: LuaCallback) -> LuaResult<LuaFunction> {
+ fn create_callback_function(&self, func: LuaCallback) -> LuaFunction {
unsafe extern "C" fn callback_call_impl(state: *mut ffi::lua_State) -> c_int {
callback_error(state, || {
let lua = Lua {
@@ -1376,7 +1373,7 @@ impl Lua {
unsafe {
stack_guard(self.state, 0, move || {
- check_stack(self.state, 2)?;
+ check_stack(self.state, 2);
let func_userdata =
ffi::lua_newuserdata(self.state, mem::size_of::<LuaCallback>()) as
@@ -1392,7 +1389,7 @@ impl Lua {
ffi::lua_pushcclosure(self.state, callback_call_impl, 1);
- Ok(LuaFunction(self.pop_ref(self.state)))
+ LuaFunction(self.pop_ref(self.state))
})
}
}
@@ -1496,7 +1493,7 @@ impl Lua {
ffi::LUA_TTHREAD => LuaValue::Thread(LuaThread(self.pop_ref(state))),
- _ => panic!("LUA_TNONE in pop_value"),
+ _ => unreachable!("internal error: LUA_TNONE in pop_value"),
}
}
@@ -1527,7 +1524,7 @@ impl Lua {
}
}
- unsafe fn userdata_metatable<T: LuaUserDataType>(&self) -> LuaResult<c_int> {
+ unsafe fn userdata_metatable<T: LuaUserDataType>(&self) -> c_int {
// Used if both an __index metamethod is set and regular methods, checks methods table
// first, then __index metamethod.
unsafe extern "C" fn meta_index_impl(state: *mut ffi::lua_State) -> c_int {
@@ -1547,7 +1544,7 @@ impl Lua {
}
stack_guard(self.state, 0, move || {
- check_stack(self.state, 3)?;
+ check_stack(self.state, 5);
ffi::lua_pushlightuserdata(
self.state,
@@ -1560,7 +1557,7 @@ impl Lua {
ffi::lua_pop(self.state, 1);
match map.entry(TypeId::of::<T>()) {
- HashMapEntry::Occupied(entry) => Ok(*entry.get()),
+ HashMapEntry::Occupied(entry) => *entry.get(),
HashMapEntry::Vacant(entry) => {
ffi::lua_newtable(self.state);
@@ -1577,12 +1574,11 @@ impl Lua {
push_string(self.state, "__index");
ffi::lua_newtable(self.state);
- check_stack(self.state, methods.methods.len() as c_int * 2)?;
for (k, m) in methods.methods {
push_string(self.state, &k);
self.push_value(
self.state,
- LuaValue::Function(self.create_callback_function(m)?),
+ LuaValue::Function(self.create_callback_function(m)),
);
ffi::lua_rawset(self.state, -3);
}
@@ -1590,7 +1586,6 @@ impl Lua {
ffi::lua_rawset(self.state, -3);
}
- check_stack(self.state, methods.meta_methods.len() as c_int * 2)?;
for (k, m) in methods.meta_methods {
if k == LuaMetaMethod::Index && has_methods {
push_string(self.state, "__index");
@@ -1598,7 +1593,7 @@ impl Lua {
ffi::lua_gettable(self.state, -3);
self.push_value(
self.state,
- LuaValue::Function(self.create_callback_function(m)?),
+ LuaValue::Function(self.create_callback_function(m)),
);
ffi::lua_pushcclosure(self.state, meta_index_impl, 2);
ffi::lua_rawset(self.state, -3);
@@ -1631,7 +1626,7 @@ impl Lua {
push_string(self.state, name);
self.push_value(
self.state,
- LuaValue::Function(self.create_callback_function(m)?),
+ LuaValue::Function(self.create_callback_function(m)),
);
ffi::lua_rawset(self.state, -3);
}
@@ -1647,7 +1642,7 @@ impl Lua {
let id = ffi::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX);
entry.insert(id);
- Ok(id)
+ id
}
}
})
diff --git a/src/tests.rs b/src/tests.rs
index ff0dda1..48d39d2 100644
--- a/src/tests.rs
+++ b/src/tests.rs
@@ -9,7 +9,7 @@ use super::*;
#[test]
fn test_set_get() {
let lua = Lua::new();
- let globals = lua.globals().unwrap();
+ let globals = lua.globals();
globals.set("foo", "bar").unwrap();
globals.set("baz", "baf").unwrap();
assert_eq!(globals.get::<_, String>("foo").unwrap(), "bar");
@@ -29,7 +29,7 @@ fn test_load() {
#[test]
fn test_exec() {
let lua = Lua::new();
- let globals = lua.globals().unwrap();
+ let globals = lua.globals();
lua.exec::<()>(
r#"
res = 'foo'..'bar'
@@ -76,9 +76,9 @@ fn test_eval() {
#[test]
fn test_table() {
let lua = Lua::new();
- let globals = lua.globals().unwrap();
+ let globals = lua.globals();
- globals.set("table", lua.create_table().unwrap()).unwrap();
+ globals.set("table", lua.create_table()).unwrap();
let table1: LuaTable = globals.get("table").unwrap();
let table2: LuaTable = globals.get("table").unwrap();
@@ -164,7 +164,7 @@ fn test_table() {
#[test]
fn test_function() {
let lua = Lua::new();
- let globals = lua.globals().unwrap();
+ let globals = lua.globals();
lua.exec::<()>(
r#"
function concat(arg1, arg2)
@@ -184,7 +184,7 @@ fn test_function() {
#[test]
fn test_bind() {
let lua = Lua::new();
- let globals = lua.globals().unwrap();
+ let globals = lua.globals();
lua.exec::<()>(
r#"
function concat(...)
@@ -211,7 +211,7 @@ fn test_bind() {
#[test]
fn test_rust_function() {
let lua = Lua::new();
- let globals = lua.globals().unwrap();
+ let globals = lua.globals();
lua.exec::<()>(
r#"
function lua_function()
@@ -225,7 +225,7 @@ fn test_rust_function() {
).unwrap();
let lua_function = globals.get::<_, LuaFunction>("lua_function").unwrap();
- let rust_function = lua.create_function(|lua, _| lua.pack("hello")).unwrap();
+ let rust_function = lua.create_function(|lua, _| lua.pack("hello"));
globals.set("rust_function", rust_function).unwrap();
assert_eq!(lua_function.call::<_, String>(()).unwrap(), "hello");
@@ -241,13 +241,13 @@ fn test_user_data() {
let lua = Lua::new();
- let userdata1 = lua.create_userdata(UserData1(1)).unwrap();
- let userdata2 = lua.create_userdata(UserData2(Box::new(2))).unwrap();
+ let userdata1 = lua.create_userdata(UserData1(1));
+ let userdata2 = lua.create_userdata(UserData2(Box::new(2)));
- assert!(userdata1.is::<UserData1>().unwrap());
- assert!(!userdata1.is::<UserData2>().unwrap());
- assert!(userdata2.is::<UserData2>().unwrap());
- assert!(!userdata2.is::<UserData1>().unwrap());
+ assert!(userdata1.is::<UserData1>());
+ assert!(!userdata1.is::<UserData2>());
+ assert!(userdata2.is::<UserData2>());
+ assert!(!userdata2.is::<UserData1>());
assert_eq!(userdata1.borrow::<UserData1>().unwrap().0, 1);
assert_eq!(*userdata2.borrow::<UserData2>().unwrap().0, 2);
@@ -268,8 +268,8 @@ fn test_methods() {
}
let lua = Lua::new();
- let globals = lua.globals().unwrap();
- let userdata = lua.create_userdata(UserData(42)).unwrap();
+ let globals = lua.globals();
+ let userdata = lua.create_userdata(UserData(42));
globals.set("userdata", userdata.clone()).unwrap();
lua.exec::<()>(
r#"
@@ -320,7 +320,7 @@ fn test_metamethods() {
}
let lua = Lua::new();
- let globals = lua.globals().unwrap();
+ let globals = lua.globals();
globals.set("userdata1", UserData(7)).unwrap();
globals.set("userdata2", UserData(3)).unwrap();
assert_eq!(lua.eval::<UserData>("userdata1 + userdata2").unwrap().0, 10);
@@ -333,7 +333,7 @@ fn test_metamethods() {
#[test]
fn test_scope() {
let lua = Lua::new();
- let globals = lua.globals().unwrap();
+ let globals = lua.globals();
lua.exec::<()>(
r#"
touter = {
@@ -369,7 +369,7 @@ fn test_scope() {
#[test]
fn test_lua_multi() {
let lua = Lua::new();
- let globals = lua.globals().unwrap();
+ let globals = lua.globals();
lua.exec::<()>(
r#"
function concat(arg1, arg2)
@@ -401,7 +401,7 @@ fn test_lua_multi() {
#[test]
fn test_coercion() {
let lua = Lua::new();
- let globals = lua.globals().unwrap();
+ let globals = lua.globals();
lua.exec::<()>(
r#"
int = 123
@@ -438,7 +438,7 @@ fn test_error() {
}
let lua = Lua::new();
- let globals = lua.globals().unwrap();
+ let globals = lua.globals();
lua.exec::<()>(
r#"
function no_error()
@@ -492,8 +492,7 @@ fn test_error() {
None,
).unwrap();
- let rust_error_function = lua.create_function(|_, _| Err(TestError.to_lua_err()))
- .unwrap();
+ let rust_error_function = lua.create_function(|_, _| Err(TestError.to_lua_err()));
globals
.set("rust_error_function", rust_error_function)
.unwrap();
@@ -546,6 +545,8 @@ fn test_error() {
match catch_unwind(|| -> LuaResult<()> {
let lua = Lua::new();
+ let globals = lua.globals();
+
lua.exec::<()>(
r#"
function rust_panic()
@@ -556,7 +557,7 @@ fn test_error() {
)?;
let rust_panic_function = lua.create_function(|_, _| {
panic!("expected panic, this panic should be caught in rust")
- })?;
+ });
globals.set("rust_panic_function", rust_panic_function)?;
let rust_panic = globals.get::<_, LuaFunction>("rust_panic")?;
@@ -570,6 +571,8 @@ fn test_error() {
match catch_unwind(|| -> LuaResult<()> {
let lua = Lua::new();
+ let globals = lua.globals();
+
lua.exec::<()>(
r#"
function rust_panic()
@@ -580,7 +583,7 @@ fn test_error() {
)?;
let rust_panic_function = lua.create_function(|_, _| {
panic!("expected panic, this panic should be caught in rust")
- })?;
+ });
globals.set("rust_panic_function", rust_panic_function)?;
let rust_panic = globals.get::<_, LuaFunction>("rust_panic")?;
@@ -608,19 +611,19 @@ fn test_thread() {
end
"#,
).unwrap(),
- ).unwrap();
+ );
- assert_eq!(thread.status().unwrap(), LuaThreadStatus::Active);
+ assert_eq!(thread.status(), LuaThreadStatus::Active);
assert_eq!(thread.resume::<_, i64>(0).unwrap(), 0);
- assert_eq!(thread.status().unwrap(), LuaThreadStatus::Active);
+ assert_eq!(thread.status(), LuaThreadStatus::Active);
assert_eq!(thread.resume::<_, i64>(1).unwrap(), 1);
- assert_eq!(thread.status().unwrap(), LuaThreadStatus::Active);
+ assert_eq!(thread.status(), LuaThreadStatus::Active);
assert_eq!(thread.resume::<_, i64>(2).unwrap(), 3);
- assert_eq!(thread.status().unwrap(), LuaThreadStatus::Active);
+ assert_eq!(thread.status(), LuaThreadStatus::Active);
assert_eq!(thread.resume::<_, i64>(3).unwrap(), 6);
- assert_eq!(thread.status().unwrap(), LuaThreadStatus::Active);
+ assert_eq!(thread.status(), LuaThreadStatus::Active);
assert_eq!(thread.resume::<_, i64>(4).unwrap(), 10);
- assert_eq!(thread.status().unwrap(), LuaThreadStatus::Dead);
+ assert_eq!(thread.status(), LuaThreadStatus::Dead);
let accumulate = lua.create_thread(
lua.eval::<LuaFunction>(
@@ -632,15 +635,15 @@ fn test_thread() {
end
"#,
).unwrap(),
- ).unwrap();
+ );
for i in 0..4 {
accumulate.resume::<_, ()>(i).unwrap();
}
assert_eq!(accumulate.resume::<_, i64>(4).unwrap(), 10);
- assert_eq!(accumulate.status().unwrap(), LuaThreadStatus::Active);
+ assert_eq!(accumulate.status(), LuaThreadStatus::Active);
assert!(accumulate.resume::<_, ()>("error").is_err());
- assert_eq!(accumulate.status().unwrap(), LuaThreadStatus::Error);
+ assert_eq!(accumulate.status(), LuaThreadStatus::Error);
let thread = lua.eval::<LuaThread>(
r#"
@@ -651,7 +654,7 @@ fn test_thread() {
end)
"#,
).unwrap();
- assert_eq!(thread.status().unwrap(), LuaThreadStatus::Active);
+ assert_eq!(thread.status(), LuaThreadStatus::Active);
assert_eq!(thread.resume::<_, i64>(()).unwrap(), 42);
let thread: LuaThread = lua.eval(
@@ -678,7 +681,7 @@ fn test_thread() {
#[test]
fn test_lightuserdata() {
let lua = Lua::new();
- let globals = lua.globals().unwrap();
+ let globals = lua.globals();
lua.exec::<()>(
r#"
function id(a)
@@ -698,7 +701,7 @@ fn test_lightuserdata() {
#[test]
fn test_table_error() {
let lua = Lua::new();
- let globals = lua.globals().unwrap();
+ let globals = lua.globals();
lua.exec::<()>(
r#"
table = {}
@@ -723,21 +726,20 @@ fn test_table_error() {
assert!(bad_table.len().is_err());
assert!(bad_table.raw_set(1, 1).is_ok());
assert!(bad_table.raw_get::<_, i32>(1).is_ok());
- assert_eq!(bad_table.raw_len().unwrap(), 1);
+ assert_eq!(bad_table.raw_len(), 1);
}
#[test]
fn test_result_conversions() {
let lua = Lua::new();
- let globals = lua.globals().unwrap();
+ let globals = lua.globals();
let err = lua.create_function(|lua, _| {
lua.pack(Result::Err::<String, _>(
"only through failure can we succeed".to_lua_err(),
))
- }).unwrap();
- let ok = lua.create_function(|lua, _| lua.pack(Result::Ok::<_, LuaError>("!".to_owned())))
- .unwrap();
+ });
+ let ok = lua.create_function(|lua, _| lua.pack(Result::Ok::<_, LuaError>("!".to_owned())));
globals.set("err", err).unwrap();
globals.set("ok", ok).unwrap();
@@ -759,7 +761,7 @@ fn test_result_conversions() {
#[test]
fn test_num_conversion() {
let lua = Lua::new();
- let globals = lua.globals().unwrap();
+ let globals = lua.globals();
globals.set("n", "1.0").unwrap();
assert_eq!(globals.get::<_, i64>("n").unwrap(), 1);
diff --git a/src/util.rs b/src/util.rs
index a02f574..ebab86f 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -16,50 +16,138 @@ macro_rules! cstr {
);
}
-pub unsafe fn check_stack(state: *mut ffi::lua_State, amount: c_int) -> LuaResult<()> {
- if ffi::lua_checkstack(state, amount) == 0 {
- Err(LuaError::StackOverflow)
- } else {
- Ok(())
- }
+// A panic that clears the given lua stack before panicking
+macro_rules! lua_panic {
+ ($state:expr) => {
+ {
+ $crate::ffi::lua_settop($state, 0);
+ panic!("rlua internal error");
+ }
+ };
+
+ ($state:expr, $msg:expr) => {
+ {
+ $crate::ffi::lua_settop($state, 0);
+ panic!(concat!("rlua: ", $msg));
+ }
+ };
+
+ ($state:expr, $fmt:expr, $($arg:tt)+) => {
+ {
+ $crate::ffi::lua_settop($state, 0);
+ panic!(concat!("rlua: ", $fmt), $($arg)+);
+ }
+ };
+}
+
+// An assert that clears the given lua stack before panicking
+macro_rules! lua_assert {
+ ($state:expr, $cond:expr) => {
+ if !$cond {
+ $crate::ffi::lua_settop($state, 0);
+ panic!("rlua internal error");
+ }
+ };
+
+ ($state:expr, $cond:expr, $msg:expr) => {
+ if !$cond {
+ $crate::ffi::lua_settop($state, 0);
+ panic!(concat!("rlua: ", $msg));
+ }
+ };
+
+ ($state:expr, $cond:expr, $fmt:expr, $($arg:tt)+) => {
+ if !$cond {
+ $crate::ffi::lua_settop($state, 0);
+ panic!(concat!("rlua: ", $fmt), $($arg)+);
+ }
+ };
+}
+
+// Checks that Lua has enough free stack space for future stack operations.
+// On failure, this will clear the stack and panic.
+pub unsafe fn check_stack(state: *mut ffi::lua_State, amount: c_int) {
+ lua_assert!(
+ state,
+ ffi::lua_checkstack(state, amount) != 0,
+ "out of stack space"
+ );
}
-// Run an operation on a lua_State and automatically clean up the stack before returning. Takes
-// the lua_State, the expected stack size change, and an operation to run. If the operation
-// results in success, then the stack is inspected to make sure the change in stack size matches
-// the expected change and otherwise this is a logic error and will panic. If the operation
-// results in an error, the stack is shrunk to the value before the call. If the operation
-// results in an error and the stack is smaller than the value before the call, then this is
-// unrecoverable and this will panic.
-pub unsafe fn stack_guard<F, R>(state: *mut ffi::lua_State, change: c_int, op: F) -> LuaResult<R>
+// Run an operation on a lua_State and check that the stack change is what is
+// expected. If the stack change does not match, clears the stack and panics.
+pub unsafe fn stack_guard<F, R>(state: *mut ffi::lua_State, change: c_int, op: F) -> R
+where
+ F: FnOnce() -> R,
+{
+ let expected = ffi::lua_gettop(state) + change;
+ lua_assert!(
+ state,
+ expected >= 0,
+ "internal stack error: too many values would be popped"
+ );
+
+ let res = op();
+
+ let top = ffi::lua_gettop(state);
+ lua_assert!(
+ state,
+ ffi::lua_gettop(state) == expected,
+ "internal stack error: expected stack to be {}, got {}",
+ expected,
+ top
+ );
+
+ res
+}
+
+// Run an operation on a lua_State and automatically clean up the stack before
+// returning. Takes the lua_State, the expected stack size change, and an
+// operation to run. If the operation results in success, then the stack is
+// inspected to make sure the change in stack size matches the expected change
+// and otherwise this is a logic error and will panic. If the operation results
+// in an error, the stack is shrunk to the value before the call. If the
+// operation results in an error and the stack is smaller than the value before
+// the call, then this is unrecoverable and this will panic. If this function
+// panics, it will clear the stack before panicking.
+pub unsafe fn stack_err_guard<F, R>(
+ state: *mut ffi::lua_State,
+ change: c_int,
+ op: F,
+) -> LuaResult<R>
where
F: FnOnce() -> LuaResult<R>,
{
let expected = ffi::lua_gettop(state) + change;
- assert!(
+ lua_assert!(
+ state,
expected >= 0,
- "lua stack error, too many values would be popped"
+ "internal stack error: too many values would be popped"
);
+
let res = op();
+
let top = ffi::lua_gettop(state);
if res.is_ok() {
- assert_eq!(
- ffi::lua_gettop(state),
- expected,
- "lua stack error, expected stack to be {}, got {}",
+ lua_assert!(
+ state,
+ ffi::lua_gettop(state) == expected,
+ "internal stack error: expected stack to be {}, got {}",
expected,
top
);
} else {
- assert!(
+ lua_assert!(
+ state,
top >= expected,
- "lua stack error, {} too many values popped",
+ "internal stack error: {} too many values popped",
top - expected
);
if top > expected {
ffi::lua_settop(state, expected);
}
}
+
res
}
@@ -127,9 +215,12 @@ pub unsafe fn handle_error(state: *mut ffi::lua_State, err: c_int) -> LuaResult<
} else if is_wrapped_panic(state, -1) {
let userdata = ffi::lua_touserdata(state, -1);
let panic = &mut *(userdata as *mut WrappedPanic);
- resume_unwind(panic.0.take().expect(
- "internal error: panic was resumed twice",
- ))
+ if let Some(p) = panic.0.take() {
+ ffi::lua_settop(state, 0);
+ resume_unwind(p);
+ } else {
+ lua_panic!(state, "internal error: panic was resumed twice")
+ }
} else {
let err_string =
@@ -174,7 +265,7 @@ pub unsafe fn handle_error(state: *mut ffi::lua_State, err: c_int) -> LuaResult<
println!("Lua error during __gc, aborting!");
process::abort()
}
- _ => panic!("unrecognized lua error code"),
+ _ => lua_panic!(state, "internal error: unrecognized lua error code"),
})
}
}