diff --git a/src/lua.rs b/src/lua.rs index e851fb1..f0d1632 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -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::(); + 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; diff --git a/tests/userdata.rs b/tests/userdata.rs index 6565a8e..5045f6e 100644 --- a/tests/userdata.rs +++ b/tests/userdata.rs @@ -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::("__type_name") + metatable.get::("__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::>>()?; 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::("__name")?.to_str()?, "CustomName"); + Ok(()) }