diff --git a/src/userdata.rs b/src/userdata.rs index af5b304..4be27d2 100644 --- a/src/userdata.rs +++ b/src/userdata.rs @@ -840,39 +840,21 @@ impl<'lua> AnyUserData<'lua> { self.inspect(|cell| cell.try_borrow_mut()) } - /// Takes out the value of `UserData` and sets the special "destructed" metatable that prevents - /// any further operations with this userdata. + /// Takes the value out of this userdata. + /// Sets the special "destructed" metatable that prevents any further operations with this userdata. /// - /// All associated user values will be also cleared. + /// Keeps associated user values unchanged (they will be collected by Lua's GC). pub fn take(&self) -> Result { let lua = self.0.lua; unsafe { let _sg = StackGuard::new(lua.state); - check_stack(lua.state, 3)?; + check_stack(lua.state, 2)?; let type_id = lua.push_userdata_ref(&self.0)?; match type_id { Some(type_id) if type_id == TypeId::of::() => { // Try to borrow userdata exclusively let _ = (*get_userdata::>(lua.state, -1)).try_borrow_mut()?; - - // Clear associated user values - #[cfg(feature = "lua54")] - for i in 1..=USER_VALUE_MAXSLOT { - ffi::lua_pushnil(lua.state); - ffi::lua_setiuservalue(lua.state, -2, i as c_int); - } - #[cfg(any(feature = "lua53", feature = "lua52", feature = "luau"))] - { - ffi::lua_pushnil(lua.state); - ffi::lua_setuservalue(lua.state, -2); - } - #[cfg(any(feature = "lua51", feature = "luajit"))] - protect_lua!(lua.state, 1, 1, fn(state) { - ffi::lua_newtable(state); - ffi::lua_setuservalue(state, -2); - })?; - Ok(take_userdata::>(lua.state).into_inner()) } _ => Err(Error::UserDataTypeMismatch), @@ -1083,6 +1065,7 @@ impl<'lua> AnyUserData<'lua> { /// For `T: UserData + 'static` returned metatable is shared among all instances of type `T`. /// /// [`UserDataMetatable`]: crate::UserDataMetatable + #[inline] pub fn get_metatable(&self) -> Result> { self.get_raw_metatable().map(UserDataMetatable) } diff --git a/tests/userdata.rs b/tests/userdata.rs index 91996b7..28f15af 100644 --- a/tests/userdata.rs +++ b/tests/userdata.rs @@ -305,21 +305,19 @@ fn test_userdata_take() -> Result<()> { fn check_userdata_take(lua: &Lua, userdata: AnyUserData, rc: Arc) -> Result<()> { lua.globals().set("userdata", userdata.clone())?; assert_eq!(Arc::strong_count(&rc), 3); - let userdata_copy = userdata.clone(); { let _value = userdata.borrow::()?; // We should not be able to take userdata if it's borrowed - match userdata_copy.take::() { + match userdata.take::() { Err(Error::UserDataBorrowMutError) => {} r => panic!("expected `UserDataBorrowMutError` error, got {:?}", r), } } - let value = userdata_copy.take::()?; + let value = userdata.take::()?; assert_eq!(*value.0, 18); drop(value); - lua.gc_collect()?; - assert_eq!(Arc::strong_count(&rc), 1); + assert_eq!(Arc::strong_count(&rc), 2); match userdata.borrow::() { Err(Error::UserDataDestructed) => {} @@ -332,6 +330,13 @@ fn test_userdata_take() -> Result<()> { }, r => panic!("improper return for destructed userdata: {:?}", r), } + + drop(userdata); + lua.globals().raw_remove("userdata")?; + lua.gc_collect()?; + lua.gc_collect()?; + assert_eq!(Arc::strong_count(&rc), 1); + Ok(()) }