Skip to content

Commit 0611906

Browse files
committed
Add Lua::type_metatable helper to get metatable of a primitive type.
The accompany function `Lua::set_type_metatable` already exists.
1 parent 72ac247 commit 0611906

File tree

4 files changed

+83
-50
lines changed

4 files changed

+83
-50
lines changed

src/state.rs

Lines changed: 26 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,7 +1514,27 @@ impl Lua {
15141514
unsafe { self.lock().make_userdata(UserDataStorage::new(ud)) }
15151515
}
15161516

1517-
/// Sets the metatable for a Lua builtin type.
1517+
/// Gets the metatable of a Lua built-in (primitive) type.
1518+
///
1519+
/// The metatable is shared by all values of the given type.
1520+
///
1521+
/// See [`Lua::set_type_metatable`] for examples.
1522+
#[allow(private_bounds)]
1523+
pub fn type_metatable<T: LuaType>(&self) -> Option<Table> {
1524+
let lua = self.lock();
1525+
let state = lua.state();
1526+
unsafe {
1527+
let _sg = StackGuard::new(state);
1528+
assert_stack(state, 2);
1529+
1530+
if lua.push_primitive_type::<T>() && ffi::lua_getmetatable(state, -1) != 0 {
1531+
return Some(Table(lua.pop_ref()));
1532+
}
1533+
}
1534+
None
1535+
}
1536+
1537+
/// Sets the metatable for a Lua built-in (primitive) type.
15181538
///
15191539
/// The metatable will be shared by all values of the given type.
15201540
///
@@ -1541,44 +1561,13 @@ impl Lua {
15411561
let _sg = StackGuard::new(state);
15421562
assert_stack(state, 2);
15431563

1544-
match T::TYPE_ID {
1545-
ffi::LUA_TBOOLEAN => {
1546-
ffi::lua_pushboolean(state, 0);
1547-
}
1548-
ffi::LUA_TLIGHTUSERDATA => {
1549-
ffi::lua_pushlightuserdata(state, ptr::null_mut());
1550-
}
1551-
ffi::LUA_TNUMBER => {
1552-
ffi::lua_pushnumber(state, 0.);
1553-
}
1554-
#[cfg(feature = "luau")]
1555-
ffi::LUA_TVECTOR => {
1556-
#[cfg(not(feature = "luau-vector4"))]
1557-
ffi::lua_pushvector(state, 0., 0., 0.);
1558-
#[cfg(feature = "luau-vector4")]
1559-
ffi::lua_pushvector(state, 0., 0., 0., 0.);
1564+
if lua.push_primitive_type::<T>() {
1565+
match metatable {
1566+
Some(metatable) => lua.push_ref(&metatable.0),
1567+
None => ffi::lua_pushnil(state),
15601568
}
1561-
ffi::LUA_TSTRING => {
1562-
ffi::lua_pushstring(state, b"\0" as *const u8 as *const _);
1563-
}
1564-
ffi::LUA_TFUNCTION => match self.load("function() end").eval::<Function>() {
1565-
Ok(func) => lua.push_ref(&func.0),
1566-
Err(_) => return,
1567-
},
1568-
ffi::LUA_TTHREAD => {
1569-
ffi::lua_pushthread(state);
1570-
}
1571-
#[cfg(feature = "luau")]
1572-
ffi::LUA_TBUFFER => {
1573-
ffi::lua_newbuffer(state, 0);
1574-
}
1575-
_ => return,
1576-
}
1577-
match metatable {
1578-
Some(metatable) => lua.push_ref(&metatable.0),
1579-
None => ffi::lua_pushnil(state),
1569+
ffi::lua_setmetatable(state, -2);
15801570
}
1581-
ffi::lua_setmetatable(state, -2);
15821571
}
15831572
}
15841573

src/state/raw.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::thread::Thread;
1919
use crate::traits::IntoLua;
2020
use crate::types::{
2121
AppDataRef, AppDataRefMut, Callback, CallbackUpvalue, DestructedUserdata, Integer, LightUserData,
22-
MaybeSend, ReentrantMutex, RegistryKey, ValueRef, XRc,
22+
LuaType, MaybeSend, ReentrantMutex, RegistryKey, ValueRef, XRc,
2323
};
2424
use crate::userdata::{
2525
init_userdata_metatable, AnyUserData, MetaMethod, RawUserDataRegistry, UserData, UserDataRegistry,
@@ -665,6 +665,46 @@ impl RawLua {
665665
}
666666
}
667667

668+
/// Pushes a primitive type value onto the Lua stack.
669+
pub(crate) unsafe fn push_primitive_type<T: LuaType>(&self) -> bool {
670+
match T::TYPE_ID {
671+
ffi::LUA_TBOOLEAN => {
672+
ffi::lua_pushboolean(self.state(), 0);
673+
}
674+
ffi::LUA_TLIGHTUSERDATA => {
675+
ffi::lua_pushlightuserdata(self.state(), ptr::null_mut());
676+
}
677+
ffi::LUA_TNUMBER => {
678+
ffi::lua_pushnumber(self.state(), 0.);
679+
}
680+
#[cfg(feature = "luau")]
681+
ffi::LUA_TVECTOR => {
682+
#[cfg(not(feature = "luau-vector4"))]
683+
ffi::lua_pushvector(self.state(), 0., 0., 0.);
684+
#[cfg(feature = "luau-vector4")]
685+
ffi::lua_pushvector(self.state(), 0., 0., 0., 0.);
686+
}
687+
ffi::LUA_TSTRING => {
688+
ffi::lua_pushstring(self.state(), b"\0" as *const u8 as *const _);
689+
}
690+
ffi::LUA_TFUNCTION => {
691+
unsafe extern "C-unwind" fn func(_state: *mut ffi::lua_State) -> c_int {
692+
0
693+
}
694+
ffi::lua_pushcfunction(self.state(), func);
695+
}
696+
ffi::LUA_TTHREAD => {
697+
ffi::lua_pushthread(self.state());
698+
}
699+
#[cfg(feature = "luau")]
700+
ffi::LUA_TBUFFER => {
701+
ffi::lua_newbuffer(self.state(), 0);
702+
}
703+
_ => return false,
704+
}
705+
true
706+
}
707+
668708
/// Pushes a value that implements `IntoLua` onto the Lua stack.
669709
///
670710
/// Uses up to 2 stack spaces to push a single value, does not call `checkstack`.

src/table.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use std::collections::HashSet;
22
use std::fmt;
33
use std::marker::PhantomData;
4-
use std::os::raw::{c_int, c_void};
4+
use std::os::raw::c_void;
55
use std::string::String as StdString;
66

77
use crate::error::{Error, Result};
88
use crate::function::Function;
99
use crate::state::{LuaGuard, RawLua, WeakLua};
1010
use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, ObjectLike};
11-
use crate::types::{Integer, LuaType, ValueRef};
11+
use crate::types::{Integer, ValueRef};
1212
use crate::util::{assert_stack, check_stack, get_metatable_ptr, StackGuard};
1313
use crate::value::{Nil, Value};
1414

@@ -935,10 +935,6 @@ where
935935
}
936936
}
937937

938-
impl LuaType for Table {
939-
const TYPE_ID: c_int = ffi::LUA_TTABLE;
940-
}
941-
942938
impl ObjectLike for Table {
943939
#[inline]
944940
fn get<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {

tests/types.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ fn test_boolean_type_metatable() -> Result<()> {
3131

3232
let mt = lua.create_table()?;
3333
mt.set("__add", Function::wrap(|a, b| Ok(a || b)))?;
34-
lua.set_type_metatable::<bool>(Some(mt));
34+
assert_eq!(lua.type_metatable::<bool>(), None);
35+
lua.set_type_metatable::<bool>(Some(mt.clone()));
36+
assert_eq!(lua.type_metatable::<bool>().unwrap(), mt);
3537

3638
lua.load(r#"assert(true + true == true)"#).exec().unwrap();
3739
lua.load(r#"assert(true + false == true)"#).exec().unwrap();
@@ -52,7 +54,8 @@ fn test_lightuserdata_type_metatable() -> Result<()> {
5254
Ok(LightUserData((a.0 as usize + b.0 as usize) as *mut c_void))
5355
}),
5456
)?;
55-
lua.set_type_metatable::<LightUserData>(Some(mt));
57+
lua.set_type_metatable::<LightUserData>(Some(mt.clone()));
58+
assert_eq!(lua.type_metatable::<LightUserData>().unwrap(), mt);
5659

5760
let res = lua
5861
.load(
@@ -77,7 +80,9 @@ fn test_number_type_metatable() -> Result<()> {
7780

7881
let mt = lua.create_table()?;
7982
mt.set("__call", Function::wrap(|n1: f64, n2: f64| Ok(n1 * n2)))?;
80-
lua.set_type_metatable::<Number>(Some(mt));
83+
lua.set_type_metatable::<Number>(Some(mt.clone()));
84+
assert_eq!(lua.type_metatable::<Number>().unwrap(), mt);
85+
8186
lua.load(r#"assert((1.5)(3.0) == 4.5)"#).exec().unwrap();
8287
lua.load(r#"assert((5)(5) == 25)"#).exec().unwrap();
8388

@@ -93,7 +98,8 @@ fn test_string_type_metatable() -> Result<()> {
9398
"__add",
9499
Function::wrap(|a: String, b: String| Ok(format!("{a}{b}"))),
95100
)?;
96-
lua.set_type_metatable::<LuaString>(Some(mt));
101+
lua.set_type_metatable::<LuaString>(Some(mt.clone()));
102+
assert_eq!(lua.type_metatable::<LuaString>().unwrap(), mt);
97103

98104
lua.load(r#"assert(("foo" + "bar") == "foobar")"#).exec().unwrap();
99105

@@ -109,7 +115,8 @@ fn test_function_type_metatable() -> Result<()> {
109115
"__index",
110116
Function::wrap(|_: Function, key: String| Ok(format!("function.{key}"))),
111117
)?;
112-
lua.set_type_metatable::<Function>(Some(mt));
118+
lua.set_type_metatable::<Function>(Some(mt.clone()));
119+
assert_eq!(lua.type_metatable::<Function>(), Some(mt));
113120

114121
lua.load(r#"assert((function() end).foo == "function.foo")"#)
115122
.exec()
@@ -127,7 +134,8 @@ fn test_thread_type_metatable() -> Result<()> {
127134
"__index",
128135
Function::wrap(|_: Thread, key: String| Ok(format!("thread.{key}"))),
129136
)?;
130-
lua.set_type_metatable::<Thread>(Some(mt));
137+
lua.set_type_metatable::<Thread>(Some(mt.clone()));
138+
assert_eq!(lua.type_metatable::<Thread>(), Some(mt));
131139

132140
lua.load(r#"assert((coroutine.create(function() end)).foo == "thread.foo")"#)
133141
.exec()

0 commit comments

Comments
 (0)