diff --git a/benches/benchmark.rs b/benches/benchmark.rs index f3d0e9f..9a1f083 100644 --- a/benches/benchmark.rs +++ b/benches/benchmark.rs @@ -170,9 +170,7 @@ fn create_registry_values(c: &mut Criterion) { } fn create_userdata(c: &mut Criterion) { - struct UserData { - i: i64, - } + struct UserData(i64); impl LuaUserData for UserData {} c.bench_function("create userdata 10", |b| { @@ -182,7 +180,7 @@ fn create_userdata(c: &mut Criterion) { { let table: LuaTable = lua.create_table().unwrap(); for i in 1..11 { - table.set(i, UserData { i }).unwrap(); + table.set(i, UserData(i)).unwrap(); } } lua diff --git a/src/function.rs b/src/function.rs index 0f97dac..f4484d9 100644 --- a/src/function.rs +++ b/src/function.rs @@ -4,7 +4,7 @@ use std::os::raw::c_int; use ffi; use error::{Error, Result}; use util::{check_stack, check_stack_err, error_traceback, pop_error, protect_lua_closure, - stack_guard}; + StackGuard}; use types::LuaRef; use value::{FromLuaMulti, MultiValue, ToLuaMulti}; @@ -63,31 +63,32 @@ impl<'lua> Function<'lua> { /// ``` pub fn call, R: FromLuaMulti<'lua>>(&self, args: A) -> Result { 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 stack_start = ffi::lua_gettop(lua.state); - lua.push_ref(&self.0); - for arg in args { - lua.push_value(arg); - } - let ret = ffi::lua_pcall(lua.state, nargs, ffi::LUA_MULTRET, stack_start); - if ret != ffi::LUA_OK { - return Err(pop_error(lua.state, ret)); - } - 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) - }) + let args = args.to_lua_multi(lua)?; + let nargs = args.len() as c_int; + + unsafe { + let _sg = StackGuard::new(lua.state); + check_stack_err(lua.state, nargs + 3)?; + + ffi::lua_pushcfunction(lua.state, error_traceback); + let stack_start = ffi::lua_gettop(lua.state); + lua.push_ref(&self.0); + for arg in args { + lua.push_value(arg); + } + let ret = ffi::lua_pcall(lua.state, nargs, ffi::LUA_MULTRET, stack_start); + if ret != ffi::LUA_OK { + return Err(pop_error(lua.state, ret)); + } + 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 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 { - stack_guard(lua.state, || { - let args = args.to_lua_multi(lua)?; - let nargs = args.len() as c_int; + let _sg = StackGuard::new(lua.state); + check_stack_err(lua.state, nargs + 5)?; + 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 { - return Err(Error::BindError); - } + protect_lua_closure(lua.state, nargs + 2, 1, |state| { + ffi::lua_pushcclosure(state, bind_call_impl, nargs + 2); + })?; - check_stack_err(lua.state, nargs + 5)?; - 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())) - }) + Ok(Function(lua.pop_ref())) } } } diff --git a/src/lua.rs b/src/lua.rs index 767f507..cef2779 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -14,8 +14,8 @@ use ffi; use error::{Error, Result}; 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, - push_string, push_userdata, push_wrapped_error, safe_pcall, safe_xpcall, stack_guard, - take_userdata, userdata_destructor}; + push_string, push_userdata, push_wrapped_error, safe_pcall, safe_xpcall, take_userdata, + userdata_destructor, StackGuard}; use value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value}; use types::{Callback, Integer, LightUserData, LuaRef, Number, RefType, RegistryKey}; use string::String; @@ -102,34 +102,33 @@ impl Lua { /// Equivalent to Lua's `load` function. pub fn load(&self, source: &str, name: Option<&str>) -> Result { unsafe { - stack_guard(self.state, || { - check_stack(self.state, 1); + let _sg = StackGuard::new(self.state); + check_stack(self.state, 1); - match if let Some(name) = name { - let name = - CString::new(name.to_owned()).map_err(|e| Error::ToLuaConversionError { - from: "&str", - to: "string", - message: Some(e.to_string()), - })?; - ffi::luaL_loadbuffer( - self.state, - source.as_ptr() as *const c_char, - source.len(), - name.as_ptr(), - ) - } else { - ffi::luaL_loadbuffer( - self.state, - source.as_ptr() as *const c_char, - source.len(), - ptr::null(), - ) - } { - ffi::LUA_OK => Ok(Function(self.pop_ref())), - err => Err(pop_error(self.state, err)), - } - }) + match if let Some(name) = name { + let name = + CString::new(name.to_owned()).map_err(|e| Error::ToLuaConversionError { + from: "&str", + to: "string", + message: Some(e.to_string()), + })?; + ffi::luaL_loadbuffer( + self.state, + source.as_ptr() as *const c_char, + source.len(), + name.as_ptr(), + ) + } else { + ffi::luaL_loadbuffer( + self.state, + source.as_ptr() as *const c_char, + source.len(), + ptr::null(), + ) + } { + ffi::LUA_OK => Ok(Function(self.pop_ref())), + 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. pub fn create_string(&self, s: &str) -> Result { unsafe { - stack_guard(self.state, || { - check_stack(self.state, 4); - push_string(self.state, s)?; - Ok(String(self.pop_ref())) - }) + let _sg = StackGuard::new(self.state); + check_stack(self.state, 4); + push_string(self.state, s)?; + Ok(String(self.pop_ref())) } } /// Creates and returns a new table. pub fn create_table(&self) -> Result { unsafe { - stack_guard(self.state, || { - check_stack(self.state, 3); - 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)?; - Ok(Table(self.pop_ref())) - }) + let _sg = StackGuard::new(self.state); + check_stack(self.state, 3); + 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)?; + Ok(Table(self.pop_ref())) } } @@ -198,25 +195,25 @@ impl Lua { I: IntoIterator, { unsafe { - stack_guard(self.state, || { - check_stack(self.state, 5); - unsafe extern "C" fn new_table(state: *mut ffi::lua_State) -> c_int { - ffi::lua_newtable(state); + let _sg = StackGuard::new(self.state); + check_stack(self.state, 5); + + 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 } - 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 - } - protect_lua(self.state, 3, raw_set)?; - } - Ok(Table(self.pop_ref())) - }) + protect_lua(self.state, 3, raw_set)?; + } + Ok(Table(self.pop_ref())) } } @@ -322,16 +319,15 @@ impl Lua { /// Equivalent to `coroutine.create`. pub fn create_thread<'lua>(&'lua self, func: Function<'lua>) -> Result> { unsafe { - stack_guard(self.state, move || { - check_stack(self.state, 2); + let _sg = StackGuard::new(self.state); + check_stack(self.state, 2); - let thread_state = - protect_lua_closure(self.state, 0, 1, |state| ffi::lua_newthread(state))?; - self.push_ref(&func.0); - ffi::lua_xmove(self.state, thread_state, 1); + let thread_state = + protect_lua_closure(self.state, 0, 1, |state| ffi::lua_newthread(state))?; + self.push_ref(&func.0); + 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. pub fn globals(&self) -> Table { unsafe { - stack_guard(self.state, move || { - check_stack(self.state, 2); - ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS); - Table(self.pop_ref()) - }) + let _sg = StackGuard::new(self.state); + check_stack(self.state, 2); + ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS); + Table(self.pop_ref()) } } @@ -392,23 +387,22 @@ impl Lua { match v { Value::String(s) => Ok(s), v => unsafe { - stack_guard(self.state, || { - check_stack(self.state, 4); - let ty = v.type_name(); - self.push_value(v); - let s = protect_lua_closure(self.state, 1, 1, |state| { - ffi::lua_tostring(state, -1) - })?; - if s.is_null() { - Err(Error::FromLuaConversionError { - from: ty, - to: "String", - message: Some("expected string or number".to_string()), - }) - } else { - Ok(String(self.pop_ref())) - } - }) + let _sg = StackGuard::new(self.state); + check_stack(self.state, 4); + + let ty = v.type_name(); + self.push_value(v); + let s = + protect_lua_closure(self.state, 1, 1, |state| ffi::lua_tostring(state, -1))?; + if s.is_null() { + Err(Error::FromLuaConversionError { + from: ty, + to: "String", + message: Some("expected string or number".to_string()), + }) + } else { + Ok(String(self.pop_ref())) + } }, } } @@ -421,22 +415,22 @@ impl Lua { match v { Value::Integer(i) => Ok(i), v => unsafe { - stack_guard(self.state, || { - check_stack(self.state, 2); - let ty = v.type_name(); - self.push_value(v); - let mut isint = 0; - let i = ffi::lua_tointegerx(self.state, -1, &mut isint); - if isint == 0 { - Err(Error::FromLuaConversionError { - from: ty, - to: "integer", - message: None, - }) - } else { - Ok(i) - } - }) + let _sg = StackGuard::new(self.state); + check_stack(self.state, 2); + + let ty = v.type_name(); + self.push_value(v); + let mut isint = 0; + let i = ffi::lua_tointegerx(self.state, -1, &mut isint); + if isint == 0 { + Err(Error::FromLuaConversionError { + from: ty, + to: "integer", + message: None, + }) + } else { + Ok(i) + } }, } } @@ -449,22 +443,22 @@ impl Lua { match v { Value::Number(n) => Ok(n), v => unsafe { - stack_guard(self.state, || { - check_stack(self.state, 2); - let ty = v.type_name(); - self.push_value(v); - let mut isnum = 0; - let n = ffi::lua_tonumberx(self.state, -1, &mut isnum); - if isnum == 0 { - Err(Error::FromLuaConversionError { - from: ty, - to: "number", - message: Some("number or string coercible to number".to_string()), - }) - } else { - Ok(n) - } - }) + let _sg = StackGuard::new(self.state); + check_stack(self.state, 2); + + let ty = v.type_name(); + self.push_value(v); + let mut isnum = 0; + let n = ffi::lua_tonumberx(self.state, -1, &mut isnum); + if isnum == 0 { + Err(Error::FromLuaConversionError { + from: ty, + to: "number", + message: Some("number or string coercible to number".to_string()), + }) + } else { + Ok(n) + } }, } } @@ -502,18 +496,17 @@ impl Lua { t: T, ) -> Result<()> { unsafe { - stack_guard(self.state, || { - check_stack(self.state, 5); + let _sg = StackGuard::new(self.state); + check_stack(self.state, 5); - push_string(self.state, name)?; - self.push_value(t.to_lua(self)?); + push_string(self.state, name)?; + self.push_value(t.to_lua(self)?); - unsafe extern "C" fn set_registry(state: *mut ffi::lua_State) -> c_int { - ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX); - 0 - } - protect_lua(self.state, 2, set_registry) - }) + unsafe extern "C" fn set_registry(state: *mut ffi::lua_State) -> c_int { + ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX); + 0 + } + protect_lua(self.state, 2, set_registry) } } @@ -525,18 +518,17 @@ impl Lua { /// [`set_named_registry_value`]: #method.set_named_registry_value pub fn named_registry_value<'lua, T: FromLua<'lua>>(&'lua self, name: &str) -> Result { unsafe { - stack_guard(self.state, || { - check_stack(self.state, 4); + let _sg = StackGuard::new(self.state); + check_stack(self.state, 4); - push_string(self.state, name)?; - unsafe extern "C" fn get_registry(state: *mut ffi::lua_State) -> c_int { - ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX); - 1 - } - protect_lua(self.state, 1, get_registry)?; + push_string(self.state, name)?; + unsafe extern "C" fn get_registry(state: *mut ffi::lua_State) -> c_int { + ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX); + 1 + } + 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. pub fn create_registry_value<'lua, T: ToLua<'lua>>(&'lua self, t: T) -> Result { unsafe { - stack_guard(self.state, || { - check_stack(self.state, 2); + let _sg = StackGuard::new(self.state); + check_stack(self.state, 2); - self.push_value(t.to_lua(self)?); - let registry_id = gc_guard(self.state, || { - ffi::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX) - }); + self.push_value(t.to_lua(self)?); + let registry_id = gc_guard(self.state, || { + ffi::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX) + }); - Ok(RegistryKey { - registry_id, - unref_list: (*self.extra()).registry_unref_list.clone(), - }) + Ok(RegistryKey { + registry_id, + unref_list: (*self.extra()).registry_unref_list.clone(), }) } } @@ -583,15 +574,15 @@ impl Lua { return Err(Error::MismatchedRegistryKey); } - stack_guard(self.state, || { - check_stack(self.state, 2); - ffi::lua_rawgeti( - self.state, - ffi::LUA_REGISTRYINDEX, - key.registry_id as ffi::lua_Integer, - ); - T::from_lua(self.pop_value(), self) - }) + let _sg = StackGuard::new(self.state); + check_stack(self.state, 2); + + ffi::lua_rawgeti( + self.state, + ffi::LUA_REGISTRYINDEX, + key.registry_id as ffi::lua_Integer, + ); + 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::()) { - return Ok(*table_id); - } + if let Some(table_id) = (*self.extra()).registered_userdata.get(&TypeId::of::()) { + return Ok(*table_id); + } - check_stack(self.state, 6); + let _sg = StackGuard::new(self.state); + check_stack(self.state, 6); - let mut methods = UserDataMethods { - methods: HashMap::new(), - meta_methods: HashMap::new(), - _type: PhantomData, - }; - T::add_methods(&mut methods); + let mut methods = UserDataMethods { + methods: HashMap::new(), + meta_methods: HashMap::new(), + _type: PhantomData, + }; + 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| { 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| { - 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); - })?; - } - + 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); })?; } - for (k, m) in methods.meta_methods { - if k == MetaMethod::Index && has_methods { - 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| { + ffi::lua_rawset(state, -3); + })?; + } - protect_lua_closure(self.state, 3, 1, |state| { - ffi::lua_rawset(state, -3); - })?; - } else { - let name = match k { - MetaMethod::Add => "__add", - MetaMethod::Sub => "__sub", - MetaMethod::Mul => "__mul", - MetaMethod::Div => "__div", - MetaMethod::Mod => "__mod", - MetaMethod::Pow => "__pow", - MetaMethod::Unm => "__unm", - MetaMethod::IDiv => "__idiv", - MetaMethod::BAnd => "__band", - MetaMethod::BOr => "__bor", - MetaMethod::BXor => "__bxor", - MetaMethod::BNot => "__bnot", - MetaMethod::Shl => "__shl", - MetaMethod::Shr => "__shr", - MetaMethod::Concat => "__concat", - MetaMethod::Len => "__len", - MetaMethod::Eq => "__eq", - 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); - })?; - } + for (k, m) in methods.meta_methods { + if k == MetaMethod::Index && has_methods { + 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| { + ffi::lua_rawset(state, -3); + })?; + } else { + let name = match k { + MetaMethod::Add => "__add", + MetaMethod::Sub => "__sub", + MetaMethod::Mul => "__mul", + MetaMethod::Div => "__div", + MetaMethod::Mod => "__mod", + MetaMethod::Pow => "__pow", + MetaMethod::Unm => "__unm", + MetaMethod::IDiv => "__idiv", + MetaMethod::BAnd => "__band", + MetaMethod::BOr => "__bor", + MetaMethod::BXor => "__bxor", + MetaMethod::BNot => "__bnot", + MetaMethod::Shl => "__shl", + MetaMethod::Shr => "__shr", + MetaMethod::Concat => "__concat", + MetaMethod::Len => "__len", + MetaMethod::Eq => "__eq", + 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")?; - ffi::lua_pushcfunction(self.state, userdata_destructor::>); - protect_lua_closure(self.state, 3, 1, |state| { - ffi::lua_rawset(state, -3); - })?; + push_string(self.state, "__gc")?; + ffi::lua_pushcfunction(self.state, userdata_destructor::>); + protect_lua_closure(self.state, 3, 1, |state| { + ffi::lua_rawset(state, -3); + })?; - push_string(self.state, "__metatable")?; - ffi::lua_pushboolean(self.state, 0); - protect_lua_closure(self.state, 3, 1, |state| { - ffi::lua_rawset(state, -3); - })?; + push_string(self.state, "__metatable")?; + ffi::lua_pushboolean(self.state, 0); + protect_lua_closure(self.state, 3, 1, |state| { + ffi::lua_rawset(state, -3); + })?; - let id = gc_guard(self.state, || { - ffi::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX) - }); - (*self.extra()) - .registered_userdata - .insert(TypeId::of::(), id); - Ok(id) - }) + let id = gc_guard(self.state, || { + ffi::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX) + }); + (*self.extra()) + .registered_userdata + .insert(TypeId::of::(), id); + Ok(id) } unsafe fn create_lua(load_debug: bool) -> Lua { @@ -1125,24 +1115,23 @@ impl Lua { } unsafe { - stack_guard(self.state, move || { - check_stack(self.state, 4); + let _sg = StackGuard::new(self.state); + check_stack(self.state, 4); - push_userdata::(self.state, func)?; + push_userdata::(self.state, func)?; - ffi::lua_pushlightuserdata( - self.state, - &FUNCTION_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void, - ); - ffi::lua_rawget(self.state, ffi::LUA_REGISTRYINDEX); - ffi::lua_setmetatable(self.state, -2); + ffi::lua_pushlightuserdata( + self.state, + &FUNCTION_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void, + ); + ffi::lua_rawget(self.state, ffi::LUA_REGISTRYINDEX); + ffi::lua_setmetatable(self.state, -2); - protect_lua_closure(self.state, 1, 1, |state| { - ffi::lua_pushcclosure(state, callback_call_impl, 1); - })?; + protect_lua_closure(self.state, 1, 1, |state| { + 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, { unsafe { - stack_guard(self.state, move || { - check_stack(self.state, 4); + let _sg = StackGuard::new(self.state); + check_stack(self.state, 4); - push_userdata::>(self.state, RefCell::new(data))?; + push_userdata::>(self.state, RefCell::new(data))?; - ffi::lua_rawgeti( - self.state, - ffi::LUA_REGISTRYINDEX, - self.userdata_metatable::()? as ffi::lua_Integer, - ); + ffi::lua_rawgeti( + self.state, + ffi::LUA_REGISTRYINDEX, + self.userdata_metatable::()? 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(); destructors.push(Box::new(move || { let state = f_destruct.lua.state; - stack_guard(state, || { - check_stack(state, 2); - f_destruct.lua.push_ref(&f_destruct); + let _sg = StackGuard::new(state); + check_stack(state, 2); + f_destruct.lua.push_ref(&f_destruct); - ffi::lua_getupvalue(state, -1, 1); - let ud = take_userdata::(state); + ffi::lua_getupvalue(state, -1, 1); + let ud = take_userdata::(state); - ffi::lua_pushnil(state); - ffi::lua_setupvalue(state, -2, 1); + ffi::lua_pushnil(state); + ffi::lua_setupvalue(state, -2, 1); - ffi::lua_pop(state, 1); - Box::new(ud) - }) + ffi::lua_pop(state, 1); + Box::new(ud) })); Ok(f) } @@ -1348,11 +1335,10 @@ impl<'scope> Scope<'scope> { let u_destruct = u.0.clone(); destructors.push(Box::new(move || { let state = u_destruct.lua.state; - stack_guard(state, || { - check_stack(state, 1); - u_destruct.lua.push_ref(&u_destruct); - Box::new(take_userdata::>(state)) - }) + let _sg = StackGuard::new(state); + check_stack(state, 1); + u_destruct.lua.push_ref(&u_destruct); + Box::new(take_userdata::>(state)) })); Ok(u) } diff --git a/src/string.rs b/src/string.rs index d854b16..1610f3e 100644 --- a/src/string.rs +++ b/src/string.rs @@ -2,7 +2,7 @@ use std::{slice, str}; use ffi; use error::{Error, Result}; -use util::{check_stack, stack_guard}; +use util::{check_stack, StackGuard}; use types::LuaRef; /// Handle to an internal Lua string. @@ -69,21 +69,21 @@ impl<'lua> String<'lua> { pub fn as_bytes_with_nul(&self) -> &[u8] { let lua = self.0.lua; unsafe { - stack_guard(lua.state, || { - 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 _sg = StackGuard::new(lua.state); + check_stack(lua.state, 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); + lua.push_ref(&self.0); + rlua_assert!( + ffi::lua_type(lua.state, -1) == ffi::LUA_TSTRING, + "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) } } } diff --git a/src/table.rs b/src/table.rs index 693e017..3c36a11 100644 --- a/src/table.rs +++ b/src/table.rs @@ -3,7 +3,7 @@ use std::os::raw::c_int; use ffi; 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 value::{FromLua, ToLua}; @@ -52,18 +52,18 @@ impl<'lua> Table<'lua> { pub fn set, V: ToLua<'lua>>(&self, key: K, value: V) -> Result<()> { let lua = self.0.lua; unsafe { - stack_guard(lua.state, || { - check_stack(lua.state, 6); - lua.push_ref(&self.0); - lua.push_value(key.to_lua(lua)?); - lua.push_value(value.to_lua(lua)?); + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 6); - 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) - }) + 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 { + ffi::lua_settable(state, -3); + 1 + } + protect_lua(lua.state, 3, set_table) } } @@ -98,19 +98,19 @@ impl<'lua> Table<'lua> { pub fn get, V: FromLua<'lua>>(&self, key: K) -> Result { let lua = self.0.lua; unsafe { - stack_guard(lua.state, || { - check_stack(lua.state, 5); - lua.push_ref(&self.0); - lua.push_value(key.to_lua(lua)?); + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 5); - 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)?; + lua.push_ref(&self.0); + lua.push_value(key.to_lua(lua)?); - 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>(&self, key: K) -> Result { let lua = self.0.lua; unsafe { - stack_guard(lua.state, || { - check_stack(lua.state, 5); - lua.push_ref(&self.0); - lua.push_value(key.to_lua(lua)?); + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 5); - 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)?; + lua.push_ref(&self.0); + lua.push_value(key.to_lua(lua)?); - let has = ffi::lua_isnil(lua.state, -1) == 0; - Ok(has) - }) + 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)?; + + let has = ffi::lua_isnil(lua.state, -1) == 0; + Ok(has) } } @@ -139,20 +139,20 @@ impl<'lua> Table<'lua> { pub fn raw_set, V: ToLua<'lua>>(&self, key: K, value: V) -> Result<()> { let lua = self.0.lua; unsafe { - stack_guard(lua.state, || { - check_stack(lua.state, 6); - lua.push_ref(&self.0); - lua.push_value(key.to_lua(lua)?); - lua.push_value(value.to_lua(lua)?); + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 6); - 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)?; + lua.push_ref(&self.0); + lua.push_value(key.to_lua(lua)?); + lua.push_value(value.to_lua(lua)?); - 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, V: FromLua<'lua>>(&self, key: K) -> Result { let lua = self.0.lua; unsafe { - stack_guard(lua.state, || { - check_stack(lua.state, 3); - lua.push_ref(&self.0); - lua.push_value(key.to_lua(lua)?); - ffi::lua_rawget(lua.state, -2); - let res = V::from_lua(lua.pop_value(), lua)?; - Ok(res) - }) + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 3); + + lua.push_ref(&self.0); + lua.push_value(key.to_lua(lua)?); + ffi::lua_rawget(lua.state, -2); + let res = V::from_lua(lua.pop_value(), lua)?; + Ok(res) } } @@ -179,11 +179,10 @@ impl<'lua> Table<'lua> { pub fn len(&self) -> Result { let lua = self.0.lua; unsafe { - stack_guard(lua.state, || { - check_stack(lua.state, 4); - lua.push_ref(&self.0); - protect_lua_closure(lua.state, 1, 0, |state| ffi::luaL_len(state, -1)) - }) + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 4); + lua.push_ref(&self.0); + 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 { let lua = self.0.lua; unsafe { - stack_guard(lua.state, || { - check_stack(lua.state, 1); - lua.push_ref(&self.0); - let len = ffi::lua_rawlen(lua.state, -1); - len as Integer - }) + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 1); + lua.push_ref(&self.0); + let len = ffi::lua_rawlen(lua.state, -1); + len as Integer } } @@ -206,16 +204,15 @@ impl<'lua> Table<'lua> { pub fn get_metatable(&self) -> Option> { let lua = self.0.lua; unsafe { - stack_guard(lua.state, || { - check_stack(lua.state, 1); - lua.push_ref(&self.0); - if ffi::lua_getmetatable(lua.state, -1) == 0 { - None - } else { - let table = Table(lua.pop_ref()); - Some(table) - } - }) + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 1); + lua.push_ref(&self.0); + if ffi::lua_getmetatable(lua.state, -1) == 0 { + None + } else { + let table = Table(lua.pop_ref()); + Some(table) + } } } @@ -226,16 +223,15 @@ impl<'lua> Table<'lua> { pub fn set_metatable(&self, metatable: Option>) { let lua = self.0.lua; unsafe { - stack_guard(lua.state, move || { - check_stack(lua.state, 1); - lua.push_ref(&self.0); - if let Some(metatable) = metatable { - lua.push_ref(&metatable.0); - } else { - ffi::lua_pushnil(lua.state); - } - ffi::lua_setmetatable(lua.state, -2); - }) + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 1); + lua.push_ref(&self.0); + if let Some(metatable) = metatable { + lua.push_ref(&metatable.0); + } else { + ffi::lua_pushnil(lua.state); + } + ffi::lua_setmetatable(lua.state, -2); } } @@ -359,31 +355,30 @@ where let lua = self.table.lua; unsafe { - stack_guard(lua.state, || { - check_stack(lua.state, 6); + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 6); - lua.push_ref(&self.table); - lua.push_ref(&next_key); + lua.push_ref(&self.table); + lua.push_ref(&next_key); - match protect_lua_closure(lua.state, 2, ffi::LUA_MULTRET, |state| { - ffi::lua_next(state, -2) != 0 - }) { - Ok(false) => None, - Ok(true) => { - ffi::lua_pushvalue(lua.state, -2); - let key = lua.pop_value(); - let value = lua.pop_value(); - self.next_key = Some(lua.pop_ref()); + match protect_lua_closure(lua.state, 2, ffi::LUA_MULTRET, |state| { + ffi::lua_next(state, -2) != 0 + }) { + Ok(false) => None, + Ok(true) => { + ffi::lua_pushvalue(lua.state, -2); + let key = lua.pop_value(); + let value = lua.pop_value(); + self.next_key = Some(lua.pop_ref()); - Some((|| { - let key = K::from_lua(key, lua)?; - let value = V::from_lua(value, lua)?; - Ok((key, value)) - })()) - } - Err(e) => Some(Err(e)), + Some((|| { + let key = K::from_lua(key, lua)?; + let value = V::from_lua(value, lua)?; + Ok((key, value)) + })()) } - }) + Err(e) => Some(Err(e)), + } } } else { None @@ -413,22 +408,20 @@ where let lua = self.table.lua; unsafe { - stack_guard(lua.state, || { - check_stack(lua.state, 5); + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 5); - lua.push_ref(&self.table); - match protect_lua_closure(lua.state, 1, 1, |state| { - ffi::lua_geti(state, -1, index) - }) { - Ok(ffi::LUA_TNIL) => None, - Ok(_) => { - let value = lua.pop_value(); - self.index = Some(index + 1); - Some(V::from_lua(value, lua)) - } - Err(err) => Some(Err(err)), + lua.push_ref(&self.table); + match protect_lua_closure(lua.state, 1, 1, |state| ffi::lua_geti(state, -1, index)) + { + Ok(ffi::LUA_TNIL) => None, + Ok(_) => { + let value = lua.pop_value(); + self.index = Some(index + 1); + Some(V::from_lua(value, lua)) } - }) + Err(err) => Some(Err(err)), + } } } else { None diff --git a/src/thread.rs b/src/thread.rs index 7174240..cb87873 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -2,7 +2,7 @@ use std::os::raw::c_int; use ffi; 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 value::{FromLuaMulti, MultiValue, ToLuaMulti}; @@ -78,45 +78,44 @@ impl<'lua> Thread<'lua> { { let lua = self.0.lua; unsafe { - stack_guard(lua.state, || { - check_stack(lua.state, 1); + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 1); - lua.push_ref(&self.0); - let thread_state = ffi::lua_tothread(lua.state, -1); + lua.push_ref(&self.0); + let thread_state = ffi::lua_tothread(lua.state, -1); - let status = ffi::lua_status(thread_state); - if status != ffi::LUA_YIELD && ffi::lua_gettop(thread_state) == 0 { - return Err(Error::CoroutineInactive); - } + let status = ffi::lua_status(thread_state); + if status != ffi::LUA_YIELD && ffi::lua_gettop(thread_state) == 0 { + return Err(Error::CoroutineInactive); + } - ffi::lua_pop(lua.state, 1); + ffi::lua_pop(lua.state, 1); - let args = args.to_lua_multi(lua)?; - let nargs = args.len() as c_int; - check_stack_err(lua.state, nargs)?; - check_stack_err(thread_state, nargs + 1)?; + let args = args.to_lua_multi(lua)?; + let nargs = args.len() as c_int; + check_stack_err(lua.state, nargs)?; + check_stack_err(thread_state, nargs + 1)?; - for arg in args { - lua.push_value(arg); - } - ffi::lua_xmove(lua.state, thread_state, nargs); + for arg in args { + lua.push_value(arg); + } + ffi::lua_xmove(lua.state, thread_state, nargs); - let ret = ffi::lua_resume(thread_state, lua.state, nargs); - if ret != ffi::LUA_OK && ret != ffi::LUA_YIELD { - error_traceback(thread_state); - return Err(pop_error(thread_state, ret)); - } + let ret = ffi::lua_resume(thread_state, lua.state, nargs); + if ret != ffi::LUA_OK && ret != ffi::LUA_YIELD { + error_traceback(thread_state); + return Err(pop_error(thread_state, ret)); + } - let nresults = ffi::lua_gettop(thread_state); - let mut results = MultiValue::new(); - ffi::lua_xmove(thread_state, lua.state, nresults); + let nresults = ffi::lua_gettop(thread_state); + let mut results = MultiValue::new(); + ffi::lua_xmove(thread_state, lua.state, nresults); - check_stack(lua.state, 2); - for _ in 0..nresults { - results.push_front(lua.pop_value()); - } - R::from_lua_multi(results, lua) - }) + check_stack(lua.state, 2); + for _ in 0..nresults { + results.push_front(lua.pop_value()); + } + R::from_lua_multi(results, lua) } } @@ -124,22 +123,21 @@ impl<'lua> Thread<'lua> { pub fn status(&self) -> ThreadStatus { let lua = self.0.lua; unsafe { - stack_guard(lua.state, || { - check_stack(lua.state, 1); + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 1); - lua.push_ref(&self.0); - let thread_state = ffi::lua_tothread(lua.state, -1); - ffi::lua_pop(lua.state, 1); + lua.push_ref(&self.0); + let thread_state = ffi::lua_tothread(lua.state, -1); + ffi::lua_pop(lua.state, 1); - let status = ffi::lua_status(thread_state); - if status != ffi::LUA_OK && status != ffi::LUA_YIELD { - ThreadStatus::Error - } else if status == ffi::LUA_YIELD || ffi::lua_gettop(thread_state) > 0 { - ThreadStatus::Resumable - } else { - ThreadStatus::Unresumable - } - }) + let status = ffi::lua_status(thread_state); + if status != ffi::LUA_OK && status != ffi::LUA_YIELD { + ThreadStatus::Error + } else if status == ffi::LUA_YIELD || ffi::lua_gettop(thread_state) > 0 { + ThreadStatus::Resumable + } else { + ThreadStatus::Unresumable + } } } } diff --git a/src/userdata.rs b/src/userdata.rs index c0383c0..be8fb32 100644 --- a/src/userdata.rs +++ b/src/userdata.rs @@ -5,7 +5,7 @@ use std::string::String as StdString; use ffi; use error::{Error, Result}; -use util::{check_stack, get_userdata, stack_guard}; +use util::{check_stack, get_userdata, StackGuard}; use types::{Callback, LuaRef}; use value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti}; use lua::Lua; @@ -415,29 +415,28 @@ impl<'lua> AnyUserData<'lua> { { unsafe { let lua = self.0.lua; - stack_guard(lua.state, move || { - check_stack(lua.state, 3); + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 3); - lua.push_ref(&self.0); + lua.push_ref(&self.0); - rlua_assert!( - ffi::lua_getmetatable(lua.state, -1) != 0, - "AnyUserData missing metatable" - ); + rlua_assert!( + ffi::lua_getmetatable(lua.state, -1) != 0, + "AnyUserData missing metatable" + ); - ffi::lua_rawgeti( - lua.state, - ffi::LUA_REGISTRYINDEX, - lua.userdata_metatable::()? as ffi::lua_Integer, - ); + ffi::lua_rawgeti( + lua.state, + ffi::LUA_REGISTRYINDEX, + lua.userdata_metatable::()? as ffi::lua_Integer, + ); - if ffi::lua_rawequal(lua.state, -1, -2) == 0 { - Err(Error::UserDataTypeMismatch) - } else { - let res = func(&*get_userdata::>(lua.state, -3)); - res - } - }) + if ffi::lua_rawequal(lua.state, -1, -2) == 0 { + Err(Error::UserDataTypeMismatch) + } else { + let res = func(&*get_userdata::>(lua.state, -3)); + res + } } } @@ -449,13 +448,12 @@ impl<'lua> AnyUserData<'lua> { pub fn set_user_value>(&self, v: V) -> Result<()> { let lua = self.0.lua; unsafe { - stack_guard(lua.state, || { - check_stack(lua.state, 2); - lua.push_ref(&self.0); - lua.push_value(v.to_lua(lua)?); - ffi::lua_setuservalue(lua.state, -2); - Ok(()) - }) + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 2); + lua.push_ref(&self.0); + lua.push_value(v.to_lua(lua)?); + ffi::lua_setuservalue(lua.state, -2); + Ok(()) } } @@ -465,13 +463,12 @@ impl<'lua> AnyUserData<'lua> { pub fn get_user_value>(&self) -> Result { let lua = self.0.lua; unsafe { - stack_guard(lua.state, || { - check_stack(lua.state, 3); - lua.push_ref(&self.0); - ffi::lua_getuservalue(lua.state, -1); - let res = V::from_lua(lua.pop_value(), lua)?; - Ok(res) - }) + let _sg = StackGuard::new(lua.state); + check_stack(lua.state, 3); + lua.push_ref(&self.0); + ffi::lua_getuservalue(lua.state, -1); + let res = V::from_lua(lua.pop_value(), lua)?; + Ok(res) } } } diff --git a/src/util.rs b/src/util.rs index 724fde8..f7dc17f 100644 --- a/src/util.rs +++ b/src/util.rs @@ -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(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. // 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