@@ -2049,17 +2049,16 @@ impl Lua {
2049
2049
T : FromLua < ' lua > ,
2050
2050
{
2051
2051
let state = self . state ( ) ;
2052
- let value = unsafe {
2052
+ unsafe {
2053
2053
let _sg = StackGuard :: new ( state) ;
2054
2054
check_stack ( state, 3 ) ?;
2055
2055
2056
2056
let protect = !self . unlikely_memory_error ( ) ;
2057
2057
push_string ( state, name. as_bytes ( ) , protect) ?;
2058
2058
ffi:: lua_rawget ( state, ffi:: LUA_REGISTRYINDEX ) ;
2059
2059
2060
- self . pop_value ( )
2061
- } ;
2062
- T :: from_lua ( value, self )
2060
+ T :: from_stack ( -1 , self )
2061
+ }
2063
2062
}
2064
2063
2065
2064
/// Removes a named value in the Lua registry.
@@ -2082,22 +2081,21 @@ impl Lua {
2082
2081
///
2083
2082
/// [`RegistryKey`]: crate::RegistryKey
2084
2083
pub fn create_registry_value < ' lua , T : IntoLua < ' lua > > ( & ' lua self , t : T ) -> Result < RegistryKey > {
2085
- let t = t. into_lua ( self ) ?;
2086
- if t == Value :: Nil {
2087
- // Special case to skip calling `luaL_ref` and use `LUA_REFNIL` instead
2088
- let unref_list = unsafe { ( * self . extra . get ( ) ) . registry_unref_list . clone ( ) } ;
2089
- return Ok ( RegistryKey :: new ( ffi:: LUA_REFNIL , unref_list) ) ;
2090
- }
2091
-
2092
2084
let state = self . state ( ) ;
2093
2085
unsafe {
2094
2086
let _sg = StackGuard :: new ( state) ;
2095
2087
check_stack ( state, 4 ) ?;
2096
2088
2097
- self . push_value ( t) ?;
2089
+ self . push ( t) ?;
2098
2090
2099
- // Try to reuse previously allocated slot
2100
2091
let unref_list = ( * self . extra . get ( ) ) . registry_unref_list . clone ( ) ;
2092
+
2093
+ // Check if the value is nil (no need to store it in the registry)
2094
+ if ffi:: lua_isnil ( state, -1 ) != 0 {
2095
+ return Ok ( RegistryKey :: new ( ffi:: LUA_REFNIL , unref_list) ) ;
2096
+ }
2097
+
2098
+ // Try to reuse previously allocated slot
2101
2099
let free_registry_id = mlua_expect ! ( unref_list. lock( ) , "unref list poisoned" )
2102
2100
. as_mut ( )
2103
2101
. and_then ( |x| x. pop ( ) ) ;
@@ -2107,7 +2105,7 @@ impl Lua {
2107
2105
return Ok ( RegistryKey :: new ( registry_id, unref_list) ) ;
2108
2106
}
2109
2107
2110
- // Allocate a new RegistryKey
2108
+ // Allocate a new RegistryKey slot
2111
2109
let registry_id = if self . unlikely_memory_error ( ) {
2112
2110
ffi:: luaL_ref ( state, ffi:: LUA_REGISTRYINDEX )
2113
2111
} else {
@@ -2131,18 +2129,16 @@ impl Lua {
2131
2129
}
2132
2130
2133
2131
let state = self . state ( ) ;
2134
- let value = match key. is_nil ( ) {
2135
- true => Value :: Nil ,
2136
- false => unsafe {
2132
+ match key. id ( ) {
2133
+ ffi :: LUA_REFNIL => T :: from_lua ( Value :: Nil , self ) ,
2134
+ registry_id => unsafe {
2137
2135
let _sg = StackGuard :: new ( state) ;
2138
2136
check_stack ( state, 1 ) ?;
2139
2137
2140
- let id = key. registry_id as Integer ;
2141
- ffi:: lua_rawgeti ( state, ffi:: LUA_REGISTRYINDEX , id) ;
2142
- self . pop_value ( )
2138
+ ffi:: lua_rawgeti ( state, ffi:: LUA_REGISTRYINDEX , registry_id as Integer ) ;
2139
+ T :: from_stack ( -1 , self )
2143
2140
} ,
2144
- } ;
2145
- T :: from_lua ( value, self )
2141
+ }
2146
2142
}
2147
2143
2148
2144
/// Removes a value from the Lua registry.
@@ -2180,29 +2176,32 @@ impl Lua {
2180
2176
}
2181
2177
2182
2178
let t = t. into_lua ( self ) ?;
2183
- if t == Value :: Nil && key. is_nil ( ) {
2184
- // Nothing to replace
2185
- return Ok ( ( ) ) ;
2186
- } else if t != Value :: Nil && key. registry_id == ffi:: LUA_REFNIL {
2187
- // We cannot update `LUA_REFNIL` slot
2188
- return Err ( Error :: runtime ( "cannot replace nil value with non-nil" ) ) ;
2189
- }
2190
2179
2191
2180
let state = self . state ( ) ;
2192
2181
unsafe {
2193
2182
let _sg = StackGuard :: new ( state) ;
2194
2183
check_stack ( state, 2 ) ?;
2195
2184
2196
- let id = key. registry_id as Integer ;
2197
- if t == Value :: Nil {
2198
- self . push_value ( Value :: Integer ( id) ) ?;
2199
- key. set_nil ( true ) ;
2200
- } else {
2201
- self . push_value ( t) ?;
2202
- key. set_nil ( false ) ;
2185
+ match ( t, key. id ( ) ) {
2186
+ ( Value :: Nil , ffi:: LUA_REFNIL ) => {
2187
+ // Do nothing, no need to replace nil with nil
2188
+ }
2189
+ ( Value :: Nil , registry_id) => {
2190
+ // Remove the value
2191
+ ffi:: luaL_unref ( state, ffi:: LUA_REGISTRYINDEX , registry_id) ;
2192
+ key. set_id ( ffi:: LUA_REFNIL ) ;
2193
+ }
2194
+ ( value, ffi:: LUA_REFNIL ) => {
2195
+ // Allocate a new `RegistryKey`
2196
+ let new_key = self . create_registry_value ( value) ?;
2197
+ key. set_id ( new_key. take ( ) ) ;
2198
+ }
2199
+ ( value, registry_id) => {
2200
+ // It must be safe to replace the value without triggering memory error
2201
+ self . push_value ( value) ?;
2202
+ ffi:: lua_rawseti ( state, ffi:: LUA_REGISTRYINDEX , registry_id as Integer ) ;
2203
+ }
2203
2204
}
2204
- // It must be safe to replace the value without triggering memory error
2205
- ffi:: lua_rawseti ( state, ffi:: LUA_REGISTRYINDEX , id) ;
2206
2205
}
2207
2206
Ok ( ( ) )
2208
2207
}
0 commit comments