@@ -58,6 +58,11 @@ impl<'lua> Table<'lua> {
58
58
///
59
59
/// [`raw_set`]: #method.raw_set
60
60
pub fn set < K : ToLua < ' lua > , V : ToLua < ' lua > > ( & self , key : K , value : V ) -> Result < ( ) > {
61
+ // Fast track
62
+ if !self . has_metatable ( ) {
63
+ return self . raw_set ( key, value) ;
64
+ }
65
+
61
66
let lua = self . 0 . lua ;
62
67
let key = key. to_lua ( lua) ?;
63
68
let value = value. to_lua ( lua) ?;
@@ -98,6 +103,11 @@ impl<'lua> Table<'lua> {
98
103
///
99
104
/// [`raw_get`]: #method.raw_get
100
105
pub fn get < K : ToLua < ' lua > , V : FromLua < ' lua > > ( & self , key : K ) -> Result < V > {
106
+ // Fast track
107
+ if !self . has_metatable ( ) {
108
+ return self . raw_get ( key) ;
109
+ }
110
+
101
111
let lua = self . 0 . lua ;
102
112
let key = key. to_lua ( lua) ?;
103
113
@@ -116,18 +126,7 @@ impl<'lua> Table<'lua> {
116
126
117
127
/// Checks whether the table contains a non-nil value for `key`.
118
128
pub fn contains_key < K : ToLua < ' lua > > ( & self , key : K ) -> Result < bool > {
119
- let lua = self . 0 . lua ;
120
- let key = key. to_lua ( lua) ?;
121
-
122
- unsafe {
123
- let _sg = StackGuard :: new ( lua. state ) ;
124
- check_stack ( lua. state , 4 ) ?;
125
-
126
- lua. push_ref ( & self . 0 ) ;
127
- lua. push_value ( key) ?;
128
- protect_lua ! ( lua. state, 2 , 1 , fn ( state) ffi:: lua_gettable( state, -2 ) ) ?;
129
- Ok ( ffi:: lua_isnil ( lua. state , -1 ) == 0 )
130
- }
129
+ Ok ( self . get :: < _ , Value > ( key) ? != Value :: Nil )
131
130
}
132
131
133
132
/// Compares two tables for equality.
@@ -199,7 +198,14 @@ impl<'lua> Table<'lua> {
199
198
lua. push_ref ( & self . 0 ) ;
200
199
lua. push_value ( key) ?;
201
200
lua. push_value ( value) ?;
202
- if lua. unlikely_memory_error ( ) {
201
+
202
+ #[ cfg( not( feature = "luau" ) ) ]
203
+ let protect = !lua. unlikely_memory_error ( ) ;
204
+ // If Luau table is readonly it will throw an exception
205
+ #[ cfg( feature = "luau" ) ]
206
+ let protect = !lua. unlikely_memory_error ( ) || self . is_readonly ( ) ;
207
+
208
+ if !protect {
203
209
ffi:: lua_rawset ( lua. state , -3 ) ;
204
210
ffi:: lua_pop ( lua. state , 1 ) ;
205
211
Ok ( ( ) )
@@ -295,6 +301,11 @@ impl<'lua> Table<'lua> {
295
301
///
296
302
/// [`raw_len`]: #method.raw_len
297
303
pub fn len ( & self ) -> Result < Integer > {
304
+ // Fast track
305
+ if !self . has_metatable ( ) {
306
+ return Ok ( self . raw_len ( ) ) ;
307
+ }
308
+
298
309
let lua = self . 0 . lua ;
299
310
unsafe {
300
311
let _sg = StackGuard :: new ( lua. state ) ;
@@ -307,14 +318,8 @@ impl<'lua> Table<'lua> {
307
318
308
319
/// Returns the result of the Lua `#` operator, without invoking the `__len` metamethod.
309
320
pub fn raw_len ( & self ) -> Integer {
310
- let lua = self . 0 . lua ;
311
- unsafe {
312
- let _sg = StackGuard :: new ( lua. state ) ;
313
- assert_stack ( lua. state , 1 ) ;
314
-
315
- lua. push_ref ( & self . 0 ) ;
316
- ffi:: lua_rawlen ( lua. state , -1 ) as Integer
317
- }
321
+ let ref_thread = self . 0 . lua . ref_thread ( ) ;
322
+ unsafe { ffi:: lua_rawlen ( ref_thread, self . 0 . index ) as Integer }
318
323
}
319
324
320
325
/// Returns a reference to the metatable of this table, or `None` if no metatable is set.
@@ -355,15 +360,28 @@ impl<'lua> Table<'lua> {
355
360
}
356
361
}
357
362
363
+ /// Returns true if the table has metatable attached.
364
+ #[ doc( hidden) ]
365
+ #[ inline]
366
+ pub fn has_metatable ( & self ) -> bool {
367
+ let ref_thread = self . 0 . lua . ref_thread ( ) ;
368
+ unsafe {
369
+ if ffi:: lua_getmetatable ( ref_thread, self . 0 . index ) != 0 {
370
+ ffi:: lua_pop ( ref_thread, 1 ) ;
371
+ return true ;
372
+ }
373
+ }
374
+ false
375
+ }
376
+
358
377
/// Sets `readonly` attribute on the table.
359
378
///
360
379
/// Requires `feature = "luau"`
361
380
#[ cfg( any( feature = "luau" , doc) ) ]
362
381
#[ cfg_attr( docsrs, doc( cfg( feature = "luau" ) ) ) ]
363
382
pub fn set_readonly ( & self , enabled : bool ) {
364
- let lua = self . 0 . lua ;
383
+ let ref_thread = self . 0 . lua . ref_thread ( ) ;
365
384
unsafe {
366
- let ref_thread = lua. ref_thread ( ) ;
367
385
ffi:: lua_setreadonly ( ref_thread, self . 0 . index , enabled as _ ) ;
368
386
if !enabled {
369
387
// Reset "safeenv" flag
@@ -378,8 +396,8 @@ impl<'lua> Table<'lua> {
378
396
#[ cfg( any( feature = "luau" , doc) ) ]
379
397
#[ cfg_attr( docsrs, doc( cfg( feature = "luau" ) ) ) ]
380
398
pub fn is_readonly ( & self ) -> bool {
381
- let lua = self . 0 . lua ;
382
- unsafe { ffi:: lua_getreadonly ( lua . ref_thread ( ) , self . 0 . index ) != 0 }
399
+ let ref_thread = self . 0 . lua . ref_thread ( ) ;
400
+ unsafe { ffi:: lua_getreadonly ( ref_thread, self . 0 . index ) != 0 }
383
401
}
384
402
385
403
/// Converts the table to a generic C pointer.
@@ -390,8 +408,8 @@ impl<'lua> Table<'lua> {
390
408
/// Typically this function is used only for hashing and debug information.
391
409
#[ inline]
392
410
pub fn to_pointer ( & self ) -> * const c_void {
393
- let lua = self . 0 . lua ;
394
- unsafe { ffi:: lua_topointer ( lua . ref_thread ( ) , self . 0 . index ) }
411
+ let ref_thread = self . 0 . lua . ref_thread ( ) ;
412
+ unsafe { ffi:: lua_topointer ( ref_thread, self . 0 . index ) }
395
413
}
396
414
397
415
/// Consume this table and return an iterator over the pairs of the table.
0 commit comments