Set `__name` field in userdata metatable if not provided

This commit is contained in:
Alex Orlenko 2023-05-25 10:59:46 +01:00
parent 2efc637ab9
commit 68e65a8ffe
No known key found for this signature in database
GPG Key ID: 4C150C250863B96D
2 changed files with 30 additions and 17 deletions

View File

@ -34,7 +34,7 @@ use crate::util::{
self, assert_stack, callback_error, check_stack, get_destructed_userdata_metatable,
get_gc_metatable, get_gc_userdata, get_main_state, get_userdata, init_error_registry,
init_gc_metatable, init_userdata_metatable, pop_error, push_gc_userdata, push_string,
push_table, rawset_field, safe_pcall, safe_xpcall, StackGuard, WrappedFailure,
push_table, rawset_field, safe_pcall, safe_xpcall, short_type_name, StackGuard, WrappedFailure,
};
use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, MultiValue, Nil, Value};
@ -2529,10 +2529,18 @@ impl Lua {
self.push_value(Value::Function(self.create_async_callback(m)?))?;
rawset_field(state, -2, MetaMethod::validate(&k)?)?;
}
let mut has_name = false;
for (k, f) in registry.meta_fields {
has_name = has_name || k == "__name";
self.push_value(f(self)?)?;
rawset_field(state, -2, MetaMethod::validate(&k)?)?;
}
// Set `__name` if not provided
if !has_name {
let type_name = short_type_name::<T>();
push_string(state, type_name.as_bytes(), !self.unlikely_memory_error())?;
rawset_field(state, -2, "__name")?;
}
let metatable_index = ffi::lua_absindex(state, -1);
let mut extra_tables_count = 0;

View File

@ -538,30 +538,22 @@ fn test_fields() -> Result<()> {
#[test]
fn test_metatable() -> Result<()> {
#[derive(Copy, Clone)]
struct MyUserData(i64);
struct MyUserData;
impl UserData for MyUserData {
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_meta_field_with("__type_name", |_| Ok("MyUserData"));
}
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_function("my_type_name", |_, data: AnyUserData| {
let metatable = data.get_metatable()?;
metatable.get::<String>("__type_name")
metatable.get::<String>("__name")
});
}
}
let lua = Lua::new();
let globals = lua.globals();
globals.set("ud", MyUserData(7))?;
lua.load(
r#"
assert(ud:my_type_name() == "MyUserData")
"#,
)
.exec()?;
globals.set("ud", MyUserData)?;
lua.load(r#"assert(ud:my_type_name() == "MyUserData")"#)
.exec()?;
let ud: AnyUserData = globals.get("ud")?;
let metatable = ud.get_metatable()?;
@ -583,10 +575,10 @@ fn test_metatable() -> Result<()> {
.map(|kv: Result<(_, Value)>| Ok(kv?.0))
.collect::<Result<Vec<_>>>()?;
methods.sort();
assert_eq!(methods, vec!["__index", "__type_name"]);
assert_eq!(methods, vec!["__index", "__name"]);
#[derive(Copy, Clone)]
struct MyUserData2(i64);
struct MyUserData2;
impl UserData for MyUserData2 {
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
@ -594,12 +586,25 @@ fn test_metatable() -> Result<()> {
}
}
match lua.create_userdata(MyUserData2(1)) {
match lua.create_userdata(MyUserData2) {
Ok(_) => panic!("expected MetaMethodTypeError, got no error"),
Err(Error::MetaMethodTypeError { .. }) => {}
Err(e) => panic!("expected MetaMethodTypeError, got {:?}", e),
}
#[derive(Copy, Clone)]
struct MyUserData3;
impl UserData for MyUserData3 {
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_meta_field_with("__name", |_| Ok("CustomName"));
}
}
let ud = lua.create_userdata(MyUserData3)?;
let metatable = ud.get_metatable()?;
assert_eq!(metatable.get::<String>("__name")?.to_str()?, "CustomName");
Ok(())
}