Use Luau tags to mark userdata objects as destructed
This commit is contained in:
parent
f9ff6116db
commit
d3b48cf2f3
|
@ -58,7 +58,7 @@ cc = { version = "1.0" }
|
||||||
pkg-config = { version = "0.3.17" }
|
pkg-config = { version = "0.3.17" }
|
||||||
lua-src = { version = ">= 544.0.0, < 550.0.0", optional = true }
|
lua-src = { version = ">= 544.0.0, < 550.0.0", optional = true }
|
||||||
luajit-src = { version = ">= 210.4.0, < 220.0.0", optional = true }
|
luajit-src = { version = ">= 210.4.0, < 220.0.0", optional = true }
|
||||||
luau0-src = { version = "0.3.2", optional = true }
|
luau0-src = { version = "0.3.6", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rustyline = "9.0"
|
rustyline = "9.0"
|
||||||
|
|
|
@ -260,6 +260,7 @@ extern "C" {
|
||||||
pub fn lua_concat(L: *mut lua_State, n: c_int);
|
pub fn lua_concat(L: *mut lua_State, n: c_int);
|
||||||
// TODO: lua_encodepointer
|
// TODO: lua_encodepointer
|
||||||
pub fn lua_clock() -> c_double;
|
pub fn lua_clock() -> c_double;
|
||||||
|
pub fn lua_setuserdatatag(L: *mut lua_State, idx: c_int, tag: c_int);
|
||||||
pub fn lua_setuserdatadtor(
|
pub fn lua_setuserdatadtor(
|
||||||
L: *mut lua_State,
|
L: *mut lua_State,
|
||||||
tag: c_int,
|
tag: c_int,
|
||||||
|
@ -437,7 +438,12 @@ extern "C" {
|
||||||
pub fn lua_setupvalue(L: *mut lua_State, funcindex: c_int, n: c_int) -> *const c_char;
|
pub fn lua_setupvalue(L: *mut lua_State, funcindex: c_int, n: c_int) -> *const c_char;
|
||||||
|
|
||||||
pub fn lua_singlestep(L: *mut lua_State, enabled: c_int);
|
pub fn lua_singlestep(L: *mut lua_State, enabled: c_int);
|
||||||
pub fn lua_breakpoint(L: *mut lua_State, funcindex: c_int, line: c_int, enabled: c_int);
|
pub fn lua_breakpoint(
|
||||||
|
L: *mut lua_State,
|
||||||
|
funcindex: c_int,
|
||||||
|
line: c_int,
|
||||||
|
enabled: c_int,
|
||||||
|
) -> c_int;
|
||||||
|
|
||||||
pub fn lua_getcoverage(
|
pub fn lua_getcoverage(
|
||||||
L: *mut lua_State,
|
L: *mut lua_State,
|
||||||
|
|
10
src/lua.rs
10
src/lua.rs
|
@ -25,7 +25,7 @@ use crate::string::String;
|
||||||
use crate::table::Table;
|
use crate::table::Table;
|
||||||
use crate::thread::Thread;
|
use crate::thread::Thread;
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
Callback, CallbackUpvalue, DestructedUserdataMT, Integer, LightUserData, LuaRef, MaybeSend,
|
Callback, CallbackUpvalue, DestructedUserdata, Integer, LightUserData, LuaRef, MaybeSend,
|
||||||
Number, RegistryKey,
|
Number, RegistryKey,
|
||||||
};
|
};
|
||||||
use crate::userdata::{AnyUserData, UserData, UserDataCell};
|
use crate::userdata::{AnyUserData, UserData, UserDataCell};
|
||||||
|
@ -602,13 +602,13 @@ impl Lua {
|
||||||
"Error while storing extra data",
|
"Error while storing extra data",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Register `DestructedUserdataMT` type
|
// Register `DestructedUserdata` type
|
||||||
get_destructed_userdata_metatable(main_state);
|
get_destructed_userdata_metatable(main_state);
|
||||||
let destructed_mt_ptr = ffi::lua_topointer(main_state, -1);
|
let destructed_mt_ptr = ffi::lua_topointer(main_state, -1);
|
||||||
let destructed_mt_typeid = Some(TypeId::of::<DestructedUserdataMT>());
|
let destructed_ud_typeid = TypeId::of::<DestructedUserdata>();
|
||||||
(*extra.get())
|
(*extra.get())
|
||||||
.registered_userdata_mt
|
.registered_userdata_mt
|
||||||
.insert(destructed_mt_ptr, destructed_mt_typeid);
|
.insert(destructed_mt_ptr, Some(destructed_ud_typeid));
|
||||||
ffi::lua_pop(main_state, 1);
|
ffi::lua_pop(main_state, 1);
|
||||||
|
|
||||||
mlua_debug_assert!(
|
mlua_debug_assert!(
|
||||||
|
@ -2587,7 +2587,7 @@ impl Lua {
|
||||||
|
|
||||||
let extra = &*self.extra.get();
|
let extra = &*self.extra.get();
|
||||||
match extra.registered_userdata_mt.get(&mt_ptr) {
|
match extra.registered_userdata_mt.get(&mt_ptr) {
|
||||||
Some(&type_id) if type_id == Some(TypeId::of::<DestructedUserdataMT>()) => {
|
Some(&type_id) if type_id == Some(TypeId::of::<DestructedUserdata>()) => {
|
||||||
Err(Error::UserDataDestructed)
|
Err(Error::UserDataDestructed)
|
||||||
}
|
}
|
||||||
Some(&type_id) => Ok(type_id),
|
Some(&type_id) => Ok(type_id),
|
||||||
|
|
|
@ -83,7 +83,7 @@ pub trait MaybeSend {}
|
||||||
#[cfg(not(feature = "send"))]
|
#[cfg(not(feature = "send"))]
|
||||||
impl<T> MaybeSend for T {}
|
impl<T> MaybeSend for T {}
|
||||||
|
|
||||||
pub(crate) struct DestructedUserdataMT;
|
pub(crate) struct DestructedUserdata;
|
||||||
|
|
||||||
/// An auto generated key into the Lua registry.
|
/// An auto generated key into the Lua registry.
|
||||||
///
|
///
|
||||||
|
|
14
src/util.rs
14
src/util.rs
|
@ -310,10 +310,7 @@ pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool)
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool) -> Result<()> {
|
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool) -> Result<()> {
|
||||||
unsafe extern "C" fn destructor<T>(ud: *mut c_void) {
|
unsafe extern "C" fn destructor<T>(ud: *mut c_void) {
|
||||||
let ud = ud as *mut T;
|
ptr::drop_in_place(ud as *mut T);
|
||||||
if *(ud.offset(1) as *mut u8) == 0 {
|
|
||||||
ptr::drop_in_place(ud);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = mem::size_of::<T>() + 1;
|
let size = mem::size_of::<T>() + 1;
|
||||||
|
@ -325,7 +322,6 @@ pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool)
|
||||||
ffi::lua_newuserdatadtor(state, size, destructor::<T>) as *mut T
|
ffi::lua_newuserdatadtor(state, size, destructor::<T>) as *mut T
|
||||||
};
|
};
|
||||||
ptr::write(ud, t);
|
ptr::write(ud, t);
|
||||||
*(ud.offset(1) as *mut u8) = 0; // Mark as not destructed
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -369,10 +365,12 @@ pub unsafe fn take_userdata<T>(state: *mut ffi::lua_State) -> T {
|
||||||
get_destructed_userdata_metatable(state);
|
get_destructed_userdata_metatable(state);
|
||||||
ffi::lua_setmetatable(state, -2);
|
ffi::lua_setmetatable(state, -2);
|
||||||
let ud = get_userdata::<T>(state, -1);
|
let ud = get_userdata::<T>(state, -1);
|
||||||
|
|
||||||
|
// Update userdata tag to disable destructor and mark as destructed
|
||||||
|
#[cfg(feature = "luau")]
|
||||||
|
ffi::lua_setuserdatatag(state, -1, 1);
|
||||||
|
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
if cfg!(feature = "luau") {
|
|
||||||
*(ud.offset(1) as *mut u8) = 1; // Mark as destructed
|
|
||||||
}
|
|
||||||
ptr::read(ud)
|
ptr::read(ud)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue