Skip to content

Commit 8274b5f

Browse files
committed
More user-friendly error message on userdata mismatch
1 parent 762e677 commit 8274b5f

File tree

4 files changed

+38
-19
lines changed

4 files changed

+38
-19
lines changed

src/state/raw.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -1004,8 +1004,18 @@ impl RawLua {
10041004
}
10051005

10061006
// Same as `get_userdata_ref_type_id` but assumes the userdata is already on the stack.
1007-
pub(crate) unsafe fn get_userdata_type_id(&self, idx: c_int) -> Result<Option<TypeId>> {
1008-
self.get_userdata_type_id_inner(self.state(), idx)
1007+
pub(crate) unsafe fn get_userdata_type_id<T>(&self, idx: c_int) -> Result<Option<TypeId>> {
1008+
match self.get_userdata_type_id_inner(self.state(), idx) {
1009+
Ok(type_id) => Ok(type_id),
1010+
Err(Error::UserDataTypeMismatch) if ffi::lua_type(self.state(), idx) != ffi::LUA_TUSERDATA => {
1011+
// Report `FromLuaConversionError` instead
1012+
let idx_type_name = CStr::from_ptr(ffi::luaL_typename(self.state(), idx));
1013+
let idx_type_name = idx_type_name.to_str().unwrap();
1014+
let message = format!("expected userdata of type '{}'", short_type_name::<T>());
1015+
Err(Error::from_lua_conversion(idx_type_name, "userdata", message))
1016+
}
1017+
Err(err) => Err(err),
1018+
}
10091019
}
10101020

10111021
unsafe fn get_userdata_type_id_inner(

src/userdata/cell.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ impl<T: 'static> FromLua for UserDataRef<T> {
195195
}
196196

197197
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
198-
let type_id = lua.get_userdata_type_id(idx)?;
198+
let type_id = lua.get_userdata_type_id::<T>(idx)?;
199199
match type_id {
200200
Some(type_id) if type_id == TypeId::of::<T>() => {
201201
(*get_userdata::<UserDataStorage<T>>(lua.state(), idx)).try_borrow_owned()
@@ -263,7 +263,7 @@ impl<T: 'static> FromLua for UserDataRefMut<T> {
263263
}
264264

265265
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
266-
let type_id = lua.get_userdata_type_id(idx)?;
266+
let type_id = lua.get_userdata_type_id::<T>(idx)?;
267267
match type_id {
268268
Some(type_id) if type_id == TypeId::of::<T>() => {
269269
(*get_userdata::<UserDataStorage<T>>(lua.state(), idx)).try_borrow_owned_mut()

src/userdata/registry.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ impl<T> UserDataRegistry<T> {
121121
match target_type_id {
122122
// This branch is for `'static` userdata that share type metatable
123123
UserDataTypeId::Shared(target_type_id) => {
124-
match try_self_arg!(rawlua.get_userdata_type_id(self_index)) {
124+
match try_self_arg!(rawlua.get_userdata_type_id::<T>(self_index)) {
125125
Some(self_type_id) if self_type_id == target_type_id => {
126126
let ud = get_userdata::<UserDataStorage<T>>(state, self_index);
127127
try_self_arg!((*ud).try_borrow_scoped(|ud| {
@@ -175,7 +175,7 @@ impl<T> UserDataRegistry<T> {
175175
match target_type_id {
176176
// This branch is for `'static` userdata that share type metatable
177177
UserDataTypeId::Shared(target_type_id) => {
178-
match try_self_arg!(rawlua.get_userdata_type_id(self_index)) {
178+
match try_self_arg!(rawlua.get_userdata_type_id::<T>(self_index)) {
179179
Some(self_type_id) if self_type_id == target_type_id => {
180180
let ud = get_userdata::<UserDataStorage<T>>(state, self_index);
181181
try_self_arg!((*ud).try_borrow_scoped_mut(|ud| {

tests/userdata.rs

+22-13
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,8 @@ fn test_metamethods() -> Result<()> {
206206
Ok(())
207207
}
208208

209-
#[test]
210209
#[cfg(feature = "lua54")]
210+
#[test]
211211
fn test_metamethod_close() -> Result<()> {
212212
#[derive(Clone)]
213213
struct MyUserData(Arc<AtomicI64>);
@@ -791,18 +791,27 @@ fn test_userdata_method_errors() -> Result<()> {
791791
let lua = Lua::new();
792792

793793
let ud = lua.create_userdata(MyUserData(123))?;
794-
let res = ud.call_function::<()>("get_value", ());
795-
let Err(Error::CallbackError { cause, .. }) = res else {
796-
panic!("expected CallbackError, got {res:?}");
797-
};
798-
assert!(matches!(
799-
&*cause,
800-
Error::BadArgument {
801-
to,
802-
name,
803-
..
804-
} if to.as_deref() == Some("MyUserData.get_value") && name.as_deref() == Some("self")
805-
));
794+
let res = ud.call_function::<()>("get_value", "not a userdata");
795+
match res {
796+
Err(Error::CallbackError { cause, .. }) => match cause.as_ref() {
797+
Error::BadArgument {
798+
to,
799+
name,
800+
cause: cause2,
801+
..
802+
} => {
803+
assert_eq!(to.as_deref(), Some("MyUserData.get_value"));
804+
assert_eq!(name.as_deref(), Some("self"));
805+
println!("{}", cause2.to_string());
806+
assert_eq!(
807+
cause2.to_string(),
808+
"error converting Lua string to userdata (expected userdata of type 'MyUserData')"
809+
);
810+
}
811+
err => panic!("expected BadArgument, got {err:?}"),
812+
},
813+
r => panic!("expected CallbackError, got {r:?}"),
814+
}
806815

807816
Ok(())
808817
}

0 commit comments

Comments
 (0)