Skip to content

Commit 646827a

Browse files
committed
Update Table::set_metatable
- Return Err (instead of panic) when trying to change readonly table (Luau) - Slightly optimize performance
1 parent 1882931 commit 646827a

File tree

7 files changed

+21
-26
lines changed

7 files changed

+21
-26
lines changed

mlua_derive/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,13 @@ pub fn chunk(input: TokenStream) -> TokenStream {
129129
let globals = lua.globals();
130130
let env = lua.create_table()?;
131131
let meta = lua.create_table()?;
132-
meta.raw_set("__index", globals.clone())?;
133-
meta.raw_set("__newindex", globals)?;
132+
meta.raw_set("__index", &globals)?;
133+
meta.raw_set("__newindex", &globals)?;
134134

135135
// Add captured variables
136136
#(#caps)*
137137

138-
env.set_metatable(Some(meta));
138+
env.set_metatable(Some(meta))?;
139139
Ok(env)
140140
};
141141

src/serde/ser.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ impl<'a> ser::Serializer for Serializer<'a> {
256256
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
257257
let table = self.lua.create_table_with_capacity(len.unwrap_or(0), 0)?;
258258
if self.options.set_array_metatable {
259-
table.set_metatable(Some(self.lua.array_metatable()));
259+
table.set_metatable(Some(self.lua.array_metatable()))?;
260260
}
261261
Ok(SerializeSeq::new(self.lua, table, self.options))
262262
}

src/table.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ impl Table {
211211
///
212212
/// let always_equals_mt = lua.create_table()?;
213213
/// always_equals_mt.set("__eq", lua.create_function(|_, (_t1, _t2): (Table, Table)| Ok(true))?)?;
214-
/// table2.set_metatable(Some(always_equals_mt));
214+
/// table2.set_metatable(Some(always_equals_mt))?;
215215
///
216216
/// assert!(table1.equals(&table1.clone())?);
217217
/// assert!(table1.equals(&table2)?);
@@ -501,27 +501,23 @@ impl Table {
501501
///
502502
/// If `metatable` is `None`, the metatable is removed (if no metatable is set, this does
503503
/// nothing).
504-
pub fn set_metatable(&self, metatable: Option<Table>) {
505-
// Workaround to throw readonly error without returning Result
504+
pub fn set_metatable(&self, metatable: Option<Table>) -> Result<()> {
506505
#[cfg(feature = "luau")]
507506
if self.is_readonly() {
508-
panic!("attempt to modify a readonly table");
507+
return Err(Error::runtime("attempt to modify a readonly table"));
509508
}
510509

511510
let lua = self.0.lua.lock();
512-
let state = lua.state();
511+
let ref_thread = lua.ref_thread();
513512
unsafe {
514-
let _sg = StackGuard::new(state);
515-
assert_stack(state, 2);
516-
517-
lua.push_ref(&self.0);
518513
if let Some(metatable) = metatable {
519-
lua.push_ref(&metatable.0);
514+
ffi::lua_pushvalue(ref_thread, metatable.0.index);
520515
} else {
521-
ffi::lua_pushnil(state);
516+
ffi::lua_pushnil(ref_thread);
522517
}
523-
ffi::lua_setmetatable(state, -2);
518+
ffi::lua_setmetatable(ref_thread, self.0.index);
524519
}
520+
Ok(())
525521
}
526522

527523
/// Returns true if the table has metatable attached.

tests/async.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ async fn test_async_table_object_like() -> Result<()> {
386386
table.get::<i64>("val")
387387
})?,
388388
)?;
389-
table.set_metatable(Some(metatable));
389+
table.set_metatable(Some(metatable))?;
390390
assert_eq!(table.call_async::<i64>(()).await.unwrap(), 15);
391391

392392
match table.call_async_method::<()>("non_existent", ()).await {

tests/luau.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
use std::cell::Cell;
44
use std::fmt::Debug;
55
use std::os::raw::c_void;
6-
use std::panic::{catch_unwind, AssertUnwindSafe};
76
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicU64, Ordering};
87
use std::sync::Arc;
98

@@ -120,7 +119,7 @@ fn test_vector_metatable() -> Result<()> {
120119
"#,
121120
)
122121
.eval::<Table>()?;
123-
vector_mt.set_metatable(Some(vector_mt.clone()));
122+
vector_mt.set_metatable(Some(vector_mt.clone()))?;
124123
lua.set_type_metatable::<Vector>(Some(vector_mt.clone()));
125124
lua.globals().set("Vector3", vector_mt)?;
126125

@@ -167,9 +166,9 @@ fn test_readonly_table() -> Result<()> {
167166
check_readonly_error(t.raw_pop::<Value>());
168167

169168
// Special case
170-
match catch_unwind(AssertUnwindSafe(|| t.set_metatable(None))) {
171-
Ok(_) => panic!("expected panic, got nothing"),
172-
Err(_) => {}
169+
match t.set_metatable(None) {
170+
Err(Error::RuntimeError(e)) if e.contains("attempt to modify a readonly table") => {}
171+
r => panic!("expected RuntimeError(...) with a specific message, got {r:?}"),
173172
}
174173

175174
Ok(())

tests/serde.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ fn test_serialize() -> Result<(), Box<dyn StdError>> {
2525
globals.set("null", lua.null())?;
2626

2727
let empty_array = lua.create_table()?;
28-
empty_array.set_metatable(Some(lua.array_metatable()));
28+
empty_array.set_metatable(Some(lua.array_metatable()))?;
2929
globals.set("empty_array", empty_array)?;
3030

3131
let val = lua
@@ -173,7 +173,7 @@ fn test_serialize_sorted() -> LuaResult<()> {
173173
globals.set("null", lua.null())?;
174174

175175
let empty_array = lua.create_table()?;
176-
empty_array.set_metatable(Some(lua.array_metatable()));
176+
empty_array.set_metatable(Some(lua.array_metatable()))?;
177177
globals.set("empty_array", empty_array)?;
178178

179179
let value = lua

tests/table.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,10 +298,10 @@ fn test_metatable() -> Result<()> {
298298
let table = lua.create_table()?;
299299
let metatable = lua.create_table()?;
300300
metatable.set("__index", lua.create_function(|_, ()| Ok("index_value"))?)?;
301-
table.set_metatable(Some(metatable));
301+
table.set_metatable(Some(metatable))?;
302302
assert_eq!(table.get::<String>("any_key")?, "index_value");
303303
assert_eq!(table.raw_get::<Value>("any_key")?, Value::Nil);
304-
table.set_metatable(None);
304+
table.set_metatable(None)?;
305305
assert_eq!(table.get::<Value>("any_key")?, Value::Nil);
306306

307307
Ok(())

0 commit comments

Comments
 (0)