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 { unsafe {
let s = self.state_ptr(); let s = self.state_ptr();
lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, lua::LUA_RIDX_GLOBALS); 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 // if the metatable is not made yet, make it
let mt = self.create_userdata_metatable::<T>()?; 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)?; mt.push_to_lua_stack(self)?;
} else if ty != lua::LUA_TTABLE { } else if ty != lua::LUA_TTABLE {
return Err(Error::RegistryConflict(name.to_string())); 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}; use crate::{ensure_type, FromLuaStack, LuaRef, PushToLuaStack, Result, StackGuard, State};
pub(crate) struct MetaTableInfo {
name: Option<String>,
lref: LuaRef,
}
#[derive(Clone)] #[derive(Clone)]
pub struct Table<'a> { pub struct Table<'a> {
state: &'a State, state: &'a State,
pub(crate) lref: LuaRef, 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> { impl<'a> Table<'a> {
@ -31,7 +27,7 @@ impl<'a> Table<'a> {
Ok(Self { Ok(Self {
state, state,
lref, lref,
meta: None, mt_marker: false,
}) })
} }
@ -39,16 +35,10 @@ impl<'a> Table<'a> {
let name_term = format!("{}\0", name); let name_term = format!("{}\0", name);
let name_term_c = name_term.as_str().as_ptr() as *const i8; 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); let _g = StackGuard::new(state);
state.ensure_stack(2)?; 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(); let s = state.state_ptr();
if lua::luaL_newmetatable(s, name_term_c) == 0 { if lua::luaL_newmetatable(s, name_term_c) == 0 {
// lua::luaL_getmetatable does not return the type that was // 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())); return Err(crate::Error::RegistryConflict(name.to_string()));
} }
} }
lua::lua_pushvalue(s, lua::lua_gettop(s)); LuaRef::from_stack(state)?
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)
}; };
Ok(Self { Ok(Self {
state, state,
lref, lref: meta_ref,
meta: Some(meta_ref) mt_marker: true
}) })
} }
/// Construct a table with a lua reference to one. /// 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(); let s = state.state_ptr();
unsafe { unsafe {
@ -91,7 +76,7 @@ impl<'a> Table<'a> {
Ok(Self { Ok(Self {
state, state,
lref: lua_ref, lref: lua_ref,
meta: None, mt_marker: is_metatable,
}) })
} }
@ -107,7 +92,7 @@ impl<'a> Table<'a> {
unsafe { unsafe {
let _g = StackGuard::new(self.state); let _g = StackGuard::new(self.state);
if let Some(_) = &self.meta { if self.mt_marker {
self.state.ensure_stack(4)?; self.state.ensure_stack(4)?;
} else { } else {
self.state.ensure_stack(3)?; self.state.ensure_stack(3)?;
@ -118,11 +103,6 @@ impl<'a> Table<'a> {
val.push_to_lua_stack(self.state)?; val.push_to_lua_stack(self.state)?;
lua::lua_settable(s, -3); lua::lua_settable(s, -3);
if let Some(mt) = &self.meta {
mt.push_to_lua_stack(self.state)?;
lua::lua_setmetatable(s, -2);
}
} }
Ok(()) Ok(())
@ -226,36 +206,26 @@ impl<'a> Table<'a> {
/// Set something in the metatable /// Set something in the metatable
/// ///
/// # Panics /// Does nothing if this table is not a metatable
/// Panics if this table is not a metatable
pub fn set_meta<K, V>(&self, key: K, val: V) -> Result<()> pub fn set_meta<K, V>(&self, key: K, val: V) -> Result<()>
where where
K: PushToLuaStack<'a>, K: PushToLuaStack<'a>,
V: PushToLuaStack<'a> V: PushToLuaStack<'a>
{ {
let mt = self.meta.as_ref() if self.mt_marker {
.expect("this table is not a meta table!");
unsafe { unsafe {
let s = self.state.state_ptr(); let s = self.state.state_ptr();
self.state.ensure_stack(3)?; self.state.ensure_stack(3)?;
let _g = StackGuard::new(self.state); let _g = StackGuard::new(self.state);
mt.push_to_lua_stack(self.state)?; self.lref.push_to_lua_stack(self.state)?;
key.push_to_lua_stack(self.state)?; key.push_to_lua_stack(self.state)?;
val.push_to_lua_stack(self.state)?; val.push_to_lua_stack(self.state)?;
lua::lua_settable(s, -3); lua::lua_settable(s, -3);
} }
Ok(())
} }
/// Returns a handle to the metatable of this table Ok(())
pub fn get_metatable(&self) -> Option<Table> {
self.meta.clone()
.map(|r|
Table::with_ref(self.state, r).unwrap()
)
} }
} }
@ -271,6 +241,6 @@ impl<'a> PushToLuaStack<'a> for Table<'a> {
impl<'a> FromLuaStack<'a> for Table<'a> { impl<'a> FromLuaStack<'a> for Table<'a> {
unsafe fn from_lua_stack(state: &'a State) -> Result<Self> { unsafe fn from_lua_stack(state: &'a State) -> Result<Self> {
ensure_type(state, lua::LUA_TTABLE, -1)?; ensure_type(state, lua::LUA_TTABLE, -1)?;
Table::with_ref(state, LuaRef::from_stack(state)?) Table::with_ref(state, LuaRef::from_stack(state)?, false)
} }
} }