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)]
pub struct Function<'a> {
state: &'a State,
lref: LuaRef,
lref: LuaRef<'a>,
pub(crate) error_handler: Option<Arc<Function<'a>>>,
}
@ -28,7 +28,7 @@ impl<'a> PushToLuaStack<'a> for 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 {
state,
lref,

View File

@ -143,42 +143,55 @@ fn main() -> Result<()> {
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)]
pub struct LuaRef(Arc<i32>);
pub struct LuaRef<'a>(Arc<i32>, &'a State);
impl From<i32> for LuaRef {
fn from(value: i32) -> Self {
Self(Arc::new(value))
impl<'a> Drop for LuaRef<'a> {
fn drop(&mut self) {
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.
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 r = lua::luaL_ref(s, lua::LUA_REGISTRYINDEX);
if r == lua::LUA_REFNIL {
Err(Error::Nil)
} 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<()> {
let s = state.state_ptr();
unsafe {
state.ensure_stack(1)?;
let top = lua::lua_gettop(s);
let ty = lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, *self.0 as i64);
let new_top = lua::lua_gettop(s);
state.ensure_stack(1)?;
let top = lua::lua_gettop(s);
let ty = lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, *self.0 as i64);
let new_top = lua::lua_gettop(s);
if ty == lua::LUA_TNIL || ty == lua::LUA_TNONE || top == new_top {
return Err(Error::Nil);
}
if ty == lua::LUA_TNIL || ty == lua::LUA_TNONE || top == new_top {
return Err(Error::Nil);
}
Ok(())

View File

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

View File

@ -6,7 +6,7 @@ use crate::{ensure_type, FromLuaStack, LuaRef, PushToLuaStack, Result, StackGuar
#[derive(Clone)]
pub struct Table<'a> {
state: &'a State,
pub(crate) lref: LuaRef,
pub(crate) lref: LuaRef<'a>,
/// a boolean indicating if this Table is a Metatable
mt_marker: bool,
}
@ -59,7 +59,7 @@ impl<'a> Table<'a> {
}
/// 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();
unsafe {

View File

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