make it so a Table can only be a normal table, or a metatable, not both at the same time

This commit is contained in:
SeanOMik 2024-01-27 11:00:02 -05:00
parent 2b03b55014
commit 9ef4203619
Signed by: SeanOMik
GPG Key ID: FEC9E2FC15235964
2 changed files with 24 additions and 54 deletions

View File

@ -173,7 +173,7 @@ impl State {
unsafe {
let s = self.state_ptr();
lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, lua::LUA_RIDX_GLOBALS);
Table::with_ref(self, LuaRef::from_stack(self)?)
Table::with_ref(self, LuaRef::from_stack(self)?, false)
}
}
@ -297,7 +297,7 @@ impl State {
// if the metatable is not made yet, make it
let mt = self.create_userdata_metatable::<T>()?;
let mt = mt.get_metatable().unwrap(); // the table 100% has a metatable
//let mt = mt.get_metatable().unwrap(); // the table 100% has a metatable
mt.push_to_lua_stack(self)?;
} else if ty != lua::LUA_TTABLE {
return Err(Error::RegistryConflict(name.to_string()));

View File

@ -5,16 +5,12 @@ use mlua_sys as lua;
use crate::{ensure_type, FromLuaStack, LuaRef, PushToLuaStack, Result, StackGuard, State};
pub(crate) struct MetaTableInfo {
name: Option<String>,
lref: LuaRef,
}
#[derive(Clone)]
pub struct Table<'a> {
state: &'a State,
pub(crate) lref: LuaRef,
pub(crate) meta: Option<LuaRef>, // Some if this table is a metatable
/// a boolean indicating if this Table is a Metatable
mt_marker: bool,
}
impl<'a> Table<'a> {
@ -31,7 +27,7 @@ impl<'a> Table<'a> {
Ok(Self {
state,
lref,
meta: None,
mt_marker: false,
})
}
@ -39,16 +35,10 @@ impl<'a> Table<'a> {
let name_term = format!("{}\0", name);
let name_term_c = name_term.as_str().as_ptr() as *const i8;
let (lref, meta_ref) = unsafe {
let meta_ref = unsafe {
let _g = StackGuard::new(state);
state.ensure_stack(2)?;
// create the table, this will be retrieved from
// stack after the metatable is created
let s = state.state_ptr();
lua::lua_newtable(s);
//let table_idx = lua::lua_gettop(s);
let s = state.state_ptr();
if lua::luaL_newmetatable(s, name_term_c) == 0 {
// lua::luaL_getmetatable does not return the type that was
@ -60,23 +50,18 @@ impl<'a> Table<'a> {
return Err(crate::Error::RegistryConflict(name.to_string()));
}
}
lua::lua_pushvalue(s, lua::lua_gettop(s));
lua::lua_setmetatable(s, -3); // -3 here since the metatable was added twice
let meta = LuaRef::from_stack(state)?;
// retrieve the table created before the metatable
(LuaRef::from_stack(state)?, meta)
LuaRef::from_stack(state)?
};
Ok(Self {
state,
lref,
meta: Some(meta_ref)
lref: meta_ref,
mt_marker: true
})
}
/// Construct a table with a lua reference to one.
pub fn with_ref(state: &'a State, lua_ref: LuaRef) -> Result<Self> {
pub fn with_ref(state: &'a State, lua_ref: LuaRef, is_metatable: bool) -> Result<Self> {
let s = state.state_ptr();
unsafe {
@ -91,7 +76,7 @@ impl<'a> Table<'a> {
Ok(Self {
state,
lref: lua_ref,
meta: None,
mt_marker: is_metatable,
})
}
@ -107,7 +92,7 @@ impl<'a> Table<'a> {
unsafe {
let _g = StackGuard::new(self.state);
if let Some(_) = &self.meta {
if self.mt_marker {
self.state.ensure_stack(4)?;
} else {
self.state.ensure_stack(3)?;
@ -118,11 +103,6 @@ impl<'a> Table<'a> {
val.push_to_lua_stack(self.state)?;
lua::lua_settable(s, -3);
if let Some(mt) = &self.meta {
mt.push_to_lua_stack(self.state)?;
lua::lua_setmetatable(s, -2);
}
}
Ok(())
@ -226,37 +206,27 @@ impl<'a> Table<'a> {
/// Set something in the metatable
///
/// # Panics
/// Panics if this table is not a metatable
/// Does nothing if this table is not a metatable
pub fn set_meta<K, V>(&self, key: K, val: V) -> Result<()>
where
K: PushToLuaStack<'a>,
V: PushToLuaStack<'a>
{
let mt = self.meta.as_ref()
.expect("this table is not a meta table!");
if self.mt_marker {
unsafe {
let s = self.state.state_ptr();
self.state.ensure_stack(3)?;
let _g = StackGuard::new(self.state);
unsafe {
let s = self.state.state_ptr();
self.state.ensure_stack(3)?;
let _g = StackGuard::new(self.state);
mt.push_to_lua_stack(self.state)?;
key.push_to_lua_stack(self.state)?;
val.push_to_lua_stack(self.state)?;
lua::lua_settable(s, -3);
self.lref.push_to_lua_stack(self.state)?;
key.push_to_lua_stack(self.state)?;
val.push_to_lua_stack(self.state)?;
lua::lua_settable(s, -3);
}
}
Ok(())
}
/// Returns a handle to the metatable of this table
pub fn get_metatable(&self) -> Option<Table> {
self.meta.clone()
.map(|r|
Table::with_ref(self.state, r).unwrap()
)
}
}
impl<'a> PushToLuaStack<'a> for Table<'a> {
@ -271,6 +241,6 @@ impl<'a> PushToLuaStack<'a> for Table<'a> {
impl<'a> FromLuaStack<'a> for Table<'a> {
unsafe fn from_lua_stack(state: &'a State) -> Result<Self> {
ensure_type(state, lua::LUA_TTABLE, -1)?;
Table::with_ref(state, LuaRef::from_stack(state)?)
Table::with_ref(state, LuaRef::from_stack(state)?, false)
}
}