diff --git a/src/userdata.rs b/src/userdata.rs index af827ad..68edf67 100644 --- a/src/userdata.rs +++ b/src/userdata.rs @@ -19,6 +19,7 @@ use { use crate::error::{Error, Result}; use crate::function::Function; use crate::lua::Lua; +use crate::string::String; use crate::table::{Table, TablePairs}; use crate::types::{Callback, LuaRef, MaybeSend}; use crate::util::{check_stack, get_userdata, take_userdata, StackGuard}; @@ -150,7 +151,7 @@ impl PartialEq for &str { } } -impl PartialEq for String { +impl PartialEq for StdString { fn eq(&self, other: &MetaMethod) -> bool { self == other.name() } @@ -411,18 +412,23 @@ pub trait UserDataMethods<'lua, T> { // #[doc(hidden)] - fn add_callback(&mut self, _name: String, _callback: Callback<'lua, 'static>) {} + fn add_callback(&mut self, _name: StdString, _callback: Callback<'lua, 'static>) {} #[doc(hidden)] #[cfg(feature = "async")] - fn add_async_callback(&mut self, _name: String, _callback: AsyncCallback<'lua, 'static>) {} + fn add_async_callback(&mut self, _name: StdString, _callback: AsyncCallback<'lua, 'static>) {} #[doc(hidden)] - fn add_meta_callback(&mut self, _name: String, _callback: Callback<'lua, 'static>) {} + fn add_meta_callback(&mut self, _name: StdString, _callback: Callback<'lua, 'static>) {} #[doc(hidden)] #[cfg(feature = "async")] - fn add_async_meta_callback(&mut self, _name: String, _callback: AsyncCallback<'lua, 'static>) {} + fn add_async_meta_callback( + &mut self, + _name: StdString, + _callback: AsyncCallback<'lua, 'static>, + ) { + } } /// Field registry for [`UserData`] implementors. @@ -495,10 +501,10 @@ pub trait UserDataFields<'lua, T> { // #[doc(hidden)] - fn add_field_getter(&mut self, _name: String, _callback: Callback<'lua, 'static>) {} + fn add_field_getter(&mut self, _name: StdString, _callback: Callback<'lua, 'static>) {} #[doc(hidden)] - fn add_field_setter(&mut self, _name: String, _callback: Callback<'lua, 'static>) {} + fn add_field_setter(&mut self, _name: StdString, _callback: Callback<'lua, 'static>) {} } /// Trait for custom userdata types. @@ -1045,6 +1051,30 @@ impl<'lua> AnyUserData<'lua> { OwnedAnyUserData(self.0.into_owned()) } + /// Returns a type name of this `UserData` (from `__name` metatable field). + pub(crate) fn type_name(&self) -> Result> { + let lua = self.0.lua; + let state = lua.state(); + unsafe { + let _sg = StackGuard::new(state); + check_stack(state, 3)?; + + lua.push_userdata_ref(&self.0)?; + let protect = !lua.unlikely_memory_error(); + let name_type = if protect { + protect_lua!(state, 1, 1, |state| { + ffi::luaL_getmetafield(state, -1, cstr!("__name")) + })? + } else { + ffi::luaL_getmetafield(state, -1, cstr!("__name")) + }; + match name_type { + ffi::LUA_TSTRING => Ok(Some(String(lua.pop_ref()).to_str()?.to_owned())), + _ => Ok(None), + } + } + } + pub(crate) fn equals>(&self, other: T) -> Result { let other = other.as_ref(); // Uses lua_rawequal() under the hood @@ -1220,7 +1250,7 @@ impl<'lua, V> Iterator for UserDataMetatablePairs<'lua, V> where V: FromLua<'lua>, { - type Item = Result<(String, V)>; + type Item = Result<(StdString, V)>; fn next(&mut self) -> Option { loop { diff --git a/src/value.rs b/src/value.rs index 77ff45c..3f17456 100644 --- a/src/value.rs +++ b/src/value.rs @@ -214,7 +214,7 @@ impl<'lua> Value<'lua> { Value::Nil => write!(fmt, "nil"), Value::Boolean(b) => write!(fmt, "{b}"), Value::LightUserData(ud) if ud.0.is_null() => write!(fmt, "null"), - Value::LightUserData(ud) => write!(fmt, "", ud.0), + Value::LightUserData(ud) => write!(fmt, "lightuserdata: {:?}", ud.0), Value::Integer(i) => write!(fmt, "{i}"), Value::Number(n) => write!(fmt, "{n}"), #[cfg(feature = "luau")] @@ -223,13 +223,16 @@ impl<'lua> Value<'lua> { Value::Table(t) if recursive && !visited.contains(&t.to_pointer()) => { t.fmt_pretty(fmt, ident, visited) } - t @ Value::Table(_) => write!(fmt, "", t.to_pointer()), - f @ Value::Function(_) => write!(fmt, "", f.to_pointer()), - t @ Value::Thread(_) => write!(fmt, "", t.to_pointer()), - // TODO: Show type name for registered userdata - u @ Value::UserData(_) => write!(fmt, "", u.to_pointer()), + t @ Value::Table(_) => write!(fmt, "table: {:?}", t.to_pointer()), + f @ Value::Function(_) => write!(fmt, "function: {:?}", f.to_pointer()), + t @ Value::Thread(_) => write!(fmt, "thread: {:?}", t.to_pointer()), + u @ Value::UserData(ud) => { + let name = ud.type_name().ok().flatten(); + let name = name.unwrap_or_else(|| "userdata".to_string()); + write!(fmt, "{name}: {:?}", u.to_pointer()) + } Value::Error(e) if recursive => write!(fmt, "{e:?}"), - Value::Error(_) => write!(fmt, ""), + Value::Error(_) => write!(fmt, "error"), } } } diff --git a/tests/debug.rs b/tests/debug.rs index 823dc7b..3bb6b8b 100644 --- a/tests/debug.rs +++ b/tests/debug.rs @@ -7,7 +7,7 @@ fn test_debug_format() -> Result<()> { // Globals let globals = lua.globals(); let dump = format!("{globals:#?}"); - assert!(dump.starts_with("{\n [\"_G\"] = Result<()> { Ok(()) } + +#[test] +fn test_debug_format() -> Result<()> { + let lua = Lua::new(); + + lua.register_userdata_type::>(|_| {})?; + let ud = lua + .create_any_userdata::>(HashMap::new()) + .map(Value::UserData)?; + assert!(format!("{ud:#?}").starts_with("HashMap:")); + + Ok(()) +}