Remove `stack_guard` function and instead just use StackGuard directly

This commit is contained in:
kyren 2018-03-12 13:13:44 -04:00
parent 7b2f7a2932
commit ee23f199f0
8 changed files with 526 additions and 562 deletions

View File

@ -170,9 +170,7 @@ fn create_registry_values(c: &mut Criterion) {
} }
fn create_userdata(c: &mut Criterion) { fn create_userdata(c: &mut Criterion) {
struct UserData { struct UserData(i64);
i: i64,
}
impl LuaUserData for UserData {} impl LuaUserData for UserData {}
c.bench_function("create userdata 10", |b| { c.bench_function("create userdata 10", |b| {
@ -182,7 +180,7 @@ fn create_userdata(c: &mut Criterion) {
{ {
let table: LuaTable = lua.create_table().unwrap(); let table: LuaTable = lua.create_table().unwrap();
for i in 1..11 { for i in 1..11 {
table.set(i, UserData { i }).unwrap(); table.set(i, UserData(i)).unwrap();
} }
} }
lua lua

View File

@ -4,7 +4,7 @@ use std::os::raw::c_int;
use ffi; use ffi;
use error::{Error, Result}; use error::{Error, Result};
use util::{check_stack, check_stack_err, error_traceback, pop_error, protect_lua_closure, use util::{check_stack, check_stack_err, error_traceback, pop_error, protect_lua_closure,
stack_guard}; StackGuard};
use types::LuaRef; use types::LuaRef;
use value::{FromLuaMulti, MultiValue, ToLuaMulti}; use value::{FromLuaMulti, MultiValue, ToLuaMulti};
@ -63,31 +63,32 @@ impl<'lua> Function<'lua> {
/// ``` /// ```
pub fn call<A: ToLuaMulti<'lua>, R: FromLuaMulti<'lua>>(&self, args: A) -> Result<R> { pub fn call<A: ToLuaMulti<'lua>, R: FromLuaMulti<'lua>>(&self, args: A) -> Result<R> {
let lua = self.0.lua; let lua = self.0.lua;
unsafe {
stack_guard(lua.state, || {
let args = args.to_lua_multi(lua)?;
let nargs = args.len() as c_int;
check_stack_err(lua.state, nargs + 3)?;
ffi::lua_pushcfunction(lua.state, error_traceback); let args = args.to_lua_multi(lua)?;
let stack_start = ffi::lua_gettop(lua.state); let nargs = args.len() as c_int;
lua.push_ref(&self.0);
for arg in args { unsafe {
lua.push_value(arg); let _sg = StackGuard::new(lua.state);
} check_stack_err(lua.state, nargs + 3)?;
let ret = ffi::lua_pcall(lua.state, nargs, ffi::LUA_MULTRET, stack_start);
if ret != ffi::LUA_OK { ffi::lua_pushcfunction(lua.state, error_traceback);
return Err(pop_error(lua.state, ret)); let stack_start = ffi::lua_gettop(lua.state);
} lua.push_ref(&self.0);
let nresults = ffi::lua_gettop(lua.state) - stack_start; for arg in args {
let mut results = MultiValue::new(); lua.push_value(arg);
check_stack(lua.state, 2); }
for _ in 0..nresults { let ret = ffi::lua_pcall(lua.state, nargs, ffi::LUA_MULTRET, stack_start);
results.push_front(lua.pop_value()); if ret != ffi::LUA_OK {
} return Err(pop_error(lua.state, ret));
ffi::lua_pop(lua.state, 1); }
R::from_lua_multi(results, lua) let nresults = ffi::lua_gettop(lua.state) - stack_start;
}) let mut results = MultiValue::new();
check_stack(lua.state, 2);
for _ in 0..nresults {
results.push_front(lua.pop_value());
}
ffi::lua_pop(lua.state, 1);
R::from_lua_multi(results, lua)
} }
} }
@ -144,28 +145,28 @@ impl<'lua> Function<'lua> {
} }
let lua = self.0.lua; let lua = self.0.lua;
let args = args.to_lua_multi(lua)?;
let nargs = args.len() as c_int;
if nargs + 2 > ffi::LUA_MAX_UPVALUES {
return Err(Error::BindError);
}
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
let args = args.to_lua_multi(lua)?; check_stack_err(lua.state, nargs + 5)?;
let nargs = args.len() as c_int; lua.push_ref(&self.0);
ffi::lua_pushinteger(lua.state, nargs as ffi::lua_Integer);
for arg in args {
lua.push_value(arg);
}
if nargs + 2 > ffi::LUA_MAX_UPVALUES { protect_lua_closure(lua.state, nargs + 2, 1, |state| {
return Err(Error::BindError); ffi::lua_pushcclosure(state, bind_call_impl, nargs + 2);
} })?;
check_stack_err(lua.state, nargs + 5)?; Ok(Function(lua.pop_ref()))
lua.push_ref(&self.0);
ffi::lua_pushinteger(lua.state, nargs as ffi::lua_Integer);
for arg in args {
lua.push_value(arg);
}
protect_lua_closure(lua.state, nargs + 2, 1, |state| {
ffi::lua_pushcclosure(state, bind_call_impl, nargs + 2);
})?;
Ok(Function(lua.pop_ref()))
})
} }
} }
} }

View File

@ -14,8 +14,8 @@ use ffi;
use error::{Error, Result}; use error::{Error, Result};
use util::{callback_error, check_stack, check_stack_err, gc_guard, get_userdata, use util::{callback_error, check_stack, check_stack_err, gc_guard, get_userdata,
get_wrapped_error, init_error_metatables, pop_error, protect_lua, protect_lua_closure, get_wrapped_error, init_error_metatables, pop_error, protect_lua, protect_lua_closure,
push_string, push_userdata, push_wrapped_error, safe_pcall, safe_xpcall, stack_guard, push_string, push_userdata, push_wrapped_error, safe_pcall, safe_xpcall, take_userdata,
take_userdata, userdata_destructor}; userdata_destructor, StackGuard};
use value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value}; use value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value};
use types::{Callback, Integer, LightUserData, LuaRef, Number, RefType, RegistryKey}; use types::{Callback, Integer, LightUserData, LuaRef, Number, RefType, RegistryKey};
use string::String; use string::String;
@ -102,34 +102,33 @@ impl Lua {
/// Equivalent to Lua's `load` function. /// Equivalent to Lua's `load` function.
pub fn load(&self, source: &str, name: Option<&str>) -> Result<Function> { pub fn load(&self, source: &str, name: Option<&str>) -> Result<Function> {
unsafe { unsafe {
stack_guard(self.state, || { let _sg = StackGuard::new(self.state);
check_stack(self.state, 1); check_stack(self.state, 1);
match if let Some(name) = name { match if let Some(name) = name {
let name = let name =
CString::new(name.to_owned()).map_err(|e| Error::ToLuaConversionError { CString::new(name.to_owned()).map_err(|e| Error::ToLuaConversionError {
from: "&str", from: "&str",
to: "string", to: "string",
message: Some(e.to_string()), message: Some(e.to_string()),
})?; })?;
ffi::luaL_loadbuffer( ffi::luaL_loadbuffer(
self.state, self.state,
source.as_ptr() as *const c_char, source.as_ptr() as *const c_char,
source.len(), source.len(),
name.as_ptr(), name.as_ptr(),
) )
} else { } else {
ffi::luaL_loadbuffer( ffi::luaL_loadbuffer(
self.state, self.state,
source.as_ptr() as *const c_char, source.as_ptr() as *const c_char,
source.len(), source.len(),
ptr::null(), ptr::null(),
) )
} { } {
ffi::LUA_OK => Ok(Function(self.pop_ref())), ffi::LUA_OK => Ok(Function(self.pop_ref())),
err => Err(pop_error(self.state, err)), err => Err(pop_error(self.state, err)),
} }
})
} }
} }
@ -167,26 +166,24 @@ impl Lua {
/// Pass a `&str` slice to Lua, creating and returning an interned Lua string. /// Pass a `&str` slice to Lua, creating and returning an interned Lua string.
pub fn create_string(&self, s: &str) -> Result<String> { pub fn create_string(&self, s: &str) -> Result<String> {
unsafe { unsafe {
stack_guard(self.state, || { let _sg = StackGuard::new(self.state);
check_stack(self.state, 4); check_stack(self.state, 4);
push_string(self.state, s)?; push_string(self.state, s)?;
Ok(String(self.pop_ref())) Ok(String(self.pop_ref()))
})
} }
} }
/// Creates and returns a new table. /// Creates and returns a new table.
pub fn create_table(&self) -> Result<Table> { pub fn create_table(&self) -> Result<Table> {
unsafe { unsafe {
stack_guard(self.state, || { let _sg = StackGuard::new(self.state);
check_stack(self.state, 3); check_stack(self.state, 3);
unsafe extern "C" fn new_table(state: *mut ffi::lua_State) -> c_int { unsafe extern "C" fn new_table(state: *mut ffi::lua_State) -> c_int {
ffi::lua_newtable(state); ffi::lua_newtable(state);
1 1
} }
protect_lua(self.state, 0, new_table)?; protect_lua(self.state, 0, new_table)?;
Ok(Table(self.pop_ref())) Ok(Table(self.pop_ref()))
})
} }
} }
@ -198,25 +195,25 @@ impl Lua {
I: IntoIterator<Item = (K, V)>, I: IntoIterator<Item = (K, V)>,
{ {
unsafe { unsafe {
stack_guard(self.state, || { let _sg = StackGuard::new(self.state);
check_stack(self.state, 5); check_stack(self.state, 5);
unsafe extern "C" fn new_table(state: *mut ffi::lua_State) -> c_int {
ffi::lua_newtable(state); unsafe extern "C" fn new_table(state: *mut ffi::lua_State) -> c_int {
ffi::lua_newtable(state);
1
}
protect_lua(self.state, 0, new_table)?;
for (k, v) in cont {
self.push_value(k.to_lua(self)?);
self.push_value(v.to_lua(self)?);
unsafe extern "C" fn raw_set(state: *mut ffi::lua_State) -> c_int {
ffi::lua_rawset(state, -3);
1 1
} }
protect_lua(self.state, 0, new_table)?; protect_lua(self.state, 3, raw_set)?;
}
for (k, v) in cont { Ok(Table(self.pop_ref()))
self.push_value(k.to_lua(self)?);
self.push_value(v.to_lua(self)?);
unsafe extern "C" fn raw_set(state: *mut ffi::lua_State) -> c_int {
ffi::lua_rawset(state, -3);
1
}
protect_lua(self.state, 3, raw_set)?;
}
Ok(Table(self.pop_ref()))
})
} }
} }
@ -322,16 +319,15 @@ impl Lua {
/// Equivalent to `coroutine.create`. /// Equivalent to `coroutine.create`.
pub fn create_thread<'lua>(&'lua self, func: Function<'lua>) -> Result<Thread<'lua>> { pub fn create_thread<'lua>(&'lua self, func: Function<'lua>) -> Result<Thread<'lua>> {
unsafe { unsafe {
stack_guard(self.state, move || { let _sg = StackGuard::new(self.state);
check_stack(self.state, 2); check_stack(self.state, 2);
let thread_state = let thread_state =
protect_lua_closure(self.state, 0, 1, |state| ffi::lua_newthread(state))?; protect_lua_closure(self.state, 0, 1, |state| ffi::lua_newthread(state))?;
self.push_ref(&func.0); self.push_ref(&func.0);
ffi::lua_xmove(self.state, thread_state, 1); ffi::lua_xmove(self.state, thread_state, 1);
Ok(Thread(self.pop_ref())) Ok(Thread(self.pop_ref()))
})
} }
} }
@ -346,11 +342,10 @@ impl Lua {
/// Returns a handle to the global environment. /// Returns a handle to the global environment.
pub fn globals(&self) -> Table { pub fn globals(&self) -> Table {
unsafe { unsafe {
stack_guard(self.state, move || { let _sg = StackGuard::new(self.state);
check_stack(self.state, 2); check_stack(self.state, 2);
ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS); ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
Table(self.pop_ref()) Table(self.pop_ref())
})
} }
} }
@ -392,23 +387,22 @@ impl Lua {
match v { match v {
Value::String(s) => Ok(s), Value::String(s) => Ok(s),
v => unsafe { v => unsafe {
stack_guard(self.state, || { let _sg = StackGuard::new(self.state);
check_stack(self.state, 4); check_stack(self.state, 4);
let ty = v.type_name();
self.push_value(v); let ty = v.type_name();
let s = protect_lua_closure(self.state, 1, 1, |state| { self.push_value(v);
ffi::lua_tostring(state, -1) let s =
})?; protect_lua_closure(self.state, 1, 1, |state| ffi::lua_tostring(state, -1))?;
if s.is_null() { if s.is_null() {
Err(Error::FromLuaConversionError { Err(Error::FromLuaConversionError {
from: ty, from: ty,
to: "String", to: "String",
message: Some("expected string or number".to_string()), message: Some("expected string or number".to_string()),
}) })
} else { } else {
Ok(String(self.pop_ref())) Ok(String(self.pop_ref()))
} }
})
}, },
} }
} }
@ -421,22 +415,22 @@ impl Lua {
match v { match v {
Value::Integer(i) => Ok(i), Value::Integer(i) => Ok(i),
v => unsafe { v => unsafe {
stack_guard(self.state, || { let _sg = StackGuard::new(self.state);
check_stack(self.state, 2); check_stack(self.state, 2);
let ty = v.type_name();
self.push_value(v); let ty = v.type_name();
let mut isint = 0; self.push_value(v);
let i = ffi::lua_tointegerx(self.state, -1, &mut isint); let mut isint = 0;
if isint == 0 { let i = ffi::lua_tointegerx(self.state, -1, &mut isint);
Err(Error::FromLuaConversionError { if isint == 0 {
from: ty, Err(Error::FromLuaConversionError {
to: "integer", from: ty,
message: None, to: "integer",
}) message: None,
} else { })
Ok(i) } else {
} Ok(i)
}) }
}, },
} }
} }
@ -449,22 +443,22 @@ impl Lua {
match v { match v {
Value::Number(n) => Ok(n), Value::Number(n) => Ok(n),
v => unsafe { v => unsafe {
stack_guard(self.state, || { let _sg = StackGuard::new(self.state);
check_stack(self.state, 2); check_stack(self.state, 2);
let ty = v.type_name();
self.push_value(v); let ty = v.type_name();
let mut isnum = 0; self.push_value(v);
let n = ffi::lua_tonumberx(self.state, -1, &mut isnum); let mut isnum = 0;
if isnum == 0 { let n = ffi::lua_tonumberx(self.state, -1, &mut isnum);
Err(Error::FromLuaConversionError { if isnum == 0 {
from: ty, Err(Error::FromLuaConversionError {
to: "number", from: ty,
message: Some("number or string coercible to number".to_string()), to: "number",
}) message: Some("number or string coercible to number".to_string()),
} else { })
Ok(n) } else {
} Ok(n)
}) }
}, },
} }
} }
@ -502,18 +496,17 @@ impl Lua {
t: T, t: T,
) -> Result<()> { ) -> Result<()> {
unsafe { unsafe {
stack_guard(self.state, || { let _sg = StackGuard::new(self.state);
check_stack(self.state, 5); check_stack(self.state, 5);
push_string(self.state, name)?; push_string(self.state, name)?;
self.push_value(t.to_lua(self)?); self.push_value(t.to_lua(self)?);
unsafe extern "C" fn set_registry(state: *mut ffi::lua_State) -> c_int { unsafe extern "C" fn set_registry(state: *mut ffi::lua_State) -> c_int {
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX); ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
0 0
} }
protect_lua(self.state, 2, set_registry) protect_lua(self.state, 2, set_registry)
})
} }
} }
@ -525,18 +518,17 @@ impl Lua {
/// [`set_named_registry_value`]: #method.set_named_registry_value /// [`set_named_registry_value`]: #method.set_named_registry_value
pub fn named_registry_value<'lua, T: FromLua<'lua>>(&'lua self, name: &str) -> Result<T> { pub fn named_registry_value<'lua, T: FromLua<'lua>>(&'lua self, name: &str) -> Result<T> {
unsafe { unsafe {
stack_guard(self.state, || { let _sg = StackGuard::new(self.state);
check_stack(self.state, 4); check_stack(self.state, 4);
push_string(self.state, name)?; push_string(self.state, name)?;
unsafe extern "C" fn get_registry(state: *mut ffi::lua_State) -> c_int { unsafe extern "C" fn get_registry(state: *mut ffi::lua_State) -> c_int {
ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX); ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX);
1 1
} }
protect_lua(self.state, 1, get_registry)?; protect_lua(self.state, 1, get_registry)?;
T::from_lua(self.pop_value(), self) T::from_lua(self.pop_value(), self)
})
} }
} }
@ -555,18 +547,17 @@ impl Lua {
/// state. /// state.
pub fn create_registry_value<'lua, T: ToLua<'lua>>(&'lua self, t: T) -> Result<RegistryKey> { pub fn create_registry_value<'lua, T: ToLua<'lua>>(&'lua self, t: T) -> Result<RegistryKey> {
unsafe { unsafe {
stack_guard(self.state, || { let _sg = StackGuard::new(self.state);
check_stack(self.state, 2); check_stack(self.state, 2);
self.push_value(t.to_lua(self)?); self.push_value(t.to_lua(self)?);
let registry_id = gc_guard(self.state, || { let registry_id = gc_guard(self.state, || {
ffi::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX) ffi::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX)
}); });
Ok(RegistryKey { Ok(RegistryKey {
registry_id, registry_id,
unref_list: (*self.extra()).registry_unref_list.clone(), unref_list: (*self.extra()).registry_unref_list.clone(),
})
}) })
} }
} }
@ -583,15 +574,15 @@ impl Lua {
return Err(Error::MismatchedRegistryKey); return Err(Error::MismatchedRegistryKey);
} }
stack_guard(self.state, || { let _sg = StackGuard::new(self.state);
check_stack(self.state, 2); check_stack(self.state, 2);
ffi::lua_rawgeti(
self.state, ffi::lua_rawgeti(
ffi::LUA_REGISTRYINDEX, self.state,
key.registry_id as ffi::lua_Integer, ffi::LUA_REGISTRYINDEX,
); key.registry_id as ffi::lua_Integer,
T::from_lua(self.pop_value(), self) );
}) T::from_lua(self.pop_value(), self)
} }
} }
@ -883,112 +874,111 @@ impl Lua {
} }
} }
stack_guard(self.state, move || { if let Some(table_id) = (*self.extra()).registered_userdata.get(&TypeId::of::<T>()) {
if let Some(table_id) = (*self.extra()).registered_userdata.get(&TypeId::of::<T>()) { return Ok(*table_id);
return Ok(*table_id); }
}
check_stack(self.state, 6); let _sg = StackGuard::new(self.state);
check_stack(self.state, 6);
let mut methods = UserDataMethods { let mut methods = UserDataMethods {
methods: HashMap::new(), methods: HashMap::new(),
meta_methods: HashMap::new(), meta_methods: HashMap::new(),
_type: PhantomData, _type: PhantomData,
}; };
T::add_methods(&mut methods); T::add_methods(&mut methods);
protect_lua_closure(self.state, 0, 1, |state| {
ffi::lua_newtable(state);
})?;
let has_methods = !methods.methods.is_empty();
if has_methods {
push_string(self.state, "__index")?;
protect_lua_closure(self.state, 0, 1, |state| { protect_lua_closure(self.state, 0, 1, |state| {
ffi::lua_newtable(state); ffi::lua_newtable(state);
})?; })?;
let has_methods = !methods.methods.is_empty(); for (k, m) in methods.methods {
push_string(self.state, &k)?;
if has_methods { self.push_value(Value::Function(self.create_callback_function(m)?));
push_string(self.state, "__index")?;
protect_lua_closure(self.state, 0, 1, |state| {
ffi::lua_newtable(state);
})?;
for (k, m) in methods.methods {
push_string(self.state, &k)?;
self.push_value(Value::Function(self.create_callback_function(m)?));
protect_lua_closure(self.state, 3, 1, |state| {
ffi::lua_rawset(state, -3);
})?;
}
protect_lua_closure(self.state, 3, 1, |state| { protect_lua_closure(self.state, 3, 1, |state| {
ffi::lua_rawset(state, -3); ffi::lua_rawset(state, -3);
})?; })?;
} }
for (k, m) in methods.meta_methods { protect_lua_closure(self.state, 3, 1, |state| {
if k == MetaMethod::Index && has_methods { ffi::lua_rawset(state, -3);
push_string(self.state, "__index")?; })?;
ffi::lua_pushvalue(self.state, -1); }
ffi::lua_gettable(self.state, -3);
self.push_value(Value::Function(self.create_callback_function(m)?));
protect_lua_closure(self.state, 2, 1, |state| {
ffi::lua_pushcclosure(state, meta_index_impl, 2);
})?;
protect_lua_closure(self.state, 3, 1, |state| { for (k, m) in methods.meta_methods {
ffi::lua_rawset(state, -3); if k == MetaMethod::Index && has_methods {
})?; push_string(self.state, "__index")?;
} else { ffi::lua_pushvalue(self.state, -1);
let name = match k { ffi::lua_gettable(self.state, -3);
MetaMethod::Add => "__add", self.push_value(Value::Function(self.create_callback_function(m)?));
MetaMethod::Sub => "__sub", protect_lua_closure(self.state, 2, 1, |state| {
MetaMethod::Mul => "__mul", ffi::lua_pushcclosure(state, meta_index_impl, 2);
MetaMethod::Div => "__div", })?;
MetaMethod::Mod => "__mod",
MetaMethod::Pow => "__pow", protect_lua_closure(self.state, 3, 1, |state| {
MetaMethod::Unm => "__unm", ffi::lua_rawset(state, -3);
MetaMethod::IDiv => "__idiv", })?;
MetaMethod::BAnd => "__band", } else {
MetaMethod::BOr => "__bor", let name = match k {
MetaMethod::BXor => "__bxor", MetaMethod::Add => "__add",
MetaMethod::BNot => "__bnot", MetaMethod::Sub => "__sub",
MetaMethod::Shl => "__shl", MetaMethod::Mul => "__mul",
MetaMethod::Shr => "__shr", MetaMethod::Div => "__div",
MetaMethod::Concat => "__concat", MetaMethod::Mod => "__mod",
MetaMethod::Len => "__len", MetaMethod::Pow => "__pow",
MetaMethod::Eq => "__eq", MetaMethod::Unm => "__unm",
MetaMethod::Lt => "__lt", MetaMethod::IDiv => "__idiv",
MetaMethod::Le => "__le", MetaMethod::BAnd => "__band",
MetaMethod::Index => "__index", MetaMethod::BOr => "__bor",
MetaMethod::NewIndex => "__newindex", MetaMethod::BXor => "__bxor",
MetaMethod::Call => "__call", MetaMethod::BNot => "__bnot",
MetaMethod::ToString => "__tostring", MetaMethod::Shl => "__shl",
}; MetaMethod::Shr => "__shr",
push_string(self.state, name)?; MetaMethod::Concat => "__concat",
self.push_value(Value::Function(self.create_callback_function(m)?)); MetaMethod::Len => "__len",
protect_lua_closure(self.state, 3, 1, |state| { MetaMethod::Eq => "__eq",
ffi::lua_rawset(state, -3); MetaMethod::Lt => "__lt",
})?; MetaMethod::Le => "__le",
} MetaMethod::Index => "__index",
MetaMethod::NewIndex => "__newindex",
MetaMethod::Call => "__call",
MetaMethod::ToString => "__tostring",
};
push_string(self.state, name)?;
self.push_value(Value::Function(self.create_callback_function(m)?));
protect_lua_closure(self.state, 3, 1, |state| {
ffi::lua_rawset(state, -3);
})?;
} }
}
push_string(self.state, "__gc")?; push_string(self.state, "__gc")?;
ffi::lua_pushcfunction(self.state, userdata_destructor::<RefCell<T>>); ffi::lua_pushcfunction(self.state, userdata_destructor::<RefCell<T>>);
protect_lua_closure(self.state, 3, 1, |state| { protect_lua_closure(self.state, 3, 1, |state| {
ffi::lua_rawset(state, -3); ffi::lua_rawset(state, -3);
})?; })?;
push_string(self.state, "__metatable")?; push_string(self.state, "__metatable")?;
ffi::lua_pushboolean(self.state, 0); ffi::lua_pushboolean(self.state, 0);
protect_lua_closure(self.state, 3, 1, |state| { protect_lua_closure(self.state, 3, 1, |state| {
ffi::lua_rawset(state, -3); ffi::lua_rawset(state, -3);
})?; })?;
let id = gc_guard(self.state, || { let id = gc_guard(self.state, || {
ffi::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX) ffi::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX)
}); });
(*self.extra()) (*self.extra())
.registered_userdata .registered_userdata
.insert(TypeId::of::<T>(), id); .insert(TypeId::of::<T>(), id);
Ok(id) Ok(id)
})
} }
unsafe fn create_lua(load_debug: bool) -> Lua { unsafe fn create_lua(load_debug: bool) -> Lua {
@ -1125,24 +1115,23 @@ impl Lua {
} }
unsafe { unsafe {
stack_guard(self.state, move || { let _sg = StackGuard::new(self.state);
check_stack(self.state, 4); check_stack(self.state, 4);
push_userdata::<Callback>(self.state, func)?; push_userdata::<Callback>(self.state, func)?;
ffi::lua_pushlightuserdata( ffi::lua_pushlightuserdata(
self.state, self.state,
&FUNCTION_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void, &FUNCTION_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void,
); );
ffi::lua_rawget(self.state, ffi::LUA_REGISTRYINDEX); ffi::lua_rawget(self.state, ffi::LUA_REGISTRYINDEX);
ffi::lua_setmetatable(self.state, -2); ffi::lua_setmetatable(self.state, -2);
protect_lua_closure(self.state, 1, 1, |state| { protect_lua_closure(self.state, 1, 1, |state| {
ffi::lua_pushcclosure(state, callback_call_impl, 1); ffi::lua_pushcclosure(state, callback_call_impl, 1);
})?; })?;
Ok(Function(self.pop_ref())) Ok(Function(self.pop_ref()))
})
} }
} }
@ -1151,21 +1140,20 @@ impl Lua {
T: UserData, T: UserData,
{ {
unsafe { unsafe {
stack_guard(self.state, move || { let _sg = StackGuard::new(self.state);
check_stack(self.state, 4); check_stack(self.state, 4);
push_userdata::<RefCell<T>>(self.state, RefCell::new(data))?; push_userdata::<RefCell<T>>(self.state, RefCell::new(data))?;
ffi::lua_rawgeti( ffi::lua_rawgeti(
self.state, self.state,
ffi::LUA_REGISTRYINDEX, 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); ffi::lua_setmetatable(self.state, -2);
Ok(AnyUserData(self.pop_ref())) Ok(AnyUserData(self.pop_ref()))
})
} }
} }
@ -1290,19 +1278,18 @@ impl<'scope> Scope<'scope> {
let f_destruct = f.0.clone(); let f_destruct = f.0.clone();
destructors.push(Box::new(move || { destructors.push(Box::new(move || {
let state = f_destruct.lua.state; let state = f_destruct.lua.state;
stack_guard(state, || { let _sg = StackGuard::new(state);
check_stack(state, 2); check_stack(state, 2);
f_destruct.lua.push_ref(&f_destruct); f_destruct.lua.push_ref(&f_destruct);
ffi::lua_getupvalue(state, -1, 1); ffi::lua_getupvalue(state, -1, 1);
let ud = take_userdata::<Callback>(state); let ud = take_userdata::<Callback>(state);
ffi::lua_pushnil(state); ffi::lua_pushnil(state);
ffi::lua_setupvalue(state, -2, 1); ffi::lua_setupvalue(state, -2, 1);
ffi::lua_pop(state, 1); ffi::lua_pop(state, 1);
Box::new(ud) Box::new(ud)
})
})); }));
Ok(f) Ok(f)
} }
@ -1348,11 +1335,10 @@ impl<'scope> Scope<'scope> {
let u_destruct = u.0.clone(); let u_destruct = u.0.clone();
destructors.push(Box::new(move || { destructors.push(Box::new(move || {
let state = u_destruct.lua.state; let state = u_destruct.lua.state;
stack_guard(state, || { let _sg = StackGuard::new(state);
check_stack(state, 1); check_stack(state, 1);
u_destruct.lua.push_ref(&u_destruct); u_destruct.lua.push_ref(&u_destruct);
Box::new(take_userdata::<RefCell<T>>(state)) Box::new(take_userdata::<RefCell<T>>(state))
})
})); }));
Ok(u) Ok(u)
} }

View File

@ -2,7 +2,7 @@ use std::{slice, str};
use ffi; use ffi;
use error::{Error, Result}; use error::{Error, Result};
use util::{check_stack, stack_guard}; use util::{check_stack, StackGuard};
use types::LuaRef; use types::LuaRef;
/// Handle to an internal Lua string. /// Handle to an internal Lua string.
@ -69,21 +69,21 @@ impl<'lua> String<'lua> {
pub fn as_bytes_with_nul(&self) -> &[u8] { pub fn as_bytes_with_nul(&self) -> &[u8] {
let lua = self.0.lua; let lua = self.0.lua;
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 1); check_stack(lua.state, 1);
lua.push_ref(&self.0);
rlua_assert!(
ffi::lua_type(lua.state, -1) == ffi::LUA_TSTRING,
"string ref is not string type"
);
let mut size = 0; lua.push_ref(&self.0);
// This will not trigger a 'm' error, because the reference is guaranteed to be of rlua_assert!(
// string type ffi::lua_type(lua.state, -1) == ffi::LUA_TSTRING,
let data = ffi::lua_tolstring(lua.state, -1, &mut size); "string ref is not string type"
);
slice::from_raw_parts(data as *const u8, size + 1) let mut size = 0;
}) // This will not trigger a 'm' error, because the reference is guaranteed to be of
// string type
let data = ffi::lua_tolstring(lua.state, -1, &mut size);
slice::from_raw_parts(data as *const u8, size + 1)
} }
} }
} }

View File

@ -3,7 +3,7 @@ use std::os::raw::c_int;
use ffi; use ffi;
use error::Result; use error::Result;
use util::{check_stack, protect_lua, protect_lua_closure, stack_guard}; use util::{check_stack, protect_lua, protect_lua_closure, StackGuard};
use types::{Integer, LuaRef, RefType}; use types::{Integer, LuaRef, RefType};
use value::{FromLua, ToLua}; use value::{FromLua, ToLua};
@ -52,18 +52,18 @@ impl<'lua> Table<'lua> {
pub fn set<K: ToLua<'lua>, V: ToLua<'lua>>(&self, key: K, value: V) -> Result<()> { pub fn set<K: ToLua<'lua>, V: ToLua<'lua>>(&self, key: K, value: V) -> Result<()> {
let lua = self.0.lua; let lua = self.0.lua;
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 6); check_stack(lua.state, 6);
lua.push_ref(&self.0);
lua.push_value(key.to_lua(lua)?);
lua.push_value(value.to_lua(lua)?);
unsafe extern "C" fn set_table(state: *mut ffi::lua_State) -> c_int { lua.push_ref(&self.0);
ffi::lua_settable(state, -3); lua.push_value(key.to_lua(lua)?);
1 lua.push_value(value.to_lua(lua)?);
}
protect_lua(lua.state, 3, set_table) unsafe extern "C" fn set_table(state: *mut ffi::lua_State) -> c_int {
}) ffi::lua_settable(state, -3);
1
}
protect_lua(lua.state, 3, set_table)
} }
} }
@ -98,19 +98,19 @@ impl<'lua> Table<'lua> {
pub fn get<K: ToLua<'lua>, V: FromLua<'lua>>(&self, key: K) -> Result<V> { pub fn get<K: ToLua<'lua>, V: FromLua<'lua>>(&self, key: K) -> Result<V> {
let lua = self.0.lua; let lua = self.0.lua;
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 5); check_stack(lua.state, 5);
lua.push_ref(&self.0);
lua.push_value(key.to_lua(lua)?);
unsafe extern "C" fn get_table(state: *mut ffi::lua_State) -> c_int { lua.push_ref(&self.0);
ffi::lua_gettable(state, -2); lua.push_value(key.to_lua(lua)?);
1
}
protect_lua(lua.state, 2, get_table)?;
V::from_lua(lua.pop_value(), lua) unsafe extern "C" fn get_table(state: *mut ffi::lua_State) -> c_int {
}) ffi::lua_gettable(state, -2);
1
}
protect_lua(lua.state, 2, get_table)?;
V::from_lua(lua.pop_value(), lua)
} }
} }
@ -118,20 +118,20 @@ impl<'lua> Table<'lua> {
pub fn contains_key<K: ToLua<'lua>>(&self, key: K) -> Result<bool> { pub fn contains_key<K: ToLua<'lua>>(&self, key: K) -> Result<bool> {
let lua = self.0.lua; let lua = self.0.lua;
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 5); check_stack(lua.state, 5);
lua.push_ref(&self.0);
lua.push_value(key.to_lua(lua)?);
unsafe extern "C" fn get_table(state: *mut ffi::lua_State) -> c_int { lua.push_ref(&self.0);
ffi::lua_gettable(state, -2); lua.push_value(key.to_lua(lua)?);
1
}
protect_lua(lua.state, 2, get_table)?;
let has = ffi::lua_isnil(lua.state, -1) == 0; unsafe extern "C" fn get_table(state: *mut ffi::lua_State) -> c_int {
Ok(has) ffi::lua_gettable(state, -2);
}) 1
}
protect_lua(lua.state, 2, get_table)?;
let has = ffi::lua_isnil(lua.state, -1) == 0;
Ok(has)
} }
} }
@ -139,20 +139,20 @@ impl<'lua> Table<'lua> {
pub fn raw_set<K: ToLua<'lua>, V: ToLua<'lua>>(&self, key: K, value: V) -> Result<()> { pub fn raw_set<K: ToLua<'lua>, V: ToLua<'lua>>(&self, key: K, value: V) -> Result<()> {
let lua = self.0.lua; let lua = self.0.lua;
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 6); check_stack(lua.state, 6);
lua.push_ref(&self.0);
lua.push_value(key.to_lua(lua)?);
lua.push_value(value.to_lua(lua)?);
unsafe extern "C" fn raw_set(state: *mut ffi::lua_State) -> c_int { lua.push_ref(&self.0);
ffi::lua_rawset(state, -3); lua.push_value(key.to_lua(lua)?);
0 lua.push_value(value.to_lua(lua)?);
}
protect_lua(lua.state, 3, raw_set)?;
Ok(()) unsafe extern "C" fn raw_set(state: *mut ffi::lua_State) -> c_int {
}) ffi::lua_rawset(state, -3);
0
}
protect_lua(lua.state, 3, raw_set)?;
Ok(())
} }
} }
@ -160,14 +160,14 @@ impl<'lua> Table<'lua> {
pub fn raw_get<K: ToLua<'lua>, V: FromLua<'lua>>(&self, key: K) -> Result<V> { pub fn raw_get<K: ToLua<'lua>, V: FromLua<'lua>>(&self, key: K) -> Result<V> {
let lua = self.0.lua; let lua = self.0.lua;
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 3); check_stack(lua.state, 3);
lua.push_ref(&self.0);
lua.push_value(key.to_lua(lua)?); lua.push_ref(&self.0);
ffi::lua_rawget(lua.state, -2); lua.push_value(key.to_lua(lua)?);
let res = V::from_lua(lua.pop_value(), lua)?; ffi::lua_rawget(lua.state, -2);
Ok(res) let res = V::from_lua(lua.pop_value(), lua)?;
}) Ok(res)
} }
} }
@ -179,11 +179,10 @@ impl<'lua> Table<'lua> {
pub fn len(&self) -> Result<Integer> { pub fn len(&self) -> Result<Integer> {
let lua = self.0.lua; let lua = self.0.lua;
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 4); check_stack(lua.state, 4);
lua.push_ref(&self.0); lua.push_ref(&self.0);
protect_lua_closure(lua.state, 1, 0, |state| ffi::luaL_len(state, -1)) protect_lua_closure(lua.state, 1, 0, |state| ffi::luaL_len(state, -1))
})
} }
} }
@ -191,12 +190,11 @@ impl<'lua> Table<'lua> {
pub fn raw_len(&self) -> Integer { pub fn raw_len(&self) -> Integer {
let lua = self.0.lua; let lua = self.0.lua;
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 1); check_stack(lua.state, 1);
lua.push_ref(&self.0); lua.push_ref(&self.0);
let len = ffi::lua_rawlen(lua.state, -1); let len = ffi::lua_rawlen(lua.state, -1);
len as Integer len as Integer
})
} }
} }
@ -206,16 +204,15 @@ impl<'lua> Table<'lua> {
pub fn get_metatable(&self) -> Option<Table<'lua>> { pub fn get_metatable(&self) -> Option<Table<'lua>> {
let lua = self.0.lua; let lua = self.0.lua;
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 1); check_stack(lua.state, 1);
lua.push_ref(&self.0); lua.push_ref(&self.0);
if ffi::lua_getmetatable(lua.state, -1) == 0 { if ffi::lua_getmetatable(lua.state, -1) == 0 {
None None
} else { } else {
let table = Table(lua.pop_ref()); let table = Table(lua.pop_ref());
Some(table) Some(table)
} }
})
} }
} }
@ -226,16 +223,15 @@ impl<'lua> Table<'lua> {
pub fn set_metatable(&self, metatable: Option<Table<'lua>>) { pub fn set_metatable(&self, metatable: Option<Table<'lua>>) {
let lua = self.0.lua; let lua = self.0.lua;
unsafe { unsafe {
stack_guard(lua.state, move || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 1); check_stack(lua.state, 1);
lua.push_ref(&self.0); lua.push_ref(&self.0);
if let Some(metatable) = metatable { if let Some(metatable) = metatable {
lua.push_ref(&metatable.0); lua.push_ref(&metatable.0);
} else { } else {
ffi::lua_pushnil(lua.state); ffi::lua_pushnil(lua.state);
} }
ffi::lua_setmetatable(lua.state, -2); ffi::lua_setmetatable(lua.state, -2);
})
} }
} }
@ -359,31 +355,30 @@ where
let lua = self.table.lua; let lua = self.table.lua;
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 6); check_stack(lua.state, 6);
lua.push_ref(&self.table); lua.push_ref(&self.table);
lua.push_ref(&next_key); lua.push_ref(&next_key);
match protect_lua_closure(lua.state, 2, ffi::LUA_MULTRET, |state| { match protect_lua_closure(lua.state, 2, ffi::LUA_MULTRET, |state| {
ffi::lua_next(state, -2) != 0 ffi::lua_next(state, -2) != 0
}) { }) {
Ok(false) => None, Ok(false) => None,
Ok(true) => { Ok(true) => {
ffi::lua_pushvalue(lua.state, -2); ffi::lua_pushvalue(lua.state, -2);
let key = lua.pop_value(); let key = lua.pop_value();
let value = lua.pop_value(); let value = lua.pop_value();
self.next_key = Some(lua.pop_ref()); self.next_key = Some(lua.pop_ref());
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)),
} }
}) Err(e) => Some(Err(e)),
}
} }
} else { } else {
None None
@ -413,22 +408,20 @@ where
let lua = self.table.lua; let lua = self.table.lua;
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 5); check_stack(lua.state, 5);
lua.push_ref(&self.table); lua.push_ref(&self.table);
match protect_lua_closure(lua.state, 1, 1, |state| { match protect_lua_closure(lua.state, 1, 1, |state| ffi::lua_geti(state, -1, index))
ffi::lua_geti(state, -1, index) {
}) { Ok(ffi::LUA_TNIL) => None,
Ok(ffi::LUA_TNIL) => None, Ok(_) => {
Ok(_) => { let value = lua.pop_value();
let value = lua.pop_value(); self.index = Some(index + 1);
self.index = Some(index + 1); Some(V::from_lua(value, lua))
Some(V::from_lua(value, lua))
}
Err(err) => Some(Err(err)),
} }
}) Err(err) => Some(Err(err)),
}
} }
} else { } else {
None None

View File

@ -2,7 +2,7 @@ use std::os::raw::c_int;
use ffi; use ffi;
use error::{Error, Result}; use error::{Error, Result};
use util::{check_stack, check_stack_err, error_traceback, pop_error, stack_guard}; use util::{check_stack, check_stack_err, error_traceback, pop_error, StackGuard};
use types::LuaRef; use types::LuaRef;
use value::{FromLuaMulti, MultiValue, ToLuaMulti}; use value::{FromLuaMulti, MultiValue, ToLuaMulti};
@ -78,45 +78,44 @@ impl<'lua> Thread<'lua> {
{ {
let lua = self.0.lua; let lua = self.0.lua;
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 1); check_stack(lua.state, 1);
lua.push_ref(&self.0); lua.push_ref(&self.0);
let thread_state = ffi::lua_tothread(lua.state, -1); let thread_state = ffi::lua_tothread(lua.state, -1);
let status = ffi::lua_status(thread_state); let status = ffi::lua_status(thread_state);
if status != ffi::LUA_YIELD && ffi::lua_gettop(thread_state) == 0 { if status != ffi::LUA_YIELD && ffi::lua_gettop(thread_state) == 0 {
return Err(Error::CoroutineInactive); return Err(Error::CoroutineInactive);
} }
ffi::lua_pop(lua.state, 1); ffi::lua_pop(lua.state, 1);
let args = args.to_lua_multi(lua)?; let args = args.to_lua_multi(lua)?;
let nargs = args.len() as c_int; let nargs = args.len() as c_int;
check_stack_err(lua.state, nargs)?; check_stack_err(lua.state, nargs)?;
check_stack_err(thread_state, nargs + 1)?; check_stack_err(thread_state, nargs + 1)?;
for arg in args { for arg in args {
lua.push_value(arg); lua.push_value(arg);
} }
ffi::lua_xmove(lua.state, thread_state, nargs); ffi::lua_xmove(lua.state, thread_state, nargs);
let ret = ffi::lua_resume(thread_state, lua.state, nargs); let ret = ffi::lua_resume(thread_state, lua.state, nargs);
if ret != ffi::LUA_OK && ret != ffi::LUA_YIELD { if ret != ffi::LUA_OK && ret != ffi::LUA_YIELD {
error_traceback(thread_state); error_traceback(thread_state);
return Err(pop_error(thread_state, ret)); return Err(pop_error(thread_state, ret));
} }
let nresults = ffi::lua_gettop(thread_state); let nresults = ffi::lua_gettop(thread_state);
let mut results = MultiValue::new(); let mut results = MultiValue::new();
ffi::lua_xmove(thread_state, lua.state, nresults); ffi::lua_xmove(thread_state, lua.state, nresults);
check_stack(lua.state, 2); check_stack(lua.state, 2);
for _ in 0..nresults { for _ in 0..nresults {
results.push_front(lua.pop_value()); results.push_front(lua.pop_value());
} }
R::from_lua_multi(results, lua) R::from_lua_multi(results, lua)
})
} }
} }
@ -124,22 +123,21 @@ impl<'lua> Thread<'lua> {
pub fn status(&self) -> ThreadStatus { pub fn status(&self) -> ThreadStatus {
let lua = self.0.lua; let lua = self.0.lua;
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 1); check_stack(lua.state, 1);
lua.push_ref(&self.0); lua.push_ref(&self.0);
let thread_state = ffi::lua_tothread(lua.state, -1); let thread_state = ffi::lua_tothread(lua.state, -1);
ffi::lua_pop(lua.state, 1); ffi::lua_pop(lua.state, 1);
let status = ffi::lua_status(thread_state); let status = ffi::lua_status(thread_state);
if status != ffi::LUA_OK && status != ffi::LUA_YIELD { if status != ffi::LUA_OK && status != ffi::LUA_YIELD {
ThreadStatus::Error ThreadStatus::Error
} else if status == ffi::LUA_YIELD || ffi::lua_gettop(thread_state) > 0 { } else if status == ffi::LUA_YIELD || ffi::lua_gettop(thread_state) > 0 {
ThreadStatus::Resumable ThreadStatus::Resumable
} else { } else {
ThreadStatus::Unresumable ThreadStatus::Unresumable
} }
})
} }
} }
} }

View File

@ -5,7 +5,7 @@ use std::string::String as StdString;
use ffi; use ffi;
use error::{Error, Result}; use error::{Error, Result};
use util::{check_stack, get_userdata, stack_guard}; use util::{check_stack, get_userdata, StackGuard};
use types::{Callback, LuaRef}; use types::{Callback, LuaRef};
use value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti}; use value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti};
use lua::Lua; use lua::Lua;
@ -415,29 +415,28 @@ impl<'lua> AnyUserData<'lua> {
{ {
unsafe { unsafe {
let lua = self.0.lua; let lua = self.0.lua;
stack_guard(lua.state, move || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 3); check_stack(lua.state, 3);
lua.push_ref(&self.0); lua.push_ref(&self.0);
rlua_assert!( rlua_assert!(
ffi::lua_getmetatable(lua.state, -1) != 0, ffi::lua_getmetatable(lua.state, -1) != 0,
"AnyUserData missing metatable" "AnyUserData missing metatable"
); );
ffi::lua_rawgeti( ffi::lua_rawgeti(
lua.state, lua.state,
ffi::LUA_REGISTRYINDEX, 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 { if ffi::lua_rawequal(lua.state, -1, -2) == 0 {
Err(Error::UserDataTypeMismatch) Err(Error::UserDataTypeMismatch)
} else { } else {
let res = func(&*get_userdata::<RefCell<T>>(lua.state, -3)); let res = func(&*get_userdata::<RefCell<T>>(lua.state, -3));
res res
} }
})
} }
} }
@ -449,13 +448,12 @@ impl<'lua> AnyUserData<'lua> {
pub fn set_user_value<V: ToLua<'lua>>(&self, v: V) -> Result<()> { pub fn set_user_value<V: ToLua<'lua>>(&self, v: V) -> Result<()> {
let lua = self.0.lua; let lua = self.0.lua;
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 2); check_stack(lua.state, 2);
lua.push_ref(&self.0); lua.push_ref(&self.0);
lua.push_value(v.to_lua(lua)?); lua.push_value(v.to_lua(lua)?);
ffi::lua_setuservalue(lua.state, -2); ffi::lua_setuservalue(lua.state, -2);
Ok(()) Ok(())
})
} }
} }
@ -465,13 +463,12 @@ impl<'lua> AnyUserData<'lua> {
pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> { pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> {
let lua = self.0.lua; let lua = self.0.lua;
unsafe { unsafe {
stack_guard(lua.state, || { let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 3); check_stack(lua.state, 3);
lua.push_ref(&self.0); lua.push_ref(&self.0);
ffi::lua_getuservalue(lua.state, -1); ffi::lua_getuservalue(lua.state, -1);
let res = V::from_lua(lua.pop_value(), lua)?; let res = V::from_lua(lua.pop_value(), lua)?;
Ok(res) Ok(res)
})
} }
} }
} }

View File

@ -57,15 +57,6 @@ impl Drop for StackGuard {
} }
} }
// Run an operation on a lua_State and restores the stack state at the end, using `StackGuard`.
pub unsafe fn stack_guard<F, R>(state: *mut ffi::lua_State, op: F) -> R
where
F: FnOnce() -> R,
{
let _stack_guard = StackGuard::new(state);
op()
}
// Call a function that calls into the Lua API and may trigger a Lua error (longjmp) in a safe way. // Call a function that calls into the Lua API and may trigger a Lua error (longjmp) in a safe way.
// Wraps the inner function in a call to `lua_pcall`, so the inner function only has access to a // Wraps the inner function in a call to `lua_pcall`, so the inner function only has access to a
// limited lua stack. `nargs` is the same as the the parameter to `lua_pcall`, and `nresults` is // limited lua stack. `nargs` is the same as the the parameter to `lua_pcall`, and `nresults` is