diff --git a/Cargo.toml b/Cargo.toml index d4ebe85..94d65f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rlua" -version = "0.4.3" +version = "0.4.4" authors = ["kyren "] description = "High level bindings to Lua 5.3" repository = "https://github.com/chucklefish/rlua" diff --git a/src/ffi.rs b/src/ffi.rs index 1d210e9..1bf3b17 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -106,6 +106,7 @@ extern "C" { pub fn lua_setmetatable(state: *mut lua_State, index: c_int); pub fn lua_len(state: *mut lua_State, index: c_int); + pub fn lua_rawlen(state: *mut lua_State, index: c_int) -> usize; pub fn lua_next(state: *mut lua_State, index: c_int) -> c_int; pub fn lua_rawequal(state: *mut lua_State, index1: c_int, index2: c_int) -> c_int; diff --git a/src/lua.rs b/src/lua.rs index cf668a8..a1aeda5 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -152,21 +152,38 @@ pub struct LuaTable<'lua>(LuaRef<'lua>); impl<'lua> LuaTable<'lua> { pub fn set, V: ToLua<'lua>>(&self, key: K, value: V) -> LuaResult<()> { let lua = self.0.lua; + let key = key.to_lua(lua)?; + let value = value.to_lua(lua)?; unsafe { - stack_guard(lua.state, 0, || { - check_stack(lua.state, 3)?; - lua.push_ref(lua.state, &self.0); - lua.push_value(lua.state, key.to_lua(lua)?)?; - lua.push_value(lua.state, value.to_lua(lua)?)?; - error_guard(lua.state, 3, 0, |state| { - ffi::lua_settable(state, -3); - Ok(()) - })?; + error_guard(lua.state, 0, 0, |state| { + check_stack(state, 3)?; + lua.push_ref(state, &self.0); + lua.push_value(state, key)?; + lua.push_value(state, value)?; + ffi::lua_settable(state, -3); Ok(()) }) } } + pub fn get, V: FromLua<'lua>>(&self, key: K) -> LuaResult { + let lua = self.0.lua; + let key = key.to_lua(lua)?; + unsafe { + let res = error_guard(lua.state, 0, 0, |state| { + check_stack(state, 2)?; + lua.push_ref(state, &self.0); + lua.push_value(state, key.to_lua(lua)?)?; + ffi::lua_gettable(state, -2); + let res = lua.pop_value(state)?; + ffi::lua_pop(state, 1); + Ok(res) + })?; + V::from_lua(res, lua) + } + } + + /// Set a field in the table, without invoking metamethods pub fn raw_set, V: ToLua<'lua>>(&self, key: K, value: V) -> LuaResult<()> { let lua = self.0.lua; unsafe { @@ -182,24 +199,7 @@ impl<'lua> LuaTable<'lua> { } } - pub fn get, V: FromLua<'lua>>(&self, key: K) -> LuaResult { - let lua = self.0.lua; - unsafe { - stack_guard(lua.state, 0, || { - check_stack(lua.state, 2)?; - lua.push_ref(lua.state, &self.0); - lua.push_value(lua.state, key.to_lua(lua)?)?; - error_guard(lua.state, 2, 2, |state| { - ffi::lua_gettable(state, -2); - Ok(()) - })?; - let res = V::from_lua(lua.pop_value(lua.state)?, lua)?; - ffi::lua_pop(lua.state, 1); - Ok(res) - }) - } - } - + /// Get a field in the table, without invoking metamethods pub fn raw_get, V: FromLua<'lua>>(&self, key: K) -> LuaResult { let lua = self.0.lua; unsafe { @@ -217,12 +217,27 @@ impl<'lua> LuaTable<'lua> { /// Equivalent to the result of the lua '#' operator. pub fn length(&self) -> LuaResult { + let lua = self.0.lua; + unsafe { + error_guard(lua.state, 0, 0, |state| { + check_stack(state, 1)?; + lua.push_ref(state, &self.0); + Ok(ffi::luaL_len(state, -1)) + }) + } + } + + /// Equivalent to the result of the lua '#' operator, without invoking the + /// __len metamethod. + pub fn raw_length(&self) -> LuaResult { let lua = self.0.lua; unsafe { stack_guard(lua.state, 0, || { check_stack(lua.state, 1)?; lua.push_ref(lua.state, &self.0); - error_guard(lua.state, 1, 0, |state| Ok(ffi::luaL_len(state, -1))) + let len = ffi::lua_rawlen(lua.state, -1); + ffi::lua_pop(lua.state, 1); + Ok(len as LuaInteger) }) } } @@ -264,7 +279,7 @@ impl<'lua> LuaTable<'lua> { check_stack(lua.state, 4)?; lua.push_ref(lua.state, &self.0); - let len = error_guard(lua.state, 1, 1, |state| Ok(ffi::luaL_len(state, -1)))?; + let len = ffi::lua_rawlen(lua.state, -1) as ffi::lua_Integer; ffi::lua_pushnil(lua.state); while ffi::lua_next(lua.state, -2) != 0 { @@ -1271,14 +1286,3 @@ impl Lua { static LUA_USERDATA_REGISTRY_KEY: u8 = 0; static FUNCTION_METATABLE_REGISTRY_KEY: u8 = 0; static TOP_STATE_REGISTRY_KEY: u8 = 0; - -// If the return code indicates an error, pops the error off of the stack and -// returns Err. If the error was actually a rust panic, clears the current lua -// stack and panics. -unsafe fn handle_error(state: *mut ffi::lua_State, ret: c_int) -> LuaResult<()> { - if ret != ffi::LUA_OK && ret != ffi::LUA_YIELD { - Err(pop_error(state)) - } else { - Ok(()) - } -} diff --git a/src/tests.rs b/src/tests.rs index 1832616..5a499ef 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -558,9 +558,10 @@ fn test_table_error() { .unwrap(); let bad_table: LuaTable = lua.get("table").unwrap(); - assert!(bad_table.set("key", 1).is_err()); - assert!(bad_table.get::<_, i32>("key").is_err()); + assert!(bad_table.set(1, 1).is_err()); + assert!(bad_table.get::<_, i32>(1).is_err()); assert!(bad_table.length().is_err()); - assert!(bad_table.raw_set("key", 1).is_ok()); - assert!(bad_table.raw_get::<_, i32>("key").is_ok()); + assert!(bad_table.raw_set(1, 1).is_ok()); + assert!(bad_table.raw_get::<_, i32>(1).is_ok()); + assert_eq!(bad_table.raw_length().unwrap(), 1); } diff --git a/src/util.rs b/src/util.rs index 2ba263c..c6c5576 100644 --- a/src/util.rs +++ b/src/util.rs @@ -102,6 +102,17 @@ pub unsafe fn error_guard(state: *mut ffi::lua_State, Ok(res.unwrap()) } +// If the return code indicates an error, pops the error off of the stack and +// returns Err. If the error was actually a rust panic, clears the current lua +// stack and panics. +pub unsafe fn handle_error(state: *mut ffi::lua_State, ret: c_int) -> LuaResult<()> { + if ret != ffi::LUA_OK && ret != ffi::LUA_YIELD { + Err(pop_error(state)) + } else { + Ok(()) + } +} + pub unsafe fn push_string(state: *mut ffi::lua_State, s: &str) { ffi::lua_pushlstring(state, s.as_ptr() as *const c_char, s.len()); }