mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
Add Lua::type_metatable helper to get metatable of a primitive type.
The accompany function `Lua::set_type_metatable` already exists.
This commit is contained in:
+26
-37
@@ -1514,7 +1514,27 @@ impl Lua {
|
||||
unsafe { self.lock().make_userdata(UserDataStorage::new(ud)) }
|
||||
}
|
||||
|
||||
/// Sets the metatable for a Lua builtin type.
|
||||
/// Gets the metatable of a Lua built-in (primitive) type.
|
||||
///
|
||||
/// The metatable is shared by all values of the given type.
|
||||
///
|
||||
/// See [`Lua::set_type_metatable`] for examples.
|
||||
#[allow(private_bounds)]
|
||||
pub fn type_metatable<T: LuaType>(&self) -> Option<Table> {
|
||||
let lua = self.lock();
|
||||
let state = lua.state();
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(state);
|
||||
assert_stack(state, 2);
|
||||
|
||||
if lua.push_primitive_type::<T>() && ffi::lua_getmetatable(state, -1) != 0 {
|
||||
return Some(Table(lua.pop_ref()));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Sets the metatable for a Lua built-in (primitive) type.
|
||||
///
|
||||
/// The metatable will be shared by all values of the given type.
|
||||
///
|
||||
@@ -1541,44 +1561,13 @@ impl Lua {
|
||||
let _sg = StackGuard::new(state);
|
||||
assert_stack(state, 2);
|
||||
|
||||
match T::TYPE_ID {
|
||||
ffi::LUA_TBOOLEAN => {
|
||||
ffi::lua_pushboolean(state, 0);
|
||||
if lua.push_primitive_type::<T>() {
|
||||
match metatable {
|
||||
Some(metatable) => lua.push_ref(&metatable.0),
|
||||
None => ffi::lua_pushnil(state),
|
||||
}
|
||||
ffi::LUA_TLIGHTUSERDATA => {
|
||||
ffi::lua_pushlightuserdata(state, ptr::null_mut());
|
||||
}
|
||||
ffi::LUA_TNUMBER => {
|
||||
ffi::lua_pushnumber(state, 0.);
|
||||
}
|
||||
#[cfg(feature = "luau")]
|
||||
ffi::LUA_TVECTOR => {
|
||||
#[cfg(not(feature = "luau-vector4"))]
|
||||
ffi::lua_pushvector(state, 0., 0., 0.);
|
||||
#[cfg(feature = "luau-vector4")]
|
||||
ffi::lua_pushvector(state, 0., 0., 0., 0.);
|
||||
}
|
||||
ffi::LUA_TSTRING => {
|
||||
ffi::lua_pushstring(state, b"\0" as *const u8 as *const _);
|
||||
}
|
||||
ffi::LUA_TFUNCTION => match self.load("function() end").eval::<Function>() {
|
||||
Ok(func) => lua.push_ref(&func.0),
|
||||
Err(_) => return,
|
||||
},
|
||||
ffi::LUA_TTHREAD => {
|
||||
ffi::lua_pushthread(state);
|
||||
}
|
||||
#[cfg(feature = "luau")]
|
||||
ffi::LUA_TBUFFER => {
|
||||
ffi::lua_newbuffer(state, 0);
|
||||
}
|
||||
_ => return,
|
||||
ffi::lua_setmetatable(state, -2);
|
||||
}
|
||||
match metatable {
|
||||
Some(metatable) => lua.push_ref(&metatable.0),
|
||||
None => ffi::lua_pushnil(state),
|
||||
}
|
||||
ffi::lua_setmetatable(state, -2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+41
-1
@@ -19,7 +19,7 @@ use crate::thread::Thread;
|
||||
use crate::traits::IntoLua;
|
||||
use crate::types::{
|
||||
AppDataRef, AppDataRefMut, Callback, CallbackUpvalue, DestructedUserdata, Integer, LightUserData,
|
||||
MaybeSend, ReentrantMutex, RegistryKey, ValueRef, XRc,
|
||||
LuaType, MaybeSend, ReentrantMutex, RegistryKey, ValueRef, XRc,
|
||||
};
|
||||
use crate::userdata::{
|
||||
init_userdata_metatable, AnyUserData, MetaMethod, RawUserDataRegistry, UserData, UserDataRegistry,
|
||||
@@ -665,6 +665,46 @@ impl RawLua {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pushes a primitive type value onto the Lua stack.
|
||||
pub(crate) unsafe fn push_primitive_type<T: LuaType>(&self) -> bool {
|
||||
match T::TYPE_ID {
|
||||
ffi::LUA_TBOOLEAN => {
|
||||
ffi::lua_pushboolean(self.state(), 0);
|
||||
}
|
||||
ffi::LUA_TLIGHTUSERDATA => {
|
||||
ffi::lua_pushlightuserdata(self.state(), ptr::null_mut());
|
||||
}
|
||||
ffi::LUA_TNUMBER => {
|
||||
ffi::lua_pushnumber(self.state(), 0.);
|
||||
}
|
||||
#[cfg(feature = "luau")]
|
||||
ffi::LUA_TVECTOR => {
|
||||
#[cfg(not(feature = "luau-vector4"))]
|
||||
ffi::lua_pushvector(self.state(), 0., 0., 0.);
|
||||
#[cfg(feature = "luau-vector4")]
|
||||
ffi::lua_pushvector(self.state(), 0., 0., 0., 0.);
|
||||
}
|
||||
ffi::LUA_TSTRING => {
|
||||
ffi::lua_pushstring(self.state(), b"\0" as *const u8 as *const _);
|
||||
}
|
||||
ffi::LUA_TFUNCTION => {
|
||||
unsafe extern "C-unwind" fn func(_state: *mut ffi::lua_State) -> c_int {
|
||||
0
|
||||
}
|
||||
ffi::lua_pushcfunction(self.state(), func);
|
||||
}
|
||||
ffi::LUA_TTHREAD => {
|
||||
ffi::lua_pushthread(self.state());
|
||||
}
|
||||
#[cfg(feature = "luau")]
|
||||
ffi::LUA_TBUFFER => {
|
||||
ffi::lua_newbuffer(self.state(), 0);
|
||||
}
|
||||
_ => return false,
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Pushes a value that implements `IntoLua` onto the Lua stack.
|
||||
///
|
||||
/// Uses up to 2 stack spaces to push a single value, does not call `checkstack`.
|
||||
|
||||
+2
-6
@@ -1,14 +1,14 @@
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::os::raw::c_void;
|
||||
use std::string::String as StdString;
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::function::Function;
|
||||
use crate::state::{LuaGuard, RawLua, WeakLua};
|
||||
use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, ObjectLike};
|
||||
use crate::types::{Integer, LuaType, ValueRef};
|
||||
use crate::types::{Integer, ValueRef};
|
||||
use crate::util::{assert_stack, check_stack, get_metatable_ptr, StackGuard};
|
||||
use crate::value::{Nil, Value};
|
||||
|
||||
@@ -935,10 +935,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl LuaType for Table {
|
||||
const TYPE_ID: c_int = ffi::LUA_TTABLE;
|
||||
}
|
||||
|
||||
impl ObjectLike for Table {
|
||||
#[inline]
|
||||
fn get<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
|
||||
|
||||
+14
-6
@@ -31,7 +31,9 @@ fn test_boolean_type_metatable() -> Result<()> {
|
||||
|
||||
let mt = lua.create_table()?;
|
||||
mt.set("__add", Function::wrap(|a, b| Ok(a || b)))?;
|
||||
lua.set_type_metatable::<bool>(Some(mt));
|
||||
assert_eq!(lua.type_metatable::<bool>(), None);
|
||||
lua.set_type_metatable::<bool>(Some(mt.clone()));
|
||||
assert_eq!(lua.type_metatable::<bool>().unwrap(), mt);
|
||||
|
||||
lua.load(r#"assert(true + true == true)"#).exec().unwrap();
|
||||
lua.load(r#"assert(true + false == true)"#).exec().unwrap();
|
||||
@@ -52,7 +54,8 @@ fn test_lightuserdata_type_metatable() -> Result<()> {
|
||||
Ok(LightUserData((a.0 as usize + b.0 as usize) as *mut c_void))
|
||||
}),
|
||||
)?;
|
||||
lua.set_type_metatable::<LightUserData>(Some(mt));
|
||||
lua.set_type_metatable::<LightUserData>(Some(mt.clone()));
|
||||
assert_eq!(lua.type_metatable::<LightUserData>().unwrap(), mt);
|
||||
|
||||
let res = lua
|
||||
.load(
|
||||
@@ -77,7 +80,9 @@ fn test_number_type_metatable() -> Result<()> {
|
||||
|
||||
let mt = lua.create_table()?;
|
||||
mt.set("__call", Function::wrap(|n1: f64, n2: f64| Ok(n1 * n2)))?;
|
||||
lua.set_type_metatable::<Number>(Some(mt));
|
||||
lua.set_type_metatable::<Number>(Some(mt.clone()));
|
||||
assert_eq!(lua.type_metatable::<Number>().unwrap(), mt);
|
||||
|
||||
lua.load(r#"assert((1.5)(3.0) == 4.5)"#).exec().unwrap();
|
||||
lua.load(r#"assert((5)(5) == 25)"#).exec().unwrap();
|
||||
|
||||
@@ -93,7 +98,8 @@ fn test_string_type_metatable() -> Result<()> {
|
||||
"__add",
|
||||
Function::wrap(|a: String, b: String| Ok(format!("{a}{b}"))),
|
||||
)?;
|
||||
lua.set_type_metatable::<LuaString>(Some(mt));
|
||||
lua.set_type_metatable::<LuaString>(Some(mt.clone()));
|
||||
assert_eq!(lua.type_metatable::<LuaString>().unwrap(), mt);
|
||||
|
||||
lua.load(r#"assert(("foo" + "bar") == "foobar")"#).exec().unwrap();
|
||||
|
||||
@@ -109,7 +115,8 @@ fn test_function_type_metatable() -> Result<()> {
|
||||
"__index",
|
||||
Function::wrap(|_: Function, key: String| Ok(format!("function.{key}"))),
|
||||
)?;
|
||||
lua.set_type_metatable::<Function>(Some(mt));
|
||||
lua.set_type_metatable::<Function>(Some(mt.clone()));
|
||||
assert_eq!(lua.type_metatable::<Function>(), Some(mt));
|
||||
|
||||
lua.load(r#"assert((function() end).foo == "function.foo")"#)
|
||||
.exec()
|
||||
@@ -127,7 +134,8 @@ fn test_thread_type_metatable() -> Result<()> {
|
||||
"__index",
|
||||
Function::wrap(|_: Thread, key: String| Ok(format!("thread.{key}"))),
|
||||
)?;
|
||||
lua.set_type_metatable::<Thread>(Some(mt));
|
||||
lua.set_type_metatable::<Thread>(Some(mt.clone()));
|
||||
assert_eq!(lua.type_metatable::<Thread>(), Some(mt));
|
||||
|
||||
lua.load(r#"assert((coroutine.create(function() end)).foo == "thread.foo")"#)
|
||||
.exec()
|
||||
|
||||
Reference in New Issue
Block a user