Remove error_guard
Replace with custom protected versions of lua ffi functions.
This commit is contained in:
parent
91dbbfe759
commit
44c99ea1b9
133
src/lua.rs
133
src/lua.rs
|
@ -223,14 +223,11 @@ impl<'lua> LuaTable<'lua> {
|
||||||
let key = key.to_lua(lua)?;
|
let key = key.to_lua(lua)?;
|
||||||
let value = value.to_lua(lua)?;
|
let value = value.to_lua(lua)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
check_stack(lua.state, 5);
|
check_stack(lua.state, 7);
|
||||||
lua.push_ref(lua.state, &self.0);
|
lua.push_ref(lua.state, &self.0);
|
||||||
lua.push_value(lua.state, key);
|
lua.push_value(lua.state, key);
|
||||||
lua.push_value(lua.state, value);
|
lua.push_value(lua.state, value);
|
||||||
error_guard(lua.state, 3, |state| {
|
psettable(lua.state, -3)?;
|
||||||
ffi::lua_settable(state, -3);
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
ffi::lua_pop(lua.state, 1);
|
ffi::lua_pop(lua.state, 1);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -245,16 +242,15 @@ impl<'lua> LuaTable<'lua> {
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
let key = key.to_lua(lua)?;
|
let key = key.to_lua(lua)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
check_stack(lua.state, 4);
|
stack_err_guard(lua.state, 0, || {
|
||||||
lua.push_ref(lua.state, &self.0);
|
check_stack(lua.state, 5);
|
||||||
lua.push_value(lua.state, key.to_lua(lua)?);
|
lua.push_ref(lua.state, &self.0);
|
||||||
error_guard(lua.state, 2, |state| {
|
lua.push_value(lua.state, key.to_lua(lua)?);
|
||||||
ffi::lua_gettable(state, -2);
|
pgettable(lua.state, -2)?;
|
||||||
Ok(())
|
let res = lua.pop_value(lua.state);
|
||||||
})?;
|
ffi::lua_pop(lua.state, 1);
|
||||||
let res = lua.pop_value(lua.state);
|
V::from_lua(res, lua)
|
||||||
ffi::lua_pop(lua.state, 1);
|
})
|
||||||
V::from_lua(res, lua)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,16 +259,15 @@ impl<'lua> LuaTable<'lua> {
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
let key = key.to_lua(lua)?;
|
let key = key.to_lua(lua)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
check_stack(lua.state, 4);
|
stack_err_guard(lua.state, 0, || {
|
||||||
lua.push_ref(lua.state, &self.0);
|
check_stack(lua.state, 5);
|
||||||
lua.push_value(lua.state, key);
|
lua.push_ref(lua.state, &self.0);
|
||||||
error_guard(lua.state, 2, |state| {
|
lua.push_value(lua.state, key);
|
||||||
ffi::lua_gettable(state, -2);
|
pgettable(lua.state, -2)?;
|
||||||
Ok(())
|
let has = ffi::lua_isnil(lua.state, -1) == 0;
|
||||||
})?;
|
ffi::lua_pop(lua.state, 2);
|
||||||
let has = ffi::lua_isnil(lua.state, -1) == 0;
|
Ok(has)
|
||||||
ffi::lua_pop(lua.state, 2);
|
})
|
||||||
Ok(has)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,13 +309,13 @@ impl<'lua> LuaTable<'lua> {
|
||||||
pub fn len(&self) -> LuaResult<LuaInteger> {
|
pub fn len(&self) -> LuaResult<LuaInteger> {
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
unsafe {
|
unsafe {
|
||||||
check_stack(lua.state, 3);
|
stack_err_guard(lua.state, 0, || {
|
||||||
lua.push_ref(lua.state, &self.0);
|
check_stack(lua.state, 3);
|
||||||
let len = error_guard(lua.state, 1, |state| {
|
lua.push_ref(lua.state, &self.0);
|
||||||
Ok(ffi::luaL_len(state, -1))
|
let len = plen(lua.state, -1)?;
|
||||||
})?;
|
ffi::lua_pop(lua.state, 1);
|
||||||
ffi::lua_pop(lua.state, 1);
|
Ok(len)
|
||||||
Ok(len)
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,31 +381,33 @@ where
|
||||||
let lua = self.table.lua;
|
let lua = self.table.lua;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
check_stack(lua.state, 6);
|
stack_guard(lua.state, 0, || {
|
||||||
|
check_stack(lua.state, 6);
|
||||||
|
|
||||||
lua.push_ref(lua.state, &self.table);
|
lua.push_ref(lua.state, &self.table);
|
||||||
lua.push_ref(lua.state, &next_key);
|
lua.push_ref(lua.state, &next_key);
|
||||||
|
|
||||||
match error_guard(lua.state, 2, |state| Ok(ffi::lua_next(state, -2) != 0)) {
|
match pnext(lua.state, -2) {
|
||||||
Ok(true) => {
|
Ok(0) => {
|
||||||
ffi::lua_pushvalue(lua.state, -2);
|
ffi::lua_pop(lua.state, 1);
|
||||||
let key = lua.pop_value(lua.state);
|
None
|
||||||
let value = lua.pop_value(lua.state);
|
}
|
||||||
self.next_key = Some(lua.pop_ref(lua.state));
|
Ok(_) => {
|
||||||
ffi::lua_pop(lua.state, 1);
|
ffi::lua_pushvalue(lua.state, -2);
|
||||||
|
let key = lua.pop_value(lua.state);
|
||||||
|
let value = lua.pop_value(lua.state);
|
||||||
|
self.next_key = Some(lua.pop_ref(lua.state));
|
||||||
|
ffi::lua_pop(lua.state, 1);
|
||||||
|
|
||||||
Some((|| {
|
Some((|| {
|
||||||
let key = K::from_lua(key, lua)?;
|
let key = K::from_lua(key, lua)?;
|
||||||
let value = V::from_lua(value, lua)?;
|
let value = V::from_lua(value, lua)?;
|
||||||
Ok((key, value))
|
Ok((key, value))
|
||||||
})())
|
})())
|
||||||
|
}
|
||||||
|
Err(e) => Some(Err(e)),
|
||||||
}
|
}
|
||||||
Ok(false) => {
|
})
|
||||||
ffi::lua_pop(lua.state, 1);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Err(e) => Some(Err(e)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -439,22 +436,24 @@ where
|
||||||
let lua = self.table.lua;
|
let lua = self.table.lua;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
check_stack(lua.state, 4);
|
stack_guard(lua.state, 0, || {
|
||||||
|
check_stack(lua.state, 4);
|
||||||
|
|
||||||
lua.push_ref(lua.state, &self.table);
|
lua.push_ref(lua.state, &self.table);
|
||||||
match error_guard(lua.state, 1, |state| Ok(ffi::lua_geti(state, -1, index) != ffi::LUA_TNIL)) {
|
match pgeti(lua.state, -1, index) {
|
||||||
Ok(true) => {
|
Ok(ffi::LUA_TNIL) => {
|
||||||
let value = lua.pop_value(lua.state);
|
ffi::lua_pop(lua.state, 2);
|
||||||
ffi::lua_pop(lua.state, 1);
|
None
|
||||||
self.index = Some(index + 1);
|
}
|
||||||
Some(V::from_lua(value, lua))
|
Ok(_) => {
|
||||||
|
let value = lua.pop_value(lua.state);
|
||||||
|
ffi::lua_pop(lua.state, 1);
|
||||||
|
self.index = Some(index + 1);
|
||||||
|
Some(V::from_lua(value, lua))
|
||||||
|
}
|
||||||
|
Err(err) => Some(Err(err)),
|
||||||
}
|
}
|
||||||
Ok(false) => {
|
})
|
||||||
ffi::lua_pop(lua.state, 2);
|
|
||||||
None
|
|
||||||
},
|
|
||||||
Err(e) => Some(Err(e)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
138
src/util.rs
138
src/util.rs
|
@ -151,56 +151,104 @@ where
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the given rust function in a protected lua context, similar to pcall. The stack given to
|
// Protected version of lua_gettable, uses 3 stack spaces, does not call checkstack.
|
||||||
// the protected function is a separate protected stack. This catches all calls to lua_error, but
|
pub unsafe fn pgettable(state: *mut ffi::lua_State, index: c_int) -> LuaResult<c_int> {
|
||||||
// ffi functions that can call lua_error are still longjmps, and have all the same dangers as
|
unsafe extern "C" fn gettable(state: *mut ffi::lua_State) -> c_int {
|
||||||
// longjmps, so extreme care must still be taken in code that uses this function. Does not call
|
ffi::lua_gettable(state, -2);
|
||||||
// lua_checkstack, and uses 2 extra stack spaces. On error, the stack position is set to just below
|
1
|
||||||
// the given arguments.
|
|
||||||
pub unsafe fn error_guard<F, R>(
|
|
||||||
state: *mut ffi::lua_State,
|
|
||||||
nargs: c_int,
|
|
||||||
func: F,
|
|
||||||
) -> LuaResult<R>
|
|
||||||
where
|
|
||||||
F: FnOnce(*mut ffi::lua_State) -> LuaResult<R> + UnwindSafe,
|
|
||||||
{
|
|
||||||
unsafe extern "C" fn call_impl<F>(state: *mut ffi::lua_State) -> c_int
|
|
||||||
where
|
|
||||||
F: FnOnce(*mut ffi::lua_State) -> c_int,
|
|
||||||
{
|
|
||||||
let func = ffi::lua_touserdata(state, -1) as *mut F;
|
|
||||||
let func = mem::replace(&mut *func, mem::uninitialized());
|
|
||||||
ffi::lua_pop(state, 1);
|
|
||||||
func(state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn cpcall<F>(
|
let table_index = ffi::lua_absindex(state, index);
|
||||||
state: *mut ffi::lua_State,
|
|
||||||
nargs: c_int,
|
ffi::lua_pushcfunction(state, gettable);
|
||||||
mut func: F,
|
ffi::lua_pushvalue(state, table_index);
|
||||||
) -> LuaResult<()>
|
ffi::lua_pushvalue(state, -3);
|
||||||
where
|
ffi::lua_remove(state, -4);
|
||||||
F: FnOnce(*mut ffi::lua_State) -> c_int,
|
|
||||||
{
|
handle_error(state, pcall_with_traceback(state, 2, 1))?;
|
||||||
ffi::lua_pushcfunction(state, call_impl::<F>);
|
Ok(ffi::lua_type(state, -1))
|
||||||
ffi::lua_insert(state, -(nargs + 1));
|
}
|
||||||
ffi::lua_pushlightuserdata(state, &mut func as *mut F as *mut c_void);
|
|
||||||
mem::forget(func);
|
// Protected version of lua_settable, uses 4 stack spaces, does not call checkstack.
|
||||||
handle_error(state, pcall_with_traceback(state, nargs + 1, ffi::LUA_MULTRET))
|
pub unsafe fn psettable(state: *mut ffi::lua_State, index: c_int) -> LuaResult<()> {
|
||||||
|
unsafe extern "C" fn settable(state: *mut ffi::lua_State) -> c_int {
|
||||||
|
ffi::lua_settable(state, -3);
|
||||||
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut res = None;
|
let table_index = ffi::lua_absindex(state, index);
|
||||||
let top = ffi::lua_gettop(state);
|
|
||||||
if let Err(err) = cpcall(state, nargs, |state| {
|
ffi::lua_pushcfunction(state, settable);
|
||||||
res = Some(callback_error(state, || func(state)));
|
ffi::lua_pushvalue(state, table_index);
|
||||||
let c = ffi::lua_gettop(state);
|
ffi::lua_pushvalue(state, -4);
|
||||||
c
|
ffi::lua_pushvalue(state, -4);
|
||||||
}) {
|
ffi::lua_remove(state, -5);
|
||||||
ffi::lua_settop(state, top - nargs);
|
ffi::lua_remove(state, -5);
|
||||||
Err(err)
|
|
||||||
|
handle_error(state, pcall_with_traceback(state, 3, 0))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protected version of luaL_len, uses 2 stack spaces, does not call checkstack.
|
||||||
|
pub unsafe fn plen(state: *mut ffi::lua_State, index: c_int) -> LuaResult<ffi::lua_Integer> {
|
||||||
|
unsafe extern "C" fn len(state: *mut ffi::lua_State) -> c_int {
|
||||||
|
ffi::lua_pushinteger(state, ffi::luaL_len(state, -1));
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
let table_index = ffi::lua_absindex(state, index);
|
||||||
|
|
||||||
|
ffi::lua_pushcfunction(state, len);
|
||||||
|
ffi::lua_pushvalue(state, table_index);
|
||||||
|
|
||||||
|
handle_error(state, pcall_with_traceback(state, 1, 1))?;
|
||||||
|
let len = ffi::lua_tointeger(state, -1);
|
||||||
|
ffi::lua_pop(state, 1);
|
||||||
|
Ok(len)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protected version of lua_geti, uses 3 stack spaces, does not call checkstack.
|
||||||
|
pub unsafe fn pgeti(state: *mut ffi::lua_State, index: c_int, i: ffi::lua_Integer) -> LuaResult<c_int> {
|
||||||
|
unsafe extern "C" fn geti(state: *mut ffi::lua_State) -> c_int {
|
||||||
|
let i = ffi::lua_tointeger(state, -1);
|
||||||
|
ffi::lua_geti(state, -2, i);
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
let table_index = ffi::lua_absindex(state, index);
|
||||||
|
|
||||||
|
ffi::lua_pushcfunction(state, geti);
|
||||||
|
ffi::lua_pushvalue(state, table_index);
|
||||||
|
ffi::lua_pushinteger(state, i);
|
||||||
|
|
||||||
|
handle_error(state, pcall_with_traceback(state, 2, 1))?;
|
||||||
|
Ok(ffi::lua_type(state, -1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protected version of lua_next, uses 3 stack spaces, does not call checkstack.
|
||||||
|
pub unsafe fn pnext(state: *mut ffi::lua_State, index: c_int) -> LuaResult<c_int> {
|
||||||
|
unsafe extern "C" fn next(state: *mut ffi::lua_State) -> c_int {
|
||||||
|
if ffi::lua_next(state, -2) == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let table_index = ffi::lua_absindex(state, index);
|
||||||
|
|
||||||
|
ffi::lua_pushcfunction(state, next);
|
||||||
|
ffi::lua_pushvalue(state, table_index);
|
||||||
|
ffi::lua_pushvalue(state, -3);
|
||||||
|
ffi::lua_remove(state, -4);
|
||||||
|
|
||||||
|
let stack_start = ffi::lua_gettop(state) - 3;
|
||||||
|
handle_error(state, pcall_with_traceback(state, 2, ffi::LUA_MULTRET))?;
|
||||||
|
let nresults = ffi::lua_gettop(state) - stack_start;
|
||||||
|
if nresults == 0 {
|
||||||
|
Ok(0)
|
||||||
} else {
|
} else {
|
||||||
Ok(res.unwrap())
|
Ok(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue