Refactor LuaInner state

Add static_assertions to check for auto traits impl on compilation stage
Bump MSRV to 1.63 (required for `Ref::filter_map`)
This commit is contained in:
Alex Orlenko 2022-12-19 11:37:40 +00:00
parent 0aa30226df
commit 9b4e3a1598
No known key found for this signature in database
GPG Key ID: 4C150C250863B96D
15 changed files with 656 additions and 534 deletions

View File

@ -73,6 +73,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
maplit = "1.0"
tempfile = "3"
static_assertions = "1.0"
[[bench]]
name = "benchmark"

View File

@ -9,7 +9,7 @@
[docs.rs]: https://docs.rs/mlua
[Coverage Status]: https://codecov.io/gh/khvzak/mlua/branch/master/graph/badge.svg?token=99339FS1CG
[codecov.io]: https://codecov.io/gh/khvzak/mlua
[MSRV]: https://img.shields.io/badge/rust-1.56+-brightgreen.svg?&logo=rust
[MSRV]: https://img.shields.io/badge/rust-1.63+-brightgreen.svg?&logo=rust
[Guided Tour] | [Benchmarks] | [FAQ]

View File

@ -95,31 +95,32 @@ impl<'lua> Function<'lua> {
/// ```
pub fn call<A: ToLuaMulti<'lua>, R: FromLuaMulti<'lua>>(&self, args: A) -> Result<R> {
let lua = self.0.lua;
let state = lua.state();
let mut args = args.to_lua_multi(lua)?;
let nargs = args.len() as c_int;
let results = unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, nargs + 3)?;
let _sg = StackGuard::new(state);
check_stack(state, nargs + 3)?;
ffi::lua_pushcfunction(lua.state, error_traceback);
let stack_start = ffi::lua_gettop(lua.state);
ffi::lua_pushcfunction(state, error_traceback);
let stack_start = ffi::lua_gettop(state);
lua.push_ref(&self.0);
for arg in args.drain_all() {
lua.push_value(arg)?;
}
let ret = ffi::lua_pcall(lua.state, nargs, ffi::LUA_MULTRET, stack_start);
let ret = ffi::lua_pcall(state, nargs, ffi::LUA_MULTRET, stack_start);
if ret != ffi::LUA_OK {
return Err(pop_error(lua.state, ret));
return Err(pop_error(state, ret));
}
let nresults = ffi::lua_gettop(lua.state) - stack_start;
let nresults = ffi::lua_gettop(state) - stack_start;
let mut results = args; // Reuse MultiValue container
assert_stack(lua.state, 2);
assert_stack(state, 2);
for _ in 0..nresults {
results.push_front(lua.pop_value());
}
ffi::lua_pop(lua.state, 1);
ffi::lua_pop(state, 1);
results
};
R::from_lua_multi(results, lua)
@ -217,6 +218,7 @@ impl<'lua> Function<'lua> {
}
let lua = self.0.lua;
let state = lua.state();
let args = args.to_lua_multi(lua)?;
let nargs = args.len() as c_int;
@ -230,14 +232,14 @@ impl<'lua> Function<'lua> {
}
let args_wrapper = unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, nargs + 3)?;
let _sg = StackGuard::new(state);
check_stack(state, nargs + 3)?;
ffi::lua_pushinteger(lua.state, nargs as ffi::lua_Integer);
ffi::lua_pushinteger(state, nargs as ffi::lua_Integer);
for arg in args {
lua.push_value(arg)?;
}
protect_lua!(lua.state, nargs + 1, 1, fn(state) {
protect_lua!(state, nargs + 1, 1, fn(state) {
ffi::lua_pushcclosure(state, args_wrapper_impl, ffi::lua_gettop(state));
})?;
@ -264,16 +266,17 @@ impl<'lua> Function<'lua> {
/// [`lua_getinfo`]: https://www.lua.org/manual/5.4/manual.html#lua_getinfo
pub fn info(&self) -> FunctionInfo {
let lua = self.0.lua;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
assert_stack(lua.state, 1);
let _sg = StackGuard::new(state);
assert_stack(state, 1);
let mut ar: ffi::lua_Debug = mem::zeroed();
lua.push_ref(&self.0);
#[cfg(not(feature = "luau"))]
let res = ffi::lua_getinfo(lua.state, cstr!(">Sn"), &mut ar);
let res = ffi::lua_getinfo(state, cstr!(">Sn"), &mut ar);
#[cfg(feature = "luau")]
let res = ffi::lua_getinfo(lua.state, -1, cstr!("sn"), &mut ar);
let res = ffi::lua_getinfo(state, -1, cstr!("sn"), &mut ar);
mlua_assert!(res != 0, "lua_getinfo failed with `>Sn`");
FunctionInfo {
@ -319,15 +322,16 @@ impl<'lua> Function<'lua> {
}
let lua = self.0.lua;
let state = lua.state();
let mut data: Vec<u8> = Vec::new();
unsafe {
let _sg = StackGuard::new(lua.state);
assert_stack(lua.state, 1);
let _sg = StackGuard::new(state);
assert_stack(state, 1);
lua.push_ref(&self.0);
let data_ptr = &mut data as *mut Vec<u8> as *mut c_void;
ffi::lua_dump(lua.state, writer, data_ptr, strip as i32);
ffi::lua_pop(lua.state, 1);
ffi::lua_dump(state, writer, data_ptr, strip as i32);
ffi::lua_pop(state, 1);
}
data
@ -375,13 +379,14 @@ impl<'lua> Function<'lua> {
}
let lua = self.0.lua;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
assert_stack(lua.state, 1);
let _sg = StackGuard::new(state);
assert_stack(state, 1);
lua.push_ref(&self.0);
let func_ptr = &mut func as *mut F as *mut c_void;
ffi::lua_getcoverage(lua.state, -1, func_ptr, callback::<F>);
ffi::lua_getcoverage(state, -1, func_ptr, callback::<F>);
}
}
@ -397,3 +402,10 @@ impl<'lua> PartialEq for Function<'lua> {
self.0 == other.0
}
}
#[cfg(test)]
mod assertions {
use super::*;
static_assertions::assert_not_impl_any!(Function: Send);
}

View File

@ -67,12 +67,12 @@ impl<'lua> Debug<'lua> {
unsafe {
#[cfg(not(feature = "luau"))]
mlua_assert!(
ffi::lua_getinfo(self.lua.state, cstr!("n"), self.ar.get()) != 0,
ffi::lua_getinfo(self.lua.state(), cstr!("n"), self.ar.get()) != 0,
"lua_getinfo failed with `n`"
);
#[cfg(feature = "luau")]
mlua_assert!(
ffi::lua_getinfo(self.lua.state, self.level, cstr!("n"), self.ar.get()) != 0,
ffi::lua_getinfo(self.lua.state(), self.level, cstr!("n"), self.ar.get()) != 0,
"lua_getinfo failed with `n`"
);
@ -91,12 +91,12 @@ impl<'lua> Debug<'lua> {
unsafe {
#[cfg(not(feature = "luau"))]
mlua_assert!(
ffi::lua_getinfo(self.lua.state, cstr!("S"), self.ar.get()) != 0,
ffi::lua_getinfo(self.lua.state(), cstr!("S"), self.ar.get()) != 0,
"lua_getinfo failed with `S`"
);
#[cfg(feature = "luau")]
mlua_assert!(
ffi::lua_getinfo(self.lua.state, self.level, cstr!("s"), self.ar.get()) != 0,
ffi::lua_getinfo(self.lua.state(), self.level, cstr!("s"), self.ar.get()) != 0,
"lua_getinfo failed with `s`"
);
@ -119,12 +119,12 @@ impl<'lua> Debug<'lua> {
unsafe {
#[cfg(not(feature = "luau"))]
mlua_assert!(
ffi::lua_getinfo(self.lua.state, cstr!("l"), self.ar.get()) != 0,
ffi::lua_getinfo(self.lua.state(), cstr!("l"), self.ar.get()) != 0,
"lua_getinfo failed with `l`"
);
#[cfg(feature = "luau")]
mlua_assert!(
ffi::lua_getinfo(self.lua.state, self.level, cstr!("l"), self.ar.get()) != 0,
ffi::lua_getinfo(self.lua.state(), self.level, cstr!("l"), self.ar.get()) != 0,
"lua_getinfo failed with `l`"
);
@ -139,7 +139,7 @@ impl<'lua> Debug<'lua> {
pub fn is_tail_call(&self) -> bool {
unsafe {
mlua_assert!(
ffi::lua_getinfo(self.lua.state, cstr!("t"), self.ar.get()) != 0,
ffi::lua_getinfo(self.lua.state(), cstr!("t"), self.ar.get()) != 0,
"lua_getinfo failed with `t`"
);
(*self.ar.get()).currentline != 0
@ -151,12 +151,12 @@ impl<'lua> Debug<'lua> {
unsafe {
#[cfg(not(feature = "luau"))]
mlua_assert!(
ffi::lua_getinfo(self.lua.state, cstr!("u"), self.ar.get()) != 0,
ffi::lua_getinfo(self.lua.state(), cstr!("u"), self.ar.get()) != 0,
"lua_getinfo failed with `u`"
);
#[cfg(feature = "luau")]
mlua_assert!(
ffi::lua_getinfo(self.lua.state, self.level, cstr!("a"), self.ar.get()) != 0,
ffi::lua_getinfo(self.lua.state(), self.level, cstr!("a"), self.ar.get()) != 0,
"lua_getinfo failed with `a`"
);

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
use std::ffi::CStr;
use std::os::raw::{c_float, c_int};
use std::string::String as StdString;
use crate::chunk::ChunkMode;
use crate::error::{Error, Result};
@ -69,14 +70,15 @@ unsafe extern "C" fn lua_collectgarbage(state: *mut ffi::lua_State) -> c_int {
}
}
fn lua_require(lua: &Lua, name: Option<std::string::String>) -> Result<Value> {
fn lua_require(lua: &Lua, name: Option<StdString>) -> Result<Value> {
let name = name.ok_or_else(|| Error::RuntimeError("invalid module name".into()))?;
// Find module in the cache
let state = lua.state();
let loaded = unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 2)?;
protect_lua!(lua.state, 0, 1, fn(state) {
let _sg = StackGuard::new(state);
check_stack(state, 2)?;
protect_lua!(state, 0, 1, fn(state) {
ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, cstr!("_LOADED"));
})?;
Table(lua.pop_ref())

View File

@ -190,7 +190,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
#[cfg(any(feature = "lua51", feature = "luajit"))]
let newtable = self.lua.create_table()?;
let destructor: DestructorCallback = Box::new(move |ud| {
let state = ud.lua.state;
let state = ud.lua.state();
let _sg = StackGuard::new(state);
assert_stack(state, 2);
@ -275,11 +275,12 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
// first argument).
let check_ud_type = move |lua: &'callback Lua, value| {
if let Some(Value::UserData(ud)) = value {
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 2)?;
let _sg = StackGuard::new(state);
check_stack(state, 2)?;
lua.push_userdata_ref(&ud.0)?;
if get_userdata(lua.state, -1) as *const _ == ud_ptr {
if get_userdata(state, -1) as *const _ == ud_ptr {
return Ok(());
}
}
@ -330,14 +331,15 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
T::add_fields(&mut ud_fields);
T::add_methods(&mut ud_methods);
let lua = self.lua;
let state = lua.state();
unsafe {
let lua = self.lua;
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 13)?;
let _sg = StackGuard::new(state);
check_stack(state, 13)?;
#[cfg(not(feature = "luau"))]
#[allow(clippy::let_and_return)]
let ud_ptr = protect_lua!(lua.state, 0, 1, |state| {
let ud_ptr = protect_lua!(state, 0, 1, |state| {
let ud =
ffi::lua_newuserdata(state, mem::size_of::<UserDataCell<Rc<RefCell<T>>>>());
@ -353,67 +355,67 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
#[cfg(feature = "luau")]
let ud_ptr = {
crate::util::push_userdata::<UserDataCell<Rc<RefCell<T>>>>(
lua.state,
state,
UserDataCell::new(data.clone()),
true,
)?;
ffi::lua_touserdata(lua.state, -1)
ffi::lua_touserdata(state, -1)
};
// Prepare metatable, add meta methods first and then meta fields
let meta_methods_nrec = ud_methods.meta_methods.len() + ud_fields.meta_fields.len() + 1;
push_table(lua.state, 0, meta_methods_nrec as c_int, true)?;
push_table(state, 0, meta_methods_nrec as c_int, true)?;
for (k, m) in ud_methods.meta_methods {
let data = data.clone();
lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;
rawset_field(lua.state, -2, k.validate()?.name())?;
rawset_field(state, -2, k.validate()?.name())?;
}
for (k, f) in ud_fields.meta_fields {
lua.push_value(f(mem::transmute(lua))?)?;
rawset_field(lua.state, -2, k.validate()?.name())?;
rawset_field(state, -2, k.validate()?.name())?;
}
let metatable_index = ffi::lua_absindex(lua.state, -1);
let metatable_index = ffi::lua_absindex(state, -1);
let mut field_getters_index = None;
let field_getters_nrec = ud_fields.field_getters.len();
if field_getters_nrec > 0 {
push_table(lua.state, 0, field_getters_nrec as c_int, true)?;
push_table(state, 0, field_getters_nrec as c_int, true)?;
for (k, m) in ud_fields.field_getters {
let data = data.clone();
lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;
rawset_field(lua.state, -2, &k)?;
rawset_field(state, -2, &k)?;
}
field_getters_index = Some(ffi::lua_absindex(lua.state, -1));
field_getters_index = Some(ffi::lua_absindex(state, -1));
}
let mut field_setters_index = None;
let field_setters_nrec = ud_fields.field_setters.len();
if field_setters_nrec > 0 {
push_table(lua.state, 0, field_setters_nrec as c_int, true)?;
push_table(state, 0, field_setters_nrec as c_int, true)?;
for (k, m) in ud_fields.field_setters {
let data = data.clone();
lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;
rawset_field(lua.state, -2, &k)?;
rawset_field(state, -2, &k)?;
}
field_setters_index = Some(ffi::lua_absindex(lua.state, -1));
field_setters_index = Some(ffi::lua_absindex(state, -1));
}
let mut methods_index = None;
let methods_nrec = ud_methods.methods.len();
if methods_nrec > 0 {
// Create table used for methods lookup
push_table(lua.state, 0, methods_nrec as c_int, true)?;
push_table(state, 0, methods_nrec as c_int, true)?;
for (k, m) in ud_methods.methods {
let data = data.clone();
lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;
rawset_field(lua.state, -2, &k)?;
rawset_field(state, -2, &k)?;
}
methods_index = Some(ffi::lua_absindex(lua.state, -1));
methods_index = Some(ffi::lua_absindex(state, -1));
}
init_userdata_metatable::<UserDataCell<Rc<RefCell<T>>>>(
lua.state,
state,
metatable_index,
field_getters_index,
field_setters_index,
@ -423,20 +425,20 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
let count = field_getters_index.map(|_| 1).unwrap_or(0)
+ field_setters_index.map(|_| 1).unwrap_or(0)
+ methods_index.map(|_| 1).unwrap_or(0);
ffi::lua_pop(lua.state, count);
ffi::lua_pop(state, count);
let mt_ptr = ffi::lua_topointer(lua.state, -1);
let mt_ptr = ffi::lua_topointer(state, -1);
// Write userdata just before attaching metatable with `__gc` metamethod
#[cfg(not(feature = "luau"))]
std::ptr::write(ud_ptr as _, UserDataCell::new(data));
ffi::lua_setmetatable(lua.state, -2);
ffi::lua_setmetatable(state, -2);
let ud = AnyUserData(lua.pop_ref());
lua.register_userdata_metatable(mt_ptr, None);
#[cfg(any(feature = "lua51", feature = "luajit"))]
let newtable = lua.create_table()?;
let destructor: DestructorCallback = Box::new(move |ud| {
let state = ud.lua.state;
let state = ud.lua.state();
let _sg = StackGuard::new(state);
assert_stack(state, 2);
@ -498,7 +500,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
let f = self.lua.create_callback(f)?;
let destructor: DestructorCallback = Box::new(|f| {
let state = f.lua.state;
let state = f.lua.state();
let _sg = StackGuard::new(state);
assert_stack(state, 3);
@ -532,7 +534,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
let get_poll_str = self.lua.create_string("get_poll")?;
let poll_str = self.lua.create_string("poll")?;
let destructor: DestructorCallback = Box::new(move |f| {
let state = f.lua.state;
let state = f.lua.state();
let _sg = StackGuard::new(state);
assert_stack(state, 5);

View File

@ -320,20 +320,21 @@ impl<'lua> ser::SerializeSeq for SerializeVec<'lua> {
T: Serialize + ?Sized,
{
let lua = self.table.0.lua;
let state = lua.state();
let value = lua.to_value_with(value, self.options)?;
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 4)?;
let _sg = StackGuard::new(state);
check_stack(state, 4)?;
lua.push_ref(&self.table.0);
lua.push_value(value)?;
if lua.unlikely_memory_error() {
let len = ffi::lua_rawlen(lua.state, -2) as Integer;
ffi::lua_rawseti(lua.state, -2, len + 1);
ffi::lua_pop(lua.state, 1);
let len = ffi::lua_rawlen(state, -2) as Integer;
ffi::lua_rawseti(state, -2, len + 1);
ffi::lua_pop(state, 1);
Ok(())
} else {
protect_lua!(lua.state, 2, 0, fn(state) {
protect_lua!(state, 2, 0, fn(state) {
let len = ffi::lua_rawlen(state, -2) as Integer;
ffi::lua_rawseti(state, -2, len + 1);
})

View File

@ -190,3 +190,10 @@ impl<'lua> Serialize for String<'lua> {
}
}
}
#[cfg(test)]
mod assertions {
use super::*;
static_assertions::assert_not_impl_any!(String: Send);
}

View File

@ -78,14 +78,15 @@ impl<'lua> Table<'lua> {
let key = key.to_lua(lua)?;
let value = value.to_lua(lua)?;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 5)?;
let _sg = StackGuard::new(state);
check_stack(state, 5)?;
lua.push_ref(&self.0);
lua.push_value(key)?;
lua.push_value(value)?;
protect_lua!(lua.state, 3, 0, fn(state) ffi::lua_settable(state, -3))
protect_lua!(state, 3, 0, fn(state) ffi::lua_settable(state, -3))
}
}
@ -120,15 +121,16 @@ impl<'lua> Table<'lua> {
}
let lua = self.0.lua;
let state = lua.state();
let key = key.to_lua(lua)?;
let value = unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 4)?;
let _sg = StackGuard::new(state);
check_stack(state, 4)?;
lua.push_ref(&self.0);
lua.push_value(key)?;
protect_lua!(lua.state, 2, 1, fn(state) ffi::lua_gettable(state, -2))?;
protect_lua!(state, 2, 1, fn(state) ffi::lua_gettable(state, -2))?;
lua.pop_value()
};
@ -148,14 +150,15 @@ impl<'lua> Table<'lua> {
}
let lua = self.0.lua;
let state = lua.state();
let value = value.to_lua(lua)?;
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 4)?;
let _sg = StackGuard::new(state);
check_stack(state, 4)?;
lua.push_ref(&self.0);
lua.push_value(value)?;
protect_lua!(lua.state, 2, 0, fn(state) {
protect_lua!(state, 2, 0, fn(state) {
let len = ffi::luaL_len(state, -2) as Integer;
ffi::lua_seti(state, -2, len + 1);
})?
@ -171,12 +174,13 @@ impl<'lua> Table<'lua> {
}
let lua = self.0.lua;
let state = lua.state();
let value = unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 4)?;
let _sg = StackGuard::new(state);
check_stack(state, 4)?;
lua.push_ref(&self.0);
protect_lua!(lua.state, 1, 1, fn(state) {
protect_lua!(state, 1, 1, fn(state) {
let len = ffi::luaL_len(state, -1) as Integer;
ffi::lua_geti(state, -1, len);
ffi::lua_pushnil(state);
@ -249,23 +253,24 @@ impl<'lua> Table<'lua> {
self.check_readonly_write()?;
let lua = self.0.lua;
let state = lua.state();
let key = key.to_lua(lua)?;
let value = value.to_lua(lua)?;
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 5)?;
let _sg = StackGuard::new(state);
check_stack(state, 5)?;
lua.push_ref(&self.0);
lua.push_value(key)?;
lua.push_value(value)?;
if lua.unlikely_memory_error() {
ffi::lua_rawset(lua.state, -3);
ffi::lua_pop(lua.state, 1);
ffi::lua_rawset(state, -3);
ffi::lua_pop(state, 1);
Ok(())
} else {
protect_lua!(lua.state, 3, 0, fn(state) ffi::lua_rawset(state, -3))
protect_lua!(state, 3, 0, fn(state) ffi::lua_rawset(state, -3))
}
}
}
@ -273,15 +278,16 @@ impl<'lua> Table<'lua> {
/// Gets the value associated to `key` without invoking metamethods.
pub fn raw_get<K: ToLua<'lua>, V: FromLua<'lua>>(&self, key: K) -> Result<V> {
let lua = self.0.lua;
let state = lua.state();
let key = key.to_lua(lua)?;
let value = unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 3)?;
let _sg = StackGuard::new(state);
check_stack(state, 3)?;
lua.push_ref(&self.0);
lua.push_value(key)?;
ffi::lua_rawget(lua.state, -2);
ffi::lua_rawget(state, -2);
lua.pop_value()
};
@ -292,6 +298,8 @@ impl<'lua> Table<'lua> {
/// The worst case complexity is O(n), where n is the table length.
pub fn raw_insert<V: ToLua<'lua>>(&self, idx: Integer, value: V) -> Result<()> {
let lua = self.0.lua;
let state = lua.state();
let size = self.raw_len();
if idx < 1 || idx > size + 1 {
return Err(Error::RuntimeError("index out of bounds".to_string()));
@ -299,12 +307,12 @@ impl<'lua> Table<'lua> {
let value = value.to_lua(lua)?;
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 5)?;
let _sg = StackGuard::new(state);
check_stack(state, 5)?;
lua.push_ref(&self.0);
lua.push_value(value)?;
protect_lua!(lua.state, 2, 0, |state| {
protect_lua!(state, 2, 0, |state| {
for i in (idx..=size).rev() {
// table[i+1] = table[i]
ffi::lua_rawgeti(state, -2, i);
@ -321,11 +329,12 @@ impl<'lua> Table<'lua> {
self.check_readonly_write()?;
let lua = self.0.lua;
let state = lua.state();
let value = value.to_lua(lua)?;
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 4)?;
let _sg = StackGuard::new(state);
check_stack(state, 4)?;
lua.push_ref(&self.0);
lua.push_value(value)?;
@ -336,9 +345,9 @@ impl<'lua> Table<'lua> {
}
if lua.unlikely_memory_error() {
callback(lua.state);
callback(state);
} else {
protect_lua!(lua.state, 2, 0, fn(state) callback(state))?;
protect_lua!(state, 2, 0, fn(state) callback(state))?;
}
}
Ok(())
@ -350,16 +359,17 @@ impl<'lua> Table<'lua> {
self.check_readonly_write()?;
let lua = self.0.lua;
let state = lua.state();
let value = unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 3)?;
let _sg = StackGuard::new(state);
check_stack(state, 3)?;
lua.push_ref(&self.0);
let len = ffi::lua_rawlen(lua.state, -1) as Integer;
ffi::lua_rawgeti(lua.state, -1, len);
let len = ffi::lua_rawlen(state, -1) as Integer;
ffi::lua_rawgeti(state, -1, len);
// Set slot to nil (it must be safe to do)
ffi::lua_pushnil(lua.state);
ffi::lua_rawseti(lua.state, -3, len);
ffi::lua_pushnil(state);
ffi::lua_rawseti(state, -3, len);
lua.pop_value()
};
V::from_lua(value, lua)
@ -374,6 +384,7 @@ impl<'lua> Table<'lua> {
/// For other key types this is equivalent to setting `table[key] = nil`.
pub fn raw_remove<K: ToLua<'lua>>(&self, key: K) -> Result<()> {
let lua = self.0.lua;
let state = lua.state();
let key = key.to_lua(lua)?;
match key {
Value::Integer(idx) => {
@ -382,11 +393,11 @@ impl<'lua> Table<'lua> {
return Err(Error::RuntimeError("index out of bounds".to_string()));
}
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 4)?;
let _sg = StackGuard::new(state);
check_stack(state, 4)?;
lua.push_ref(&self.0);
protect_lua!(lua.state, 1, 0, |state| {
protect_lua!(state, 1, 0, |state| {
for i in idx..size {
ffi::lua_rawgeti(state, -1, i + 1);
ffi::lua_rawseti(state, -2, i);
@ -412,12 +423,13 @@ impl<'lua> Table<'lua> {
}
let lua = self.0.lua;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 4)?;
let _sg = StackGuard::new(state);
check_stack(state, 4)?;
lua.push_ref(&self.0);
protect_lua!(lua.state, 1, 0, |state| ffi::luaL_len(state, -1))
protect_lua!(state, 1, 0, |state| ffi::luaL_len(state, -1))
}
}
@ -432,12 +444,13 @@ impl<'lua> Table<'lua> {
/// Unlike the `getmetatable` Lua function, this method ignores the `__metatable` field.
pub fn get_metatable(&self) -> Option<Table<'lua>> {
let lua = self.0.lua;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
assert_stack(lua.state, 2);
let _sg = StackGuard::new(state);
assert_stack(state, 2);
lua.push_ref(&self.0);
if ffi::lua_getmetatable(lua.state, -1) == 0 {
if ffi::lua_getmetatable(state, -1) == 0 {
None
} else {
Some(Table(lua.pop_ref()))
@ -457,17 +470,18 @@ impl<'lua> Table<'lua> {
}
let lua = self.0.lua;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
assert_stack(lua.state, 2);
let _sg = StackGuard::new(state);
assert_stack(state, 2);
lua.push_ref(&self.0);
if let Some(metatable) = metatable {
lua.push_ref(&metatable.0);
} else {
ffi::lua_pushnil(lua.state);
ffi::lua_pushnil(state);
}
ffi::lua_setmetatable(lua.state, -2);
ffi::lua_setmetatable(state, -2);
}
}
@ -654,16 +668,17 @@ impl<'lua> Table<'lua> {
#[cfg(feature = "serialize")]
pub(crate) fn is_array(&self) -> bool {
let lua = self.0.lua;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
assert_stack(lua.state, 3);
let _sg = StackGuard::new(state);
assert_stack(state, 3);
lua.push_ref(&self.0);
if ffi::lua_getmetatable(lua.state, -1) == 0 {
if ffi::lua_getmetatable(state, -1) == 0 {
return false;
}
crate::serde::push_array_metatable(lua.state);
ffi::lua_rawequal(lua.state, -1, -2) != 0
crate::serde::push_array_metatable(state);
ffi::lua_rawequal(state, -1, -2) != 0
}
}
@ -911,15 +926,16 @@ where
fn next(&mut self) -> Option<Self::Item> {
if let Some(prev_key) = self.key.take() {
let lua = self.table.lua;
let state = lua.state();
let res = (|| unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 5)?;
let _sg = StackGuard::new(state);
check_stack(state, 5)?;
lua.push_ref(&self.table);
lua.push_value(prev_key)?;
let next = protect_lua!(lua.state, 2, ffi::LUA_MULTRET, |state| {
let next = protect_lua!(state, 2, ffi::LUA_MULTRET, |state| {
ffi::lua_next(state, -2)
})?;
if next != 0 {
@ -971,16 +987,17 @@ where
fn next(&mut self) -> Option<Self::Item> {
if let Some(index) = self.index.take() {
let lua = self.table.lua;
let state = lua.state();
let res = (|| unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 1 + if self.raw { 0 } else { 3 })?;
let _sg = StackGuard::new(state);
check_stack(state, 1 + if self.raw { 0 } else { 3 })?;
lua.push_ref(&self.table);
let res = if self.raw {
ffi::lua_rawgeti(lua.state, -1, index)
ffi::lua_rawgeti(state, -1, index)
} else {
protect_lua!(lua.state, 1, 1, |state| ffi::lua_geti(state, -1, index))?
protect_lua!(state, 1, 1, |state| ffi::lua_geti(state, -1, index))?
};
match res {
ffi::LUA_TNIL if index > self.len.unwrap_or(0) => Ok(None),
@ -1001,3 +1018,10 @@ where
}
}
}
#[cfg(test)]
mod assertions {
use super::*;
static_assertions::assert_not_impl_any!(Table: Send);
}

View File

@ -22,7 +22,6 @@ use {
},
futures_core::{future::Future, stream::Stream},
std::{
cell::RefCell,
marker::PhantomData,
pin::Pin,
task::{Context, Poll, Waker},
@ -67,10 +66,9 @@ impl OwnedThread {
/// [`Stream`]: futures_core::stream::Stream
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
#[derive(Debug)]
pub struct AsyncThread<'lua, R> {
thread: Thread<'lua>,
args0: RefCell<Option<Result<MultiValue<'lua>>>>,
args0: Option<Result<MultiValue<'lua>>>,
ret: PhantomData<R>,
recycle: bool,
}
@ -123,11 +121,13 @@ impl<'lua> Thread<'lua> {
R: FromLuaMulti<'lua>,
{
let lua = self.0.lua;
let state = lua.state();
let mut args = args.to_lua_multi(lua)?;
let nargs = args.len() as c_int;
let results = unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, cmp::max(nargs + 1, 3))?;
let _sg = StackGuard::new(state);
check_stack(state, cmp::max(nargs + 1, 3))?;
let thread_state = ffi::lua_tothread(lua.ref_thread(), self.0.index);
@ -140,23 +140,23 @@ impl<'lua> Thread<'lua> {
for arg in args.drain_all() {
lua.push_value(arg)?;
}
ffi::lua_xmove(lua.state, thread_state, nargs);
ffi::lua_xmove(state, thread_state, nargs);
let mut nresults = 0;
let ret = ffi::lua_resume(thread_state, lua.state, nargs, &mut nresults as *mut c_int);
let ret = ffi::lua_resume(thread_state, state, nargs, &mut nresults as *mut c_int);
if ret != ffi::LUA_OK && ret != ffi::LUA_YIELD {
check_stack(lua.state, 3)?;
protect_lua!(lua.state, 0, 1, |state| error_traceback_thread(
check_stack(state, 3)?;
protect_lua!(state, 0, 1, |state| error_traceback_thread(
state,
thread_state
))?;
return Err(pop_error(lua.state, ret));
return Err(pop_error(state, ret));
}
let mut results = args; // Reuse MultiValue container
check_stack(lua.state, nresults + 2)?; // 2 is extra for `lua.pop_value()` below
ffi::lua_xmove(thread_state, lua.state, nresults);
check_stack(state, nresults + 2)?; // 2 is extra for `lua.pop_value()` below
ffi::lua_xmove(thread_state, state, nresults);
for _ in 0..nresults {
results.push_front(lua.pop_value());
@ -205,12 +205,13 @@ impl<'lua> Thread<'lua> {
))]
pub fn reset(&self, func: Function<'lua>) -> Result<()> {
let lua = self.0.lua;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 2)?;
let _sg = StackGuard::new(state);
check_stack(state, 2)?;
lua.push_ref(&self.0);
let thread_state = ffi::lua_tothread(lua.state, -1);
let thread_state = ffi::lua_tothread(state, -1);
#[cfg(feature = "lua54")]
let status = ffi::lua_resetthread(thread_state);
@ -219,17 +220,17 @@ impl<'lua> Thread<'lua> {
return Err(pop_error(thread_state, status));
}
#[cfg(all(feature = "luajit", feature = "vendored"))]
ffi::lua_resetthread(lua.state, thread_state);
ffi::lua_resetthread(state, thread_state);
#[cfg(feature = "luau")]
ffi::lua_resetthread(thread_state);
lua.push_ref(&func.0);
ffi::lua_xmove(lua.state, thread_state, 1);
ffi::lua_xmove(state, thread_state, 1);
#[cfg(feature = "luau")]
{
// Inherit `LUA_GLOBALSINDEX` from the caller
ffi::lua_xpush(lua.state, thread_state, ffi::LUA_GLOBALSINDEX);
ffi::lua_xpush(state, thread_state, ffi::LUA_GLOBALSINDEX);
ffi::lua_replace(thread_state, ffi::LUA_GLOBALSINDEX);
}
@ -292,7 +293,7 @@ impl<'lua> Thread<'lua> {
let args = args.to_lua_multi(self.0.lua);
AsyncThread {
thread: self,
args0: RefCell::new(Some(args)),
args0: Some(args),
ret: PhantomData,
recycle: false,
}
@ -334,14 +335,15 @@ impl<'lua> Thread<'lua> {
#[doc(hidden)]
pub fn sandbox(&self) -> Result<()> {
let lua = self.0.lua;
let state = lua.state();
unsafe {
let thread = ffi::lua_tothread(lua.ref_thread(), self.0.index);
check_stack(thread, 1)?;
check_stack(lua.state, 3)?;
check_stack(state, 3)?;
// Inherit `LUA_GLOBALSINDEX` from the caller
ffi::lua_xpush(lua.state, thread, ffi::LUA_GLOBALSINDEX);
ffi::lua_xpush(state, thread, ffi::LUA_GLOBALSINDEX);
ffi::lua_replace(thread, ffi::LUA_GLOBALSINDEX);
protect_lua!(lua.state, 0, 0, |_| ffi::luaL_sandboxthread(thread))
protect_lua!(state, 0, 0, |_| ffi::luaL_sandboxthread(thread))
}
}
@ -406,10 +408,13 @@ where
};
let _wg = WakerGuard::new(lua, cx.waker().clone());
let ret: MultiValue = if let Some(args) = self.args0.borrow_mut().take() {
self.thread.resume(args?)?
// This is safe as we are not moving the whole struct
let this = unsafe { self.get_unchecked_mut() };
let ret: MultiValue = if let Some(args) = this.args0.take() {
this.thread.resume(args?)?
} else {
self.thread.resume(())?
this.thread.resume(())?
};
if is_poll_pending(&ret) {
@ -437,17 +442,20 @@ where
};
let _wg = WakerGuard::new(lua, cx.waker().clone());
let ret: MultiValue = if let Some(args) = self.args0.borrow_mut().take() {
self.thread.resume(args?)?
// This is safe as we are not moving the whole struct
let this = unsafe { self.get_unchecked_mut() };
let ret: MultiValue = if let Some(args) = this.args0.take() {
this.thread.resume(args?)?
} else {
self.thread.resume(())?
this.thread.resume(())?
};
if is_poll_pending(&ret) {
return Poll::Pending;
}
if let ThreadStatus::Resumable = self.thread.status() {
if let ThreadStatus::Resumable = this.thread.status() {
// Ignore value returned via yield()
cx.waker().wake_by_ref();
return Poll::Pending;
@ -493,3 +501,10 @@ impl<'lua> Drop for WakerGuard<'lua> {
}
}
}
#[cfg(test)]
mod assertions {
use super::*;
static_assertions::assert_not_impl_any!(Thread: Send);
}

View File

@ -192,6 +192,7 @@ impl<'lua> LuaRef<'lua> {
}
}
#[inline]
pub(crate) fn into_owned(self) -> LuaOwnedRef {
self.lua.make_owned_ref(self)
}
@ -220,12 +221,13 @@ impl<'lua> Drop for LuaRef<'lua> {
impl<'lua> PartialEq for LuaRef<'lua> {
fn eq(&self, other: &Self) -> bool {
let lua = self.lua;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
assert_stack(lua.state, 2);
let _sg = StackGuard::new(state);
assert_stack(state, 2);
lua.push_ref(self);
lua.push_ref(other);
ffi::lua_rawequal(lua.state, -1, -2) == 1
ffi::lua_rawequal(state, -1, -2) == 1
}
}
}
@ -249,10 +251,10 @@ impl Clone for LuaOwnedRef {
impl Drop for LuaOwnedRef {
fn drop(&mut self) {
self.lua.drop_ref(&LuaRef {
drop(LuaRef {
lua: &self.lua,
index: self.index,
drop: false,
drop: true,
});
}
}
@ -266,3 +268,11 @@ impl LuaOwnedRef {
}
}
}
#[cfg(test)]
mod assertions {
use super::*;
static_assertions::assert_impl_all!(RegistryKey: Send, Sync);
static_assertions::assert_not_impl_any!(LuaRef: Send);
}

View File

@ -829,16 +829,17 @@ impl<'lua> AnyUserData<'lua> {
/// Keeps associated user values unchanged (they will be collected by Lua's GC).
pub fn take<T: 'static + UserData>(&self) -> Result<T> {
let lua = self.0.lua;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 2)?;
let _sg = StackGuard::new(state);
check_stack(state, 2)?;
let type_id = lua.push_userdata_ref(&self.0)?;
match type_id {
Some(type_id) if type_id == TypeId::of::<T>() => {
// Try to borrow userdata exclusively
let _ = (*get_userdata::<UserDataCell<T>>(lua.state, -1)).try_borrow_mut()?;
Ok(take_userdata::<UserDataCell<T>>(lua.state).into_inner())
let _ = (*get_userdata::<UserDataCell<T>>(state, -1)).try_borrow_mut()?;
Ok(take_userdata::<UserDataCell<T>>(state).into_inner())
}
_ => Err(Error::UserDataTypeMismatch),
}
@ -887,21 +888,22 @@ impl<'lua> AnyUserData<'lua> {
}
let lua = self.0.lua;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 5)?;
let _sg = StackGuard::new(state);
check_stack(state, 5)?;
lua.push_userdata_ref(&self.0)?;
lua.push_value(v.to_lua(lua)?)?;
#[cfg(feature = "lua54")]
if n < USER_VALUE_MAXSLOT {
ffi::lua_setiuservalue(lua.state, -2, n as c_int);
ffi::lua_setiuservalue(state, -2, n as c_int);
return Ok(());
}
// Multiple (extra) user values are emulated by storing them in a table
protect_lua!(lua.state, 2, 0, |state| {
protect_lua!(state, 2, 0, |state| {
if getuservalue_table(state, -2) != ffi::LUA_TTABLE {
// Create a new table to use as uservalue
ffi::lua_pop(state, 1);
@ -941,20 +943,21 @@ impl<'lua> AnyUserData<'lua> {
}
let lua = self.0.lua;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 4)?;
let _sg = StackGuard::new(state);
check_stack(state, 4)?;
lua.push_userdata_ref(&self.0)?;
#[cfg(feature = "lua54")]
if n < USER_VALUE_MAXSLOT {
ffi::lua_getiuservalue(lua.state, -1, n as c_int);
ffi::lua_getiuservalue(state, -1, n as c_int);
return V::from_lua(lua.pop_value(), lua);
}
// Multiple (extra) user values are emulated by storing them in a table
protect_lua!(lua.state, 1, 1, |state| {
protect_lua!(state, 1, 1, |state| {
if getuservalue_table(state, -1) != ffi::LUA_TTABLE {
ffi::lua_pushnil(state);
return;
@ -979,15 +982,16 @@ impl<'lua> AnyUserData<'lua> {
V: ToLua<'lua>,
{
let lua = self.0.lua;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 5)?;
let _sg = StackGuard::new(state);
check_stack(state, 5)?;
lua.push_userdata_ref(&self.0)?;
lua.push_value(v.to_lua(lua)?)?;
// Multiple (extra) user values are emulated by storing them in a table
protect_lua!(lua.state, 2, 0, |state| {
protect_lua!(state, 2, 0, |state| {
if getuservalue_table(state, -2) != ffi::LUA_TTABLE {
// Create a new table to use as uservalue
ffi::lua_pop(state, 1);
@ -1016,14 +1020,15 @@ impl<'lua> AnyUserData<'lua> {
V: FromLua<'lua>,
{
let lua = self.0.lua;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 4)?;
let _sg = StackGuard::new(state);
check_stack(state, 4)?;
lua.push_userdata_ref(&self.0)?;
// Multiple (extra) user values are emulated by storing them in a table
protect_lua!(lua.state, 1, 1, |state| {
protect_lua!(state, 1, 1, |state| {
if getuservalue_table(state, -1) != ffi::LUA_TTABLE {
ffi::lua_pushnil(state);
return;
@ -1050,13 +1055,14 @@ impl<'lua> AnyUserData<'lua> {
}
fn get_raw_metatable(&self) -> Result<Table<'lua>> {
let lua = self.0.lua;
let state = lua.state();
unsafe {
let lua = self.0.lua;
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 3)?;
let _sg = StackGuard::new(state);
check_stack(state, 3)?;
lua.push_userdata_ref(&self.0)?;
ffi::lua_getmetatable(lua.state, -1); // Checked that non-empty on the previous call
ffi::lua_getmetatable(state, -1); // Checked that non-empty on the previous call
Ok(Table(lua.pop_ref()))
}
}
@ -1093,14 +1099,15 @@ impl<'lua> AnyUserData<'lua> {
F: FnOnce(&'a UserDataCell<T>) -> Result<R>,
{
let lua = self.0.lua;
let state = lua.state();
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 2)?;
let _sg = StackGuard::new(state);
check_stack(state, 2)?;
let type_id = lua.push_userdata_ref(&self.0)?;
match type_id {
Some(type_id) if type_id == TypeId::of::<T>() => {
func(&*get_userdata::<UserDataCell<T>>(lua.state, -1))
func(&*get_userdata::<UserDataCell<T>>(state, -1))
}
_ => Err(Error::UserDataTypeMismatch),
}
@ -1209,12 +1216,13 @@ impl<'lua> Serialize for AnyUserData<'lua> {
S: Serializer,
{
let lua = self.0.lua;
let state = lua.state();
let data = unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 3).map_err(ser::Error::custom)?;
let _sg = StackGuard::new(state);
check_stack(state, 3).map_err(ser::Error::custom)?;
lua.push_userdata_ref(&self.0).map_err(ser::Error::custom)?;
let ud = &*get_userdata::<UserDataCell<()>>(lua.state, -1);
let ud = &*get_userdata::<UserDataCell<()>>(state, -1);
ud.0.try_borrow()
.map_err(|_| ser::Error::custom(Error::UserDataBorrowError))?
};
@ -1224,3 +1232,10 @@ impl<'lua> Serialize for AnyUserData<'lua> {
}
}
}
#[cfg(test)]
mod assertions {
use super::*;
static_assertions::assert_not_impl_any!(AnyUserData: Send);
}

View File

@ -211,42 +211,43 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
{
Box::new(move |lua, mut args| {
if let Some(front) = args.pop_front() {
let state = lua.state();
let userdata = AnyUserData::from_lua(front, lua)?;
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 2)?;
let _sg = StackGuard::new(state);
check_stack(state, 2)?;
let type_id = lua.push_userdata_ref(&userdata.0)?;
match type_id {
Some(id) if id == TypeId::of::<T>() => {
let ud = get_userdata_ref::<T>(lua.state)?;
let ud = get_userdata_ref::<T>(state)?;
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
}
#[cfg(not(feature = "send"))]
Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
let ud = get_userdata_ref::<Rc<RefCell<T>>>(lua.state)?;
let ud = get_userdata_ref::<Rc<RefCell<T>>>(state)?;
let ud = ud.try_borrow().map_err(|_| Error::UserDataBorrowError)?;
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
}
Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
let ud = get_userdata_ref::<Arc<Mutex<T>>>(lua.state)?;
let ud = get_userdata_ref::<Arc<Mutex<T>>>(state)?;
let ud = ud.try_lock().map_err(|_| Error::UserDataBorrowError)?;
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
}
#[cfg(feature = "parking_lot")]
Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(lua.state)?;
let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(state)?;
let ud = ud.try_lock().ok_or(Error::UserDataBorrowError)?;
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
}
Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
let ud = get_userdata_ref::<Arc<RwLock<T>>>(lua.state)?;
let ud = get_userdata_ref::<Arc<RwLock<T>>>(state)?;
let ud = ud.try_read().map_err(|_| Error::UserDataBorrowError)?;
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
}
#[cfg(feature = "parking_lot")]
Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
let ud = get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(lua.state)?;
let ud = get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(state)?;
let ud = ud.try_read().ok_or(Error::UserDataBorrowError)?;
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
}
@ -272,49 +273,50 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
let method = RefCell::new(method);
Box::new(move |lua, mut args| {
if let Some(front) = args.pop_front() {
let state = lua.state();
let userdata = AnyUserData::from_lua(front, lua)?;
let mut method = method
.try_borrow_mut()
.map_err(|_| Error::RecursiveMutCallback)?;
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 2)?;
let _sg = StackGuard::new(state);
check_stack(state, 2)?;
let type_id = lua.push_userdata_ref(&userdata.0)?;
match type_id {
Some(id) if id == TypeId::of::<T>() => {
let mut ud = get_userdata_mut::<T>(lua.state)?;
let mut ud = get_userdata_mut::<T>(state)?;
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
}
#[cfg(not(feature = "send"))]
Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
let ud = get_userdata_mut::<Rc<RefCell<T>>>(lua.state)?;
let ud = get_userdata_mut::<Rc<RefCell<T>>>(state)?;
let mut ud = ud
.try_borrow_mut()
.map_err(|_| Error::UserDataBorrowMutError)?;
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
}
Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
let ud = get_userdata_mut::<Arc<Mutex<T>>>(lua.state)?;
let ud = get_userdata_mut::<Arc<Mutex<T>>>(state)?;
let mut ud =
ud.try_lock().map_err(|_| Error::UserDataBorrowMutError)?;
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
}
#[cfg(feature = "parking_lot")]
Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
let ud = get_userdata_mut::<Arc<parking_lot::Mutex<T>>>(lua.state)?;
let ud = get_userdata_mut::<Arc<parking_lot::Mutex<T>>>(state)?;
let mut ud = ud.try_lock().ok_or(Error::UserDataBorrowMutError)?;
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
}
Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
let ud = get_userdata_mut::<Arc<RwLock<T>>>(lua.state)?;
let ud = get_userdata_mut::<Arc<RwLock<T>>>(state)?;
let mut ud =
ud.try_write().map_err(|_| Error::UserDataBorrowMutError)?;
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
}
#[cfg(feature = "parking_lot")]
Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
let ud = get_userdata_mut::<Arc<parking_lot::RwLock<T>>>(lua.state)?;
let ud = get_userdata_mut::<Arc<parking_lot::RwLock<T>>>(state)?;
let mut ud = ud.try_write().ok_or(Error::UserDataBorrowMutError)?;
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
}
@ -343,43 +345,43 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
Box::new(move |lua, mut args| {
let fut_res = || {
if let Some(front) = args.pop_front() {
let state = lua.state();
let userdata = AnyUserData::from_lua(front, lua)?;
unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, 2)?;
let _sg = StackGuard::new(state);
check_stack(state, 2)?;
let type_id = lua.push_userdata_ref(&userdata.0)?;
match type_id {
Some(id) if id == TypeId::of::<T>() => {
let ud = get_userdata_ref::<T>(lua.state)?;
let ud = get_userdata_ref::<T>(state)?;
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
}
#[cfg(not(feature = "send"))]
Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
let ud = get_userdata_ref::<Rc<RefCell<T>>>(lua.state)?;
let ud = get_userdata_ref::<Rc<RefCell<T>>>(state)?;
let ud = ud.try_borrow().map_err(|_| Error::UserDataBorrowError)?;
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
}
Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
let ud = get_userdata_ref::<Arc<Mutex<T>>>(lua.state)?;
let ud = get_userdata_ref::<Arc<Mutex<T>>>(state)?;
let ud = ud.try_lock().map_err(|_| Error::UserDataBorrowError)?;
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
}
#[cfg(feature = "parking_lot")]
Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(lua.state)?;
let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(state)?;
let ud = ud.try_lock().ok_or(Error::UserDataBorrowError)?;
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
}
Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
let ud = get_userdata_ref::<Arc<RwLock<T>>>(lua.state)?;
let ud = get_userdata_ref::<Arc<RwLock<T>>>(state)?;
let ud = ud.try_read().map_err(|_| Error::UserDataBorrowError)?;
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
}
#[cfg(feature = "parking_lot")]
Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
let ud =
get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(lua.state)?;
let ud = get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(state)?;
let ud = ud.try_read().ok_or(Error::UserDataBorrowError)?;
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
}

View File

@ -357,3 +357,11 @@ pub trait FromLuaMulti<'lua>: Sized {
/// any missing values are nil.
fn from_lua_multi(values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self>;
}
#[cfg(test)]
mod assertions {
use super::*;
static_assertions::assert_not_impl_any!(Value: Send);
static_assertions::assert_not_impl_any!(MultiValue: Send);
}