diff --git a/src/error.rs b/src/error.rs index c7ff2e5..2787331 100644 --- a/src/error.rs +++ b/src/error.rs @@ -87,6 +87,8 @@ pub enum Error { /// [`AnyUserData`]: struct.AnyUserData.html /// [`UserData`]: trait.UserData.html UserDataBorrowMutError, + /// A `RegistryKey` produced from a different Lua state was used. + MismatchedRegistryKey, /// A Rust callback returned `Err`, raising the contained `Error` as a Lua error. CallbackError { /// Lua call stack backtrace. @@ -142,6 +144,9 @@ impl fmt::Display for Error { Error::UserDataTypeMismatch => write!(fmt, "userdata is not expected type"), Error::UserDataBorrowError => write!(fmt, "userdata already mutably borrowed"), Error::UserDataBorrowMutError => write!(fmt, "userdata already borrowed"), + Error::MismatchedRegistryKey => { + write!(fmt, "RegistryKey used from different Lua state") + } Error::CallbackError { ref traceback, .. } => { write!(fmt, "callback error: {}", traceback) } diff --git a/src/lua.rs b/src/lua.rs index 8d53b90..d8dd809 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -504,11 +504,9 @@ impl Lua { /// value previously placed by `create_registry_value`. pub fn registry_value<'lua, T: FromLua<'lua>>(&'lua self, key: &RegistryKey) -> Result { unsafe { - lua_assert!( - self.state, - Arc::ptr_eq(&key.drop_list, &(*self.extra()).registry_drop_list), - "Lua instance passed RegistryKey created from a different Lua" - ); + if !Arc::ptr_eq(&key.drop_list, &(*self.extra()).registry_drop_list) { + return Err(Error::MismatchedRegistryKey); + } stack_err_guard(self.state, 0, || { check_stack(self.state, 1); @@ -528,25 +526,25 @@ impl Lua { /// `create_registry_value`. In addition to manual `RegistryKey` removal, you can also call /// `expire_registry_values` to automatically remove values from the registry whose /// `RegistryKey`s have been dropped. - pub fn remove_registry_value(&self, mut key: RegistryKey) { + pub fn remove_registry_value(&self, mut key: RegistryKey) -> Result<()> { unsafe { - lua_assert!( - self.state, - Arc::ptr_eq(&key.drop_list, &(*self.extra()).registry_drop_list), - "Lua instance passed RegistryKey created from a different Lua" - ); + if !Arc::ptr_eq(&key.drop_list, &(*self.extra()).registry_drop_list) { + return Err(Error::MismatchedRegistryKey); + } ffi::luaL_unref(self.state, ffi::LUA_REGISTRYINDEX, key.registry_id); // Don't adding to the registry drop list when dropping the key key.registry_id = ffi::LUA_REFNIL; + Ok(()) } } /// Returns true if the given `RegistryKey` was created by a `Lua` which shares the underlying /// main state with this `Lua` instance. /// - /// Other than this, methods that accept a `RegistryKey` will panic if passed a `RegistryKey` - /// that was not created with a matching `Lua` state. + /// Other than this, methods that accept a `RegistryKey` will return + /// `Error::MismatchedRegistryKey` if passed a `RegistryKey` that was not created with a + /// matching `Lua` state. pub fn owns_registry_value(&self, key: &RegistryKey) -> bool { unsafe { Arc::ptr_eq(&key.drop_list, &(*self.extra()).registry_drop_list) } } diff --git a/src/tests.rs b/src/tests.rs index cd10d89..cbad78c 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -586,13 +586,15 @@ fn test_lua_registry_ownership() { } #[test] -#[should_panic] fn test_mismatched_registry_key() { let lua1 = Lua::new(); let lua2 = Lua::new(); let r = lua1.create_registry_value("hello").unwrap(); - lua2.remove_registry_value(r); + match lua2.remove_registry_value(r) { + Err(Error::MismatchedRegistryKey) => {} + r => panic!("wrong result type for mismatched registry key, {:?}", r), + }; } // TODO: Need to use compiletest-rs or similar to make sure these don't compile.