unref LuaRefs when they are dropped

This commit is contained in:
SeanOMik 2024-01-29 10:38:46 -05:00
parent fcc33d4607
commit a3dbe82613
Signed by: SeanOMik
GPG Key ID: FEC9E2FC15235964
5 changed files with 37 additions and 24 deletions

View File

@ -7,7 +7,7 @@ use mlua_sys as lua;
#[derive(Clone)] #[derive(Clone)]
pub struct Function<'a> { pub struct Function<'a> {
state: &'a State, state: &'a State,
lref: LuaRef, lref: LuaRef<'a>,
pub(crate) error_handler: Option<Arc<Function<'a>>>, pub(crate) error_handler: Option<Arc<Function<'a>>>,
} }
@ -28,7 +28,7 @@ impl<'a> PushToLuaStack<'a> for Function<'a> {
} }
impl<'a> Function<'a> { impl<'a> Function<'a> {
pub fn from_ref(state: &'a State, lref: LuaRef) -> Self { pub fn from_ref(state: &'a State, lref: LuaRef<'a>) -> Self {
Self { Self {
state, state,
lref, lref,

View File

@ -143,42 +143,55 @@ fn main() -> Result<()> {
Ok(()) Ok(())
} }
/// A LuaRef is a a handle to something in Lua.
///
/// These are created with `luaL_ref`, they can be created from anything on the top of the stack
/// with [`LuaRef::from_stack`]. The references are automatically freed with `luaL_unref` when
/// the inner Arc detects a single strong count.
#[derive(Clone)] #[derive(Clone)]
pub struct LuaRef(Arc<i32>); pub struct LuaRef<'a>(Arc<i32>, &'a State);
impl From<i32> for LuaRef { impl<'a> Drop for LuaRef<'a> {
fn from(value: i32) -> Self { fn drop(&mut self) {
Self(Arc::new(value)) unsafe {
let s = self.1.state_ptr();
if Arc::strong_count(&self.0) == 1 {
lua::luaL_unref(s, lua::LUA_REGISTRYINDEX, *self.0);
}
}
} }
} }
impl LuaRef { impl<'a> LuaRef<'a> {
pub fn new(lua_ref: i32, state: &'a State) -> Self {
Self(Arc::new(lua_ref), state)
}
/// Creates a reference to what is at the top of the stack. /// Creates a reference to what is at the top of the stack.
pub unsafe fn from_stack(state: &State) -> Result<Self> { pub unsafe fn from_stack(state: &'a State) -> Result<Self> {
let s = state.state_ptr(); let s = state.state_ptr();
let r = lua::luaL_ref(s, lua::LUA_REGISTRYINDEX); let r = lua::luaL_ref(s, lua::LUA_REGISTRYINDEX);
if r == lua::LUA_REFNIL { if r == lua::LUA_REFNIL {
Err(Error::Nil) Err(Error::Nil)
} else { } else {
Ok(LuaRef::from(r)) Ok(LuaRef::new(r, state))
} }
} }
} }
impl<'a> PushToLuaStack<'a> for LuaRef { impl<'a> PushToLuaStack<'a> for LuaRef<'a> {
unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> { unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> {
let s = state.state_ptr(); let s = state.state_ptr();
unsafe { state.ensure_stack(1)?;
state.ensure_stack(1)?; let top = lua::lua_gettop(s);
let top = lua::lua_gettop(s); let ty = lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, *self.0 as i64);
let ty = lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, *self.0 as i64); let new_top = lua::lua_gettop(s);
let new_top = lua::lua_gettop(s);
if ty == lua::LUA_TNIL || ty == lua::LUA_TNONE || top == new_top { if ty == lua::LUA_TNIL || ty == lua::LUA_TNONE || top == new_top {
return Err(Error::Nil); return Err(Error::Nil);
}
} }
Ok(()) Ok(())

View File

@ -88,8 +88,8 @@ struct ClosureData<'a> {
} }
#[derive(Default)] #[derive(Default)]
struct ExtraSpace { struct ExtraSpace<'a> {
userdata_metatables: HashMap<TypeId, LuaRef>, userdata_metatables: HashMap<TypeId, LuaRef<'a>>,
} }
pub struct State { pub struct State {

View File

@ -6,7 +6,7 @@ use crate::{ensure_type, FromLuaStack, LuaRef, PushToLuaStack, Result, StackGuar
#[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<'a>,
/// a boolean indicating if this Table is a Metatable /// a boolean indicating if this Table is a Metatable
mt_marker: bool, mt_marker: bool,
} }
@ -59,7 +59,7 @@ impl<'a> Table<'a> {
} }
/// 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, is_metatable: bool) -> Result<Self> { pub fn with_ref(state: &'a State, lua_ref: LuaRef<'a>, is_metatable: bool) -> Result<Self> {
let s = state.state_ptr(); let s = state.state_ptr();
unsafe { unsafe {

View File

@ -255,12 +255,12 @@ pub trait Userdata: Sized {
/// A handle to some userdata on the stack /// A handle to some userdata on the stack
#[derive(Clone)] #[derive(Clone)]
pub struct AnyUserdata<'a> { pub struct AnyUserdata<'a> {
pub(crate) lref: LuaRef, pub(crate) lref: LuaRef<'a>,
state: &'a State, state: &'a State,
} }
impl<'a> AnyUserdata<'a> { impl<'a> AnyUserdata<'a> {
pub fn from_ref(state: &'a State, lref: LuaRef) -> Self { pub fn from_ref(state: &'a State, lref: LuaRef<'a>) -> Self {
Self { Self {
lref, lref,
state, state,