Remove SubtypeId from AnyUserData and instead add Value::Other variant that will cover any unknown types (eg. LuaJIT CData)

This commit is contained in:
Alex Orlenko
2024-10-02 12:16:48 +01:00
parent b6cdf32f16
commit 04d8106676
9 changed files with 31 additions and 52 deletions
+2 -2
View File
@@ -6,7 +6,7 @@ use std::os::raw::c_void;
use crate::error::{Error, Result};
use crate::function::Function;
use crate::state::{Lua, LuaGuard, RawLua};
use crate::types::{Callback, CallbackUpvalue, ScopedCallback, SubtypeId, ValueRef};
use crate::types::{Callback, CallbackUpvalue, ScopedCallback, ValueRef};
use crate::userdata::{AnyUserData, UserData, UserDataRegistry, UserDataStorage};
use crate::util::{self, assert_stack, check_stack, get_userdata, take_userdata, StackGuard};
use crate::value::{FromLuaMulti, IntoLuaMulti};
@@ -186,7 +186,7 @@ impl<'scope, 'env: 'scope> Scope<'scope, 'env> {
std::ptr::write(ud_ptr, UserDataStorage::new_scoped(data));
ffi::lua_setmetatable(state, -2);
let ud = AnyUserData(self.lua.pop_ref(), SubtypeId::None);
let ud = AnyUserData(self.lua.pop_ref());
let destructor: DestructorCallback = Box::new(|rawlua, vref| {
let state = rawlua.state();
+2 -1
View File
@@ -150,7 +150,8 @@ impl<'de> serde::Deserializer<'de> for Deserializer {
| Value::Thread(_)
| Value::UserData(_)
| Value::LightUserData(_)
| Value::Error(_) => {
| Value::Error(_)
| Value::Other(_) => {
if self.options.deny_unsupported_types {
let msg = format!("unsupported value type `{}`", self.value.type_name());
Err(de::Error::custom(msg))
+6 -9
View File
@@ -18,7 +18,7 @@ use crate::table::Table;
use crate::thread::Thread;
use crate::types::{
AppDataRef, AppDataRefMut, Callback, CallbackUpvalue, DestructedUserdata, Integer, LightUserData,
MaybeSend, ReentrantMutex, RegistryKey, SubtypeId, ValueRef, XRc,
MaybeSend, ReentrantMutex, RegistryKey, ValueRef, XRc,
};
use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataRegistry, UserDataStorage};
use crate::util::{
@@ -560,6 +560,7 @@ impl RawLua {
let protect = !self.unlikely_memory_error();
push_internal_userdata(state, WrappedFailure::Error(*err.clone()), protect)?;
}
Value::Other(vref) => self.push_ref(vref),
}
Ok(())
}
@@ -644,7 +645,7 @@ impl RawLua {
}
_ => {
ffi::lua_xpush(state, self.ref_thread(), idx);
Value::UserData(AnyUserData(self.pop_ref_thread(), SubtypeId::None))
Value::UserData(AnyUserData(self.pop_ref_thread()))
}
}
}
@@ -661,14 +662,10 @@ impl RawLua {
Value::Buffer(crate::Buffer(self.pop_ref_thread()))
}
#[cfg(feature = "luajit")]
ffi::LUA_TCDATA => {
// CData is represented as a userdata type
_ => {
ffi::lua_xpush(state, self.ref_thread(), idx);
Value::UserData(AnyUserData(self.pop_ref_thread(), SubtypeId::CData))
Value::Other(self.pop_ref_thread())
}
_ => mlua_panic!("unexpected value type on stack"),
}
}
@@ -806,7 +803,7 @@ impl RawLua {
ffi::lua_setuservalue(state, -2);
}
Ok(AnyUserData(self.pop_ref(), SubtypeId::None))
Ok(AnyUserData(self.pop_ref()))
}
pub(crate) unsafe fn create_userdata_metatable<T>(
-8
View File
@@ -28,14 +28,6 @@ pub type Integer = ffi::lua_Integer;
/// Type of Lua floating point numbers.
pub type Number = ffi::lua_Number;
// Represents different subtypes wrapped in AnyUserData
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(crate) enum SubtypeId {
None,
#[cfg(feature = "luajit")]
CData,
}
/// A "light" userdata value. Equivalent to an unmanaged raw pointer.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct LightUserData(pub *mut c_void);
+2 -8
View File
@@ -19,7 +19,7 @@ use crate::function::Function;
use crate::state::Lua;
use crate::string::String;
use crate::table::{Table, TablePairs};
use crate::types::{MaybeSend, SubtypeId, ValueRef};
use crate::types::{MaybeSend, ValueRef};
use crate::util::{check_stack, get_userdata, take_userdata, StackGuard};
use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Value};
@@ -643,7 +643,7 @@ pub trait UserData: Sized {
/// [`is`]: crate::AnyUserData::is
/// [`borrow`]: crate::AnyUserData::borrow
#[derive(Clone, Debug)]
pub struct AnyUserData(pub(crate) ValueRef, pub(crate) SubtypeId);
pub struct AnyUserData(pub(crate) ValueRef);
impl AnyUserData {
/// Checks whether the type of this userdata is `T`.
@@ -935,12 +935,6 @@ impl AnyUserData {
/// Returns a type name of this `UserData` (from a metatable field).
pub(crate) fn type_name(&self) -> Result<Option<StdString>> {
match self.1 {
SubtypeId::None => {}
#[cfg(feature = "luajit")]
SubtypeId::CData => return Ok(Some("cdata".to_owned())),
}
let lua = self.0.lua.lock();
let state = lua.state();
unsafe {
+1 -1
View File
@@ -88,6 +88,6 @@ impl ObjectLike for AnyUserData {
#[inline]
fn to_string(&self) -> Result<StdString> {
Value::UserData(AnyUserData(self.0.copy(), self.1)).to_string()
Value::UserData(AnyUserData(self.0.copy())).to_string()
}
}
+4 -3
View File
@@ -275,9 +275,10 @@ pub(crate) unsafe fn to_string(state: *mut ffi::lua_State, index: c_int) -> Stri
ffi::LUA_TTHREAD => format!("<thread {:?}>", ffi::lua_topointer(state, index)),
#[cfg(feature = "luau")]
ffi::LUA_TBUFFER => format!("<buffer {:?}>", ffi::lua_topointer(state, index)),
#[cfg(feature = "luajit")]
ffi::LUA_TCDATA => format!("<cdata {:?}>", ffi::lua_topointer(state, index)),
_ => "<unknown>".to_string(),
type_id => {
let type_name = CStr::from_ptr(ffi::lua_typename(state, type_id)).to_string_lossy();
format!("<{type_name} {:?}>", ffi::lua_topointer(state, index))
}
}
}
+13 -18
View File
@@ -14,7 +14,7 @@ use crate::state::{Lua, RawLua};
use crate::string::{BorrowedStr, String};
use crate::table::Table;
use crate::thread::Thread;
use crate::types::{Integer, LightUserData, Number, SubtypeId, ValueRef};
use crate::types::{Integer, LightUserData, Number, ValueRef};
use crate::userdata::AnyUserData;
use crate::util::{check_stack, StackGuard};
@@ -28,7 +28,7 @@ use {
/// A dynamically typed Lua value.
///
/// The `String`, `Table`, `Function`, `Thread`, and `UserData` variants contain handle types
/// The non-primitive variants (eg. string/table/function/thread/userdata) contain handle types
/// into the internal Lua state. It is a logic error to mix handle types between separate
/// `Lua` instances, and doing so will result in a panic.
#[derive(Clone)]
@@ -69,6 +69,9 @@ pub enum Value {
Buffer(crate::Buffer),
/// `Error` is a special builtin userdata type. When received from Lua it is implicitly cloned.
Error(Box<Error>),
/// Any other value not known to mlua (eg. LuaJIT CData).
#[allow(private_interfaces)]
Other(ValueRef),
}
pub use self::Value::Nil;
@@ -93,12 +96,11 @@ impl Value {
Value::Table(_) => "table",
Value::Function(_) => "function",
Value::Thread(_) => "thread",
Value::UserData(AnyUserData(_, SubtypeId::None)) => "userdata",
#[cfg(feature = "luajit")]
Value::UserData(AnyUserData(_, SubtypeId::CData)) => "cdata",
Value::UserData(_) => "userdata",
#[cfg(feature = "luau")]
Value::Buffer(_) => "buffer",
Value::Error(_) => "error",
Value::Other(_) => "other",
}
}
@@ -173,7 +175,8 @@ impl Value {
Value::Table(Table(vref))
| Value::Function(Function(vref))
| Value::Thread(Thread(vref, ..))
| Value::UserData(AnyUserData(vref, ..)) => unsafe { invoke_to_string(vref) },
| Value::UserData(AnyUserData(vref))
| Value::Other(vref) => unsafe { invoke_to_string(vref) },
#[cfg(feature = "luau")]
Value::Buffer(crate::Buffer(vref)) => unsafe { invoke_to_string(vref) },
Value::Error(err) => Ok(err.to_string()),
@@ -448,17 +451,6 @@ impl Value {
self.as_buffer().is_some()
}
/// Returns `true` if the value is a CData wrapped in [`AnyUserData`].
#[cfg(any(feature = "luajit", doc))]
#[cfg_attr(docsrs, doc(cfg(feature = "luajit")))]
#[doc(hidden)]
#[inline]
pub fn is_cdata(&self) -> bool {
self.as_userdata()
.map(|ud| ud.1 == SubtypeId::CData)
.unwrap_or_default()
}
/// Wrap reference to this Value into [`SerializableValue`].
///
/// This allows customizing serialization behavior using serde.
@@ -548,6 +540,7 @@ impl Value {
buf @ Value::Buffer(_) => write!(fmt, "buffer: {:?}", buf.to_pointer()),
Value::Error(e) if recursive => write!(fmt, "{e:?}"),
Value::Error(_) => write!(fmt, "error"),
Value::Other(v) => write!(fmt, "other: {:?}", v.to_pointer()),
}
}
}
@@ -574,6 +567,7 @@ impl fmt::Debug for Value {
#[cfg(feature = "luau")]
Value::Buffer(buf) => write!(fmt, "{buf:?}"),
Value::Error(e) => write!(fmt, "Error({e:?})"),
Value::Other(v) => write!(fmt, "Other({v:?})"),
}
}
}
@@ -711,7 +705,8 @@ impl<'a> Serialize for SerializableValue<'a> {
| Value::Thread(_)
| Value::UserData(_)
| Value::LightUserData(_)
| Value::Error(_) => {
| Value::Error(_)
| Value::Other(_) => {
if self.options.deny_unsupported_types {
let msg = format!("cannot serialize <{}>", self.value.type_name());
Err(ser::Error::custom(msg))
+1 -2
View File
@@ -1256,8 +1256,7 @@ fn test_luajit_cdata() -> Result<()> {
"#,
)
.eval::<Value>()?;
assert!(cdata.is_userdata() && cdata.is_cdata());
assert_eq!(cdata.type_name(), "cdata");
assert_eq!(cdata.type_name(), "other");
assert!(cdata.to_string()?.starts_with("cdata<void *>:"));
Ok(())