Skip to content

Commit 4e028d8

Browse files
committed
Change AnyUserData::type_name to return LuaString instead.
This avoids unnecessary allocation and returns type name as it stored in metatable.
1 parent 3d1ae98 commit 4e028d8

2 files changed

Lines changed: 46 additions & 6 deletions

File tree

src/userdata.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::fmt;
88
use std::hash::Hash;
99
use std::os::raw::{c_char, c_void};
1010

11+
use crate::Either;
1112
use crate::error::{Error, Result};
1213
use crate::function::Function;
1314
use crate::state::Lua;
@@ -1028,8 +1029,8 @@ impl AnyUserData {
10281029

10291030
/// Returns a type name of this userdata (from a metatable field).
10301031
///
1031-
/// If no type name is set, returns `None`.
1032-
pub fn type_name(&self) -> Result<Option<String>> {
1032+
/// If no type name is set, returns `userdata`.
1033+
pub fn type_name(&self) -> Result<LuaString> {
10331034
let lua = self.0.lua.lock();
10341035
let state = lua.state();
10351036
unsafe {
@@ -1046,8 +1047,8 @@ impl AnyUserData {
10461047
ffi::luaL_getmetafield(state, -1, MetaMethod::Type.as_cstr().as_ptr())
10471048
};
10481049
match name_type {
1049-
ffi::LUA_TSTRING => Ok(Some(LuaString(lua.pop_ref()).to_str()?.to_owned())),
1050-
_ => Ok(None),
1050+
ffi::LUA_TSTRING => Ok(LuaString(lua.pop_ref())),
1051+
_ => lua.create_string(b"userdata"),
10511052
}
10521053
}
10531054
}
@@ -1108,8 +1109,10 @@ impl AnyUserData {
11081109
match unsafe { self.invoke_tostring_dbg() } {
11091110
Ok(Some(s)) => write!(fmt, "{s}"),
11101111
_ => {
1111-
let name = self.type_name().ok().flatten();
1112-
let name = name.as_deref().unwrap_or("userdata");
1112+
let name = self.type_name().ok();
1113+
let name = (name.as_ref())
1114+
.map(|s| Either::Left(s.display()))
1115+
.unwrap_or(Either::Right("userdata"));
11131116
write!(fmt, "{name}: {:?}", self.to_pointer())
11141117
}
11151118
}

tests/userdata.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,43 @@ fn test_metatable() -> Result<()> {
733733
Ok(())
734734
}
735735

736+
#[test]
737+
fn test_userdata_type_name() -> Result<()> {
738+
struct MyUserData;
739+
impl UserData for MyUserData {}
740+
741+
struct MyUserdataCustom;
742+
impl UserData for MyUserdataCustom {
743+
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
744+
fields.add_meta_field_with(MetaMethod::Type, |_| Ok("MyCustomName"));
745+
}
746+
}
747+
748+
// mlua always sets __name/__type; override with a non-string to test the "userdata" fallback
749+
struct MyUserdataInvalid;
750+
impl UserData for MyUserdataInvalid {
751+
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
752+
fields.add_meta_field_with(MetaMethod::Type, |_| Ok(42_i64));
753+
}
754+
}
755+
756+
let lua = Lua::new();
757+
758+
// Default is the Rust type name
759+
let ud = lua.create_userdata(MyUserData)?;
760+
assert_eq!(ud.type_name()?, "MyUserData");
761+
762+
// Custom name from metatable
763+
let ud = lua.create_userdata(MyUserdataCustom)?;
764+
assert_eq!(ud.type_name()?, "MyCustomName");
765+
766+
// Invalid type name should fallback to "userdata"
767+
let ud = lua.create_userdata(MyUserdataInvalid)?;
768+
assert_eq!(ud.type_name()?.to_str()?, "userdata");
769+
770+
Ok(())
771+
}
772+
736773
#[test]
737774
fn test_userdata_proxy() -> Result<()> {
738775
struct MyUserData(i64);

0 commit comments

Comments
 (0)