Revert "Move away from metatable hashmap cache to direct keys"
This reverts commit adbc9ccc9b
.
This commit is contained in:
parent
8ff610529b
commit
60822d12d2
68
src/lua.rs
68
src/lua.rs
|
@ -27,10 +27,10 @@ use crate::userdata::{
|
||||||
};
|
};
|
||||||
use crate::util::{
|
use crate::util::{
|
||||||
self, assert_stack, callback_error, check_stack, get_destructed_userdata_metatable,
|
self, assert_stack, callback_error, check_stack, get_destructed_userdata_metatable,
|
||||||
get_gc_metatable, get_gc_userdata, get_main_state, get_userdata, get_wrapped_error,
|
get_gc_metatable_for, get_gc_userdata, get_main_state, get_userdata, get_wrapped_error,
|
||||||
init_error_registry, init_gc_metatable, init_userdata_metatable, pop_error, push_gc_userdata,
|
init_error_registry, init_gc_metatable_for, init_userdata_metatable, pop_error,
|
||||||
push_string, push_table, push_userdata, push_wrapped_error, rawset_field, safe_pcall,
|
push_gc_userdata, push_string, push_table, push_userdata, push_wrapped_error, rawset_field,
|
||||||
safe_xpcall, StackGuard, WrappedError, WrappedPanic, WRAPPED_ERROR_MT, WRAPPED_PANIC_MT,
|
safe_pcall, safe_xpcall, StackGuard, WrappedError, WrappedPanic,
|
||||||
};
|
};
|
||||||
use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value};
|
use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value};
|
||||||
|
|
||||||
|
@ -148,23 +148,11 @@ impl LuaOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static CALLBACK_MT: u8 = 0;
|
|
||||||
static CALLBACK_UPVALUE_MT: u8 = 0;
|
|
||||||
|
|
||||||
pub(crate) static EXTRA_REGISTRY_KEY: u8 = 0;
|
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
static ASYNC_CALLBACK_MT: u8 = 0;
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
static ASYNC_CALLBACK_UPVALUE_MT: u8 = 0;
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
static ASYNC_POLL_UPVALUE_MT: u8 = 0;
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
pub(crate) static WAKER_MT: u8 = 0;
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
pub(crate) static WAKER_REGISTRY_KEY: u8 = 0;
|
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
pub(crate) static ASYNC_POLL_PENDING: u8 = 0;
|
pub(crate) static ASYNC_POLL_PENDING: u8 = 0;
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub(crate) static WAKER_REGISTRY_KEY: u8 = 0;
|
||||||
|
pub(crate) static EXTRA_REGISTRY_KEY: u8 = 0;
|
||||||
|
|
||||||
/// Requires `feature = "send"`
|
/// Requires `feature = "send"`
|
||||||
#[cfg(feature = "send")]
|
#[cfg(feature = "send")]
|
||||||
|
@ -409,18 +397,17 @@ impl Lua {
|
||||||
// Create the internal metatables and place them in the registry
|
// Create the internal metatables and place them in the registry
|
||||||
// to prevent them from being garbage collected.
|
// to prevent them from being garbage collected.
|
||||||
|
|
||||||
init_gc_metatable::<Callback>(state, &CALLBACK_MT, None)?;
|
init_gc_metatable_for::<Callback>(state, None)?;
|
||||||
init_gc_metatable::<CallbackUpvalue>(state, &CALLBACK_UPVALUE_MT, None)?;
|
init_gc_metatable_for::<CallbackUpvalue>(state, None)?;
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
{
|
{
|
||||||
init_gc_metatable::<AsyncCallback>(state, &ASYNC_CALLBACK_MT, None)?;
|
init_gc_metatable_for::<AsyncCallback>(state, None)?;
|
||||||
#[rustfmt::skip]
|
init_gc_metatable_for::<AsyncCallbackUpvalue>(state, None)?;
|
||||||
init_gc_metatable::<AsyncCallbackUpvalue>(state, &ASYNC_CALLBACK_UPVALUE_MT, None)?;
|
init_gc_metatable_for::<AsyncPollUpvalue>(state, None)?;
|
||||||
init_gc_metatable::<AsyncPollUpvalue>(state, &ASYNC_POLL_UPVALUE_MT, None)?;
|
init_gc_metatable_for::<Option<Waker>>(state, None)?;
|
||||||
init_gc_metatable::<Option<Waker>>(state, &WAKER_MT, None)?;
|
|
||||||
|
|
||||||
// Create empty Waker slot
|
// Create empty Waker slot
|
||||||
push_gc_userdata::<Option<Waker>>(state, &WAKER_MT, None)?;
|
push_gc_userdata::<Option<Waker>>(state, None)?;
|
||||||
protect_lua!(state, 1, 0, state => {
|
protect_lua!(state, 1, 0, state => {
|
||||||
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
|
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
|
||||||
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
|
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
|
||||||
|
@ -1622,9 +1609,7 @@ impl Lua {
|
||||||
let err = err.clone();
|
let err = err.clone();
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
Value::Error(err)
|
Value::Error(err)
|
||||||
} else if let Some(panic) =
|
} else if let Some(panic) = get_gc_userdata::<WrappedPanic>(state, -1).as_mut() {
|
||||||
get_gc_userdata::<WrappedPanic>(state, -1, &WRAPPED_PANIC_MT).as_mut()
|
|
||||||
{
|
|
||||||
if let Some(panic) = (*panic).0.take() {
|
if let Some(panic) = (*panic).0.take() {
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
resume_unwind(panic);
|
resume_unwind(panic);
|
||||||
|
@ -1883,12 +1868,8 @@ impl Lua {
|
||||||
check_stack(self.state, 4)?;
|
check_stack(self.state, 4)?;
|
||||||
|
|
||||||
let lua = self.clone();
|
let lua = self.clone();
|
||||||
push_gc_userdata(
|
let func = mem::transmute(func);
|
||||||
self.state,
|
push_gc_userdata(self.state, CallbackUpvalue { lua, func })?;
|
||||||
&CALLBACK_UPVALUE_MT,
|
|
||||||
CallbackUpvalue { lua, func },
|
|
||||||
)?;
|
|
||||||
|
|
||||||
protect_lua!(self.state, 1, 1, state => {
|
protect_lua!(self.state, 1, 1, state => {
|
||||||
ffi::lua_pushcclosure(state, call_callback, 1);
|
ffi::lua_pushcclosure(state, call_callback, 1);
|
||||||
})?;
|
})?;
|
||||||
|
@ -1939,7 +1920,7 @@ impl Lua {
|
||||||
|
|
||||||
let fut = ((*upvalue).func)(lua, args);
|
let fut = ((*upvalue).func)(lua, args);
|
||||||
let lua = lua.clone();
|
let lua = lua.clone();
|
||||||
push_gc_userdata(state, &ASYNC_POLL_UPVALUE_MT, AsyncPollUpvalue { lua, fut })?;
|
push_gc_userdata(state, AsyncPollUpvalue { lua, fut })?;
|
||||||
protect_lua!(state, 1, 1, state => {
|
protect_lua!(state, 1, 1, state => {
|
||||||
ffi::lua_pushcclosure(state, poll_future, 1);
|
ffi::lua_pushcclosure(state, poll_future, 1);
|
||||||
})?;
|
})?;
|
||||||
|
@ -1970,7 +1951,7 @@ impl Lua {
|
||||||
// Try to get an outer poll waker
|
// Try to get an outer poll waker
|
||||||
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
|
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
|
||||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
|
||||||
let waker = match get_gc_userdata::<Option<Waker>>(state, -1, &WAKER_MT).as_ref() {
|
let waker = match get_gc_userdata::<Option<Waker>>(state, -1).as_ref() {
|
||||||
Some(Some(waker)) => waker.clone(),
|
Some(Some(waker)) => waker.clone(),
|
||||||
_ => noop_waker(),
|
_ => noop_waker(),
|
||||||
};
|
};
|
||||||
|
@ -2004,11 +1985,8 @@ impl Lua {
|
||||||
check_stack(self.state, 4)?;
|
check_stack(self.state, 4)?;
|
||||||
|
|
||||||
let lua = self.clone();
|
let lua = self.clone();
|
||||||
push_gc_userdata(
|
let func = mem::transmute(func);
|
||||||
self.state,
|
push_gc_userdata(self.state, AsyncCallbackUpvalue { lua, func })?;
|
||||||
&ASYNC_CALLBACK_UPVALUE_MT,
|
|
||||||
AsyncCallbackUpvalue { lua, func },
|
|
||||||
)?;
|
|
||||||
protect_lua!(self.state, 1, 1, state => {
|
protect_lua!(self.state, 1, 1, state => {
|
||||||
ffi::lua_pushcclosure(state, call_callback, 1);
|
ffi::lua_pushcclosure(state, call_callback, 1);
|
||||||
})?;
|
})?;
|
||||||
|
@ -2438,7 +2416,7 @@ where
|
||||||
Ok(Err(err)) => {
|
Ok(Err(err)) => {
|
||||||
let wrapped_error = get_prealloc_err() as *mut WrappedError;
|
let wrapped_error = get_prealloc_err() as *mut WrappedError;
|
||||||
ptr::write(wrapped_error, WrappedError(err));
|
ptr::write(wrapped_error, WrappedError(err));
|
||||||
get_gc_metatable(state, &WRAPPED_ERROR_MT);
|
get_gc_metatable_for::<WrappedError>(state);
|
||||||
ffi::lua_setmetatable(state, -2);
|
ffi::lua_setmetatable(state, -2);
|
||||||
|
|
||||||
// Convert to CallbackError and attach traceback
|
// Convert to CallbackError and attach traceback
|
||||||
|
@ -2458,7 +2436,7 @@ where
|
||||||
Err(p) => {
|
Err(p) => {
|
||||||
let wrapped_panic = get_prealloc_err() as *mut WrappedPanic;
|
let wrapped_panic = get_prealloc_err() as *mut WrappedPanic;
|
||||||
ptr::write(wrapped_panic, WrappedPanic(Some(p)));
|
ptr::write(wrapped_panic, WrappedPanic(Some(p)));
|
||||||
get_gc_metatable(state, &WRAPPED_PANIC_MT);
|
get_gc_metatable_for::<WrappedPanic>(state);
|
||||||
ffi::lua_setmetatable(state, -2);
|
ffi::lua_setmetatable(state, -2);
|
||||||
ffi::lua_error(state)
|
ffi::lua_error(state)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use crate::function::Function;
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
lua::{ASYNC_POLL_PENDING, WAKER_MT, WAKER_REGISTRY_KEY},
|
lua::{ASYNC_POLL_PENDING, WAKER_REGISTRY_KEY},
|
||||||
util::get_gc_userdata,
|
util::get_gc_userdata,
|
||||||
value::Value,
|
value::Value,
|
||||||
},
|
},
|
||||||
|
@ -362,7 +362,7 @@ impl WakerGuard {
|
||||||
|
|
||||||
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
|
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
|
||||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
|
||||||
let waker_slot = get_gc_userdata::<Option<Waker>>(state, -1, &WAKER_MT).as_mut();
|
let waker_slot = get_gc_userdata::<Option<Waker>>(state, -1).as_mut();
|
||||||
let old = mlua_expect!(waker_slot, "Waker is destroyed").replace(waker);
|
let old = mlua_expect!(waker_slot, "Waker is destroyed").replace(waker);
|
||||||
|
|
||||||
Ok(WakerGuard(state, old))
|
Ok(WakerGuard(state, old))
|
||||||
|
@ -380,7 +380,7 @@ impl Drop for WakerGuard {
|
||||||
|
|
||||||
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
|
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
|
||||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
|
||||||
let waker_slot = get_gc_userdata::<Option<Waker>>(state, -1, &WAKER_MT).as_mut();
|
let waker_slot = get_gc_userdata::<Option<Waker>>(state, -1).as_mut();
|
||||||
mem::swap(mlua_expect!(waker_slot, "Waker is destroyed"), &mut self.1);
|
mem::swap(mlua_expect!(waker_slot, "Waker is destroyed"), &mut self.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
101
src/util.rs
101
src/util.rs
|
@ -1,18 +1,21 @@
|
||||||
use std::any::Any;
|
use std::any::{Any, TypeId};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::os::raw::{c_char, c_int, c_void};
|
use std::os::raw::{c_char, c_int, c_void};
|
||||||
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
|
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex};
|
||||||
use std::{mem, ptr, slice};
|
use std::{mem, ptr, slice};
|
||||||
|
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
|
|
||||||
pub(crate) static WRAPPED_ERROR_MT: u8 = 0;
|
static METATABLE_CACHE: Lazy<Mutex<HashMap<TypeId, u8>>> = Lazy::new(|| {
|
||||||
pub(crate) static WRAPPED_PANIC_MT: u8 = 0;
|
// The capacity must(!) be greater than number of stored keys
|
||||||
static DESTRUCTED_USERDATA_MT: u8 = 0;
|
Mutex::new(HashMap::with_capacity(32))
|
||||||
static ERROR_PRINT_BUFFER_KEY: u8 = 0;
|
});
|
||||||
|
|
||||||
// Checks that Lua has enough free stack space for future stack operations. On failure, this will
|
// Checks that Lua has enough free stack space for future stack operations. On failure, this will
|
||||||
// panic with an internal error message.
|
// panic with an internal error message.
|
||||||
|
@ -196,9 +199,7 @@ pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error {
|
||||||
if let Some(err) = get_wrapped_error(state, -1).as_ref() {
|
if let Some(err) = get_wrapped_error(state, -1).as_ref() {
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
err.clone()
|
err.clone()
|
||||||
} else if let Some(panic) =
|
} else if let Some(panic) = get_gc_userdata::<WrappedPanic>(state, -1).as_mut() {
|
||||||
get_gc_userdata::<WrappedPanic>(state, -1, &WRAPPED_PANIC_MT).as_mut()
|
|
||||||
{
|
|
||||||
if let Some(p) = (*panic).0.take() {
|
if let Some(p) = (*panic).0.take() {
|
||||||
resume_unwind(p);
|
resume_unwind(p);
|
||||||
} else {
|
} else {
|
||||||
|
@ -297,24 +298,20 @@ pub unsafe fn take_userdata<T>(state: *mut ffi::lua_State) -> T {
|
||||||
|
|
||||||
// Pushes the userdata and attaches a metatable with __gc method.
|
// Pushes the userdata and attaches a metatable with __gc method.
|
||||||
// Internally uses 3 stack spaces, does not call checkstack.
|
// Internally uses 3 stack spaces, does not call checkstack.
|
||||||
pub unsafe fn push_gc_userdata<T>(state: *mut ffi::lua_State, key: *const u8, t: T) -> Result<()> {
|
pub unsafe fn push_gc_userdata<T: Any>(state: *mut ffi::lua_State, t: T) -> Result<()> {
|
||||||
push_userdata(state, t)?;
|
push_userdata(state, t)?;
|
||||||
get_gc_metatable(state, key);
|
get_gc_metatable_for::<T>(state);
|
||||||
ffi::lua_setmetatable(state, -2);
|
ffi::lua_setmetatable(state, -2);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses 2 stack spaces, does not call checkstack
|
// Uses 2 stack spaces, does not call checkstack
|
||||||
pub unsafe fn get_gc_userdata<T>(
|
pub unsafe fn get_gc_userdata<T: Any>(state: *mut ffi::lua_State, index: c_int) -> *mut T {
|
||||||
state: *mut ffi::lua_State,
|
|
||||||
index: c_int,
|
|
||||||
key: *const u8,
|
|
||||||
) -> *mut T {
|
|
||||||
let ud = ffi::lua_touserdata(state, index) as *mut T;
|
let ud = ffi::lua_touserdata(state, index) as *mut T;
|
||||||
if ud.is_null() || ffi::lua_getmetatable(state, index) == 0 {
|
if ud.is_null() || ffi::lua_getmetatable(state, index) == 0 {
|
||||||
return ptr::null_mut();
|
return ptr::null_mut();
|
||||||
}
|
}
|
||||||
get_gc_metatable(state, key);
|
get_gc_metatable_for::<T>(state);
|
||||||
let res = ffi::lua_rawequal(state, -1, -2);
|
let res = ffi::lua_rawequal(state, -1, -2);
|
||||||
ffi::lua_pop(state, 2);
|
ffi::lua_pop(state, 2);
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
|
@ -528,7 +525,7 @@ where
|
||||||
|
|
||||||
let wrapped_error = ud as *mut WrappedError;
|
let wrapped_error = ud as *mut WrappedError;
|
||||||
ptr::write(wrapped_error, WrappedError(err));
|
ptr::write(wrapped_error, WrappedError(err));
|
||||||
get_gc_metatable(state, &WRAPPED_ERROR_MT);
|
get_gc_metatable_for::<WrappedError>(state);
|
||||||
ffi::lua_setmetatable(state, -2);
|
ffi::lua_setmetatable(state, -2);
|
||||||
|
|
||||||
// Convert to CallbackError and attach traceback
|
// Convert to CallbackError and attach traceback
|
||||||
|
@ -548,7 +545,7 @@ where
|
||||||
Err(p) => {
|
Err(p) => {
|
||||||
ffi::lua_settop(state, 1);
|
ffi::lua_settop(state, 1);
|
||||||
ptr::write(ud as *mut WrappedPanic, WrappedPanic(Some(p)));
|
ptr::write(ud as *mut WrappedPanic, WrappedPanic(Some(p)));
|
||||||
get_gc_metatable(state, &WRAPPED_PANIC_MT);
|
get_gc_metatable_for::<WrappedPanic>(state);
|
||||||
ffi::lua_setmetatable(state, -2);
|
ffi::lua_setmetatable(state, -2);
|
||||||
ffi::lua_error(state)
|
ffi::lua_error(state)
|
||||||
}
|
}
|
||||||
|
@ -562,8 +559,8 @@ pub unsafe extern "C" fn error_traceback(state: *mut ffi::lua_State) -> c_int {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if get_gc_userdata::<WrappedError>(state, -1, &WRAPPED_ERROR_MT).is_null()
|
if get_gc_userdata::<WrappedError>(state, -1).is_null()
|
||||||
&& get_gc_userdata::<WrappedPanic>(state, -1, &WRAPPED_PANIC_MT).is_null()
|
&& get_gc_userdata::<WrappedPanic>(state, -1).is_null()
|
||||||
{
|
{
|
||||||
let s = ffi::luaL_tolstring(state, -1, ptr::null_mut());
|
let s = ffi::luaL_tolstring(state, -1, ptr::null_mut());
|
||||||
if ffi::lua_checkstack(state, ffi::LUA_TRACEBACK_STACK) != 0 {
|
if ffi::lua_checkstack(state, ffi::LUA_TRACEBACK_STACK) != 0 {
|
||||||
|
@ -590,7 +587,7 @@ pub unsafe extern "C" fn safe_pcall(state: *mut ffi::lua_State) -> c_int {
|
||||||
ffi::lua_insert(state, 1);
|
ffi::lua_insert(state, 1);
|
||||||
ffi::lua_gettop(state)
|
ffi::lua_gettop(state)
|
||||||
} else {
|
} else {
|
||||||
if !get_gc_userdata::<WrappedPanic>(state, -1, &WRAPPED_PANIC_MT).is_null() {
|
if !get_gc_userdata::<WrappedPanic>(state, -1).is_null() {
|
||||||
ffi::lua_error(state);
|
ffi::lua_error(state);
|
||||||
}
|
}
|
||||||
ffi::lua_pushboolean(state, 0);
|
ffi::lua_pushboolean(state, 0);
|
||||||
|
@ -604,7 +601,7 @@ pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int {
|
||||||
unsafe extern "C" fn xpcall_msgh(state: *mut ffi::lua_State) -> c_int {
|
unsafe extern "C" fn xpcall_msgh(state: *mut ffi::lua_State) -> c_int {
|
||||||
ffi::luaL_checkstack(state, 2, ptr::null());
|
ffi::luaL_checkstack(state, 2, ptr::null());
|
||||||
|
|
||||||
if !get_gc_userdata::<WrappedPanic>(state, -1, &WRAPPED_PANIC_MT).is_null() {
|
if !get_gc_userdata::<WrappedPanic>(state, -1).is_null() {
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(1));
|
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(1));
|
||||||
|
@ -632,7 +629,7 @@ pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int {
|
||||||
ffi::lua_insert(state, 2);
|
ffi::lua_insert(state, 2);
|
||||||
ffi::lua_gettop(state) - 1
|
ffi::lua_gettop(state) - 1
|
||||||
} else {
|
} else {
|
||||||
if !get_gc_userdata::<WrappedPanic>(state, -1, &WRAPPED_PANIC_MT).is_null() {
|
if !get_gc_userdata::<WrappedPanic>(state, -1).is_null() {
|
||||||
ffi::lua_error(state);
|
ffi::lua_error(state);
|
||||||
}
|
}
|
||||||
ffi::lua_pushboolean(state, 0);
|
ffi::lua_pushboolean(state, 0);
|
||||||
|
@ -667,14 +664,14 @@ pub unsafe fn get_main_state(state: *mut ffi::lua_State) -> Option<*mut ffi::lua
|
||||||
// Pushes a WrappedError to the top of the stack.
|
// Pushes a WrappedError to the top of the stack.
|
||||||
// Uses 3 stack spaces and does not call checkstack.
|
// Uses 3 stack spaces and does not call checkstack.
|
||||||
pub unsafe fn push_wrapped_error(state: *mut ffi::lua_State, err: Error) -> Result<()> {
|
pub unsafe fn push_wrapped_error(state: *mut ffi::lua_State, err: Error) -> Result<()> {
|
||||||
push_gc_userdata::<WrappedError>(state, &WRAPPED_ERROR_MT, WrappedError(err))
|
push_gc_userdata::<WrappedError>(state, WrappedError(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if the value at the given index is a WrappedError, and if it is returns a pointer to it,
|
// Checks if the value at the given index is a WrappedError, and if it is returns a pointer to it,
|
||||||
// otherwise returns null.
|
// otherwise returns null.
|
||||||
// Uses 2 stack spaces and does not call checkstack.
|
// Uses 2 stack spaces and does not call checkstack.
|
||||||
pub unsafe fn get_wrapped_error(state: *mut ffi::lua_State, index: c_int) -> *const Error {
|
pub unsafe fn get_wrapped_error(state: *mut ffi::lua_State, index: c_int) -> *const Error {
|
||||||
let ud = get_gc_userdata::<WrappedError>(state, index, &WRAPPED_ERROR_MT);
|
let ud = get_gc_userdata::<WrappedError>(state, index);
|
||||||
if ud.is_null() {
|
if ud.is_null() {
|
||||||
return ptr::null();
|
return ptr::null();
|
||||||
}
|
}
|
||||||
|
@ -683,13 +680,23 @@ pub unsafe fn get_wrapped_error(state: *mut ffi::lua_State, index: c_int) -> *co
|
||||||
|
|
||||||
// Initialize the internal (with __gc method) metatable for a type T.
|
// Initialize the internal (with __gc method) metatable for a type T.
|
||||||
// Uses 6 stack spaces and calls checkstack.
|
// Uses 6 stack spaces and calls checkstack.
|
||||||
pub unsafe fn init_gc_metatable<T>(
|
pub unsafe fn init_gc_metatable_for<T: Any>(
|
||||||
state: *mut ffi::lua_State,
|
state: *mut ffi::lua_State,
|
||||||
key: *const u8,
|
|
||||||
customize_fn: Option<fn(*mut ffi::lua_State) -> Result<()>>,
|
customize_fn: Option<fn(*mut ffi::lua_State) -> Result<()>>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
check_stack(state, 6)?;
|
check_stack(state, 6)?;
|
||||||
|
|
||||||
|
let type_id = TypeId::of::<T>();
|
||||||
|
let ref_addr = {
|
||||||
|
let mut mt_cache = mlua_expect!(METATABLE_CACHE.lock(), "cannot lock metatable cache");
|
||||||
|
mlua_assert!(
|
||||||
|
mt_cache.capacity() - mt_cache.len() > 0,
|
||||||
|
"out of metatable cache capacity"
|
||||||
|
);
|
||||||
|
mt_cache.insert(type_id, 0);
|
||||||
|
&mt_cache[&type_id] as *const u8
|
||||||
|
};
|
||||||
|
|
||||||
push_table(state, 0, 3)?;
|
push_table(state, 0, 3)?;
|
||||||
|
|
||||||
ffi::lua_pushcfunction(state, userdata_destructor::<T>);
|
ffi::lua_pushcfunction(state, userdata_destructor::<T>);
|
||||||
|
@ -703,14 +710,19 @@ pub unsafe fn init_gc_metatable<T>(
|
||||||
}
|
}
|
||||||
|
|
||||||
protect_lua!(state, 1, 0, |state| {
|
protect_lua!(state, 1, 0, |state| {
|
||||||
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, key as *const c_void)
|
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, ref_addr as *mut c_void)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn get_gc_metatable(state: *mut ffi::lua_State, key: *const u8) {
|
pub unsafe fn get_gc_metatable_for<T: Any>(state: *mut ffi::lua_State) {
|
||||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, key as *const c_void);
|
let type_id = TypeId::of::<T>();
|
||||||
|
let ref_addr = {
|
||||||
|
let mt_cache = mlua_expect!(METATABLE_CACHE.lock(), "cannot lock metatable cache");
|
||||||
|
mlua_expect!(mt_cache.get(&type_id), "gc metatable does not exist") as *const u8
|
||||||
|
};
|
||||||
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, ref_addr as *const c_void);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the error, panic, and destructed userdata metatables.
|
// Initialize the error, panic, and destructed userdata metatables.
|
||||||
|
@ -759,9 +771,7 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
Ok(err_buf)
|
Ok(err_buf)
|
||||||
} else if let Some(panic) =
|
} else if let Some(panic) = get_gc_userdata::<WrappedPanic>(state, -1).as_ref() {
|
||||||
get_gc_userdata::<WrappedPanic>(state, -1, &WRAPPED_PANIC_MT).as_ref()
|
|
||||||
{
|
|
||||||
if let Some(ref p) = (*panic).0 {
|
if let Some(ref p) = (*panic).0 {
|
||||||
let err_buf_key = &ERROR_PRINT_BUFFER_KEY as *const u8 as *const c_void;
|
let err_buf_key = &ERROR_PRINT_BUFFER_KEY as *const u8 as *const c_void;
|
||||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, err_buf_key);
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, err_buf_key);
|
||||||
|
@ -792,18 +802,16 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
init_gc_metatable::<WrappedError>(
|
init_gc_metatable_for::<WrappedError>(
|
||||||
state,
|
state,
|
||||||
&WRAPPED_ERROR_MT,
|
|
||||||
Some(|state| {
|
Some(|state| {
|
||||||
ffi::lua_pushcfunction(state, error_tostring);
|
ffi::lua_pushcfunction(state, error_tostring);
|
||||||
rawset_field(state, -2, "__tostring")
|
rawset_field(state, -2, "__tostring")
|
||||||
}),
|
}),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
init_gc_metatable::<WrappedPanic>(
|
init_gc_metatable_for::<WrappedPanic>(
|
||||||
state,
|
state,
|
||||||
&WRAPPED_PANIC_MT,
|
|
||||||
Some(|state| {
|
Some(|state| {
|
||||||
ffi::lua_pushcfunction(state, error_tostring);
|
ffi::lua_pushcfunction(state, error_tostring);
|
||||||
rawset_field(state, -2, "__tostring")
|
rawset_field(state, -2, "__tostring")
|
||||||
|
@ -862,16 +870,16 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
|
|
||||||
protect_lua!(state, 1, 0, state => {
|
protect_lua!(state, 1, 0, state => {
|
||||||
let key = &DESTRUCTED_USERDATA_MT as *const u8 as *const c_void;
|
let destructed_metatable_key = &DESTRUCTED_USERDATA_METATABLE as *const u8 as *const c_void;
|
||||||
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, key)
|
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, destructed_metatable_key)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Create error print buffer
|
// Create error print buffer
|
||||||
init_gc_metatable::<String>(state, &ERROR_PRINT_BUFFER_KEY, None)?;
|
init_gc_metatable_for::<String>(state, None)?;
|
||||||
push_gc_userdata(state, &ERROR_PRINT_BUFFER_KEY, String::new())?;
|
push_gc_userdata(state, String::new())?;
|
||||||
protect_lua!(state, 1, 0, state => {
|
protect_lua!(state, 1, 0, state => {
|
||||||
let key = &ERROR_PRINT_BUFFER_KEY as *const u8 as *const c_void;
|
let err_buf_key = &ERROR_PRINT_BUFFER_KEY as *const u8 as *const c_void;
|
||||||
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, key)
|
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, err_buf_key)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -915,6 +923,9 @@ pub(crate) unsafe fn to_string(state: *mut ffi::lua_State, index: c_int) -> Stri
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn get_destructed_userdata_metatable(state: *mut ffi::lua_State) {
|
pub(crate) unsafe fn get_destructed_userdata_metatable(state: *mut ffi::lua_State) {
|
||||||
let key = &DESTRUCTED_USERDATA_MT as *const u8 as *const c_void;
|
let key = &DESTRUCTED_USERDATA_METATABLE as *const u8 as *const c_void;
|
||||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, key);
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DESTRUCTED_USERDATA_METATABLE: u8 = 0;
|
||||||
|
static ERROR_PRINT_BUFFER_KEY: u8 = 0;
|
||||||
|
|
Loading…
Reference in New Issue