mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
Add Lua::scope back
This commit is contained in:
+1
-1
@@ -87,7 +87,7 @@ mod hook;
|
||||
mod luau;
|
||||
mod memory;
|
||||
mod multi;
|
||||
// mod scope;
|
||||
mod scope;
|
||||
mod state;
|
||||
mod stdlib;
|
||||
mod string;
|
||||
|
||||
+112
-790
File diff suppressed because it is too large
Load Diff
+17
-20
@@ -12,7 +12,7 @@ use crate::error::{Error, Result};
|
||||
use crate::function::Function;
|
||||
use crate::hook::Debug;
|
||||
use crate::memory::MemoryState;
|
||||
// use crate::scope::Scope;
|
||||
use crate::scope::Scope;
|
||||
use crate::stdlib::StdLib;
|
||||
use crate::string::String;
|
||||
use crate::table::Table;
|
||||
@@ -21,7 +21,7 @@ use crate::types::{
|
||||
AppDataRef, AppDataRefMut, ArcReentrantMutexGuard, Integer, LightUserData, MaybeSend, Number,
|
||||
ReentrantMutex, ReentrantMutexGuard, RegistryKey, XRc, XWeak,
|
||||
};
|
||||
use crate::userdata::{AnyUserData, UserData, UserDataProxy, UserDataRegistry, UserDataVariant};
|
||||
use crate::userdata::{AnyUserData, UserData, UserDataProxy, UserDataRegistry, UserDataStorage};
|
||||
use crate::util::{assert_stack, check_stack, push_string, push_table, rawset_field, StackGuard};
|
||||
use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, MultiValue, Nil, Value};
|
||||
|
||||
@@ -1201,7 +1201,7 @@ impl Lua {
|
||||
where
|
||||
T: UserData + MaybeSend + 'static,
|
||||
{
|
||||
unsafe { self.lock().make_userdata(UserDataVariant::new(data)) }
|
||||
unsafe { self.lock().make_userdata(UserDataStorage::new(data)) }
|
||||
}
|
||||
|
||||
/// Creates a Lua userdata object from a custom serializable userdata type.
|
||||
@@ -1214,7 +1214,7 @@ impl Lua {
|
||||
where
|
||||
T: UserData + Serialize + MaybeSend + 'static,
|
||||
{
|
||||
unsafe { self.lock().make_userdata(UserDataVariant::new_ser(data)) }
|
||||
unsafe { self.lock().make_userdata(UserDataStorage::new_ser(data)) }
|
||||
}
|
||||
|
||||
/// Creates a Lua userdata object from a custom Rust type.
|
||||
@@ -1229,7 +1229,7 @@ impl Lua {
|
||||
where
|
||||
T: MaybeSend + 'static,
|
||||
{
|
||||
unsafe { self.lock().make_any_userdata(UserDataVariant::new(data)) }
|
||||
unsafe { self.lock().make_any_userdata(UserDataStorage::new(data)) }
|
||||
}
|
||||
|
||||
/// Creates a Lua userdata object from a custom serializable Rust type.
|
||||
@@ -1244,26 +1244,26 @@ impl Lua {
|
||||
where
|
||||
T: Serialize + MaybeSend + 'static,
|
||||
{
|
||||
unsafe { (self.lock()).make_any_userdata(UserDataVariant::new_ser(data)) }
|
||||
unsafe { (self.lock()).make_any_userdata(UserDataStorage::new_ser(data)) }
|
||||
}
|
||||
|
||||
/// Registers a custom Rust type in Lua to use in userdata objects.
|
||||
///
|
||||
/// This methods provides a way to add fields or methods to userdata objects of a type `T`.
|
||||
pub fn register_userdata_type<T: 'static>(&self, f: impl FnOnce(&mut UserDataRegistry<T>)) -> Result<()> {
|
||||
let mut registry = const { UserDataRegistry::new() };
|
||||
let type_id = TypeId::of::<T>();
|
||||
let mut registry = UserDataRegistry::new(type_id);
|
||||
f(&mut registry);
|
||||
|
||||
let lua = self.lock();
|
||||
unsafe {
|
||||
// Deregister the type if it already registered
|
||||
let type_id = TypeId::of::<T>();
|
||||
if let Some(&table_id) = (*lua.extra.get()).registered_userdata.get(&type_id) {
|
||||
if let Some(&table_id) = (*lua.extra.get()).registered_userdata_t.get(&type_id) {
|
||||
ffi::luaL_unref(lua.state(), ffi::LUA_REGISTRYINDEX, table_id);
|
||||
}
|
||||
|
||||
// Register the type
|
||||
lua.register_userdata_metatable(registry)?;
|
||||
lua.create_userdata_metatable(registry)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1306,7 +1306,7 @@ impl Lua {
|
||||
T: UserData + 'static,
|
||||
{
|
||||
let ud = UserDataProxy::<T>(PhantomData);
|
||||
unsafe { self.lock().make_userdata(UserDataVariant::new(ud)) }
|
||||
unsafe { self.lock().make_userdata(UserDataStorage::new(ud)) }
|
||||
}
|
||||
|
||||
/// Sets the metatable for a Luau builtin vector type.
|
||||
@@ -1380,15 +1380,12 @@ impl Lua {
|
||||
/// dropped. `Function` types will error when called, and `AnyUserData` will be typeless. It
|
||||
/// would be impossible to prevent handles to scoped values from escaping anyway, since you
|
||||
/// would always be able to smuggle them through Lua state.
|
||||
// pub fn scope<'lua, 'scope, R>(
|
||||
// &'lua self,
|
||||
// f: impl FnOnce(&Scope<'lua, 'scope>) -> Result<R>,
|
||||
// ) -> Result<R>
|
||||
// where
|
||||
// 'lua: 'scope,
|
||||
// {
|
||||
// f(&Scope::new(self))
|
||||
// }
|
||||
pub fn scope<'env, R>(
|
||||
&self,
|
||||
f: impl for<'scope> FnOnce(&'scope mut Scope<'scope, 'env>) -> Result<R>,
|
||||
) -> Result<R> {
|
||||
f(&mut Scope::new(self.lock_arc()))
|
||||
}
|
||||
|
||||
/// Attempts to coerce a Lua value into a String in a manner consistent with Lua's internal
|
||||
/// behavior.
|
||||
|
||||
+2
-2
@@ -35,7 +35,7 @@ pub(crate) struct ExtraData {
|
||||
pub(super) weak: MaybeUninit<WeakLua>,
|
||||
pub(super) owned: bool,
|
||||
|
||||
pub(super) registered_userdata: FxHashMap<TypeId, c_int>,
|
||||
pub(super) registered_userdata_t: FxHashMap<TypeId, c_int>,
|
||||
pub(super) registered_userdata_mt: FxHashMap<*const c_void, Option<TypeId>>,
|
||||
pub(super) last_checked_userdata_mt: (*const c_void, Option<TypeId>),
|
||||
|
||||
@@ -144,7 +144,7 @@ impl ExtraData {
|
||||
lua: MaybeUninit::uninit(),
|
||||
weak: MaybeUninit::uninit(),
|
||||
owned,
|
||||
registered_userdata: FxHashMap::default(),
|
||||
registered_userdata_t: FxHashMap::default(),
|
||||
registered_userdata_mt: FxHashMap::default(),
|
||||
last_checked_userdata_mt: (ptr::null(), None),
|
||||
registry_unref_list: Arc::new(Mutex::new(Some(Vec::new()))),
|
||||
|
||||
+50
-56
@@ -20,7 +20,7 @@ use crate::types::{
|
||||
AppDataRef, AppDataRefMut, Callback, CallbackUpvalue, DestructedUserdata, Integer, LightUserData,
|
||||
MaybeSend, ReentrantMutex, RegistryKey, SubtypeId, ValueRef, XRc,
|
||||
};
|
||||
use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataRegistry, UserDataVariant};
|
||||
use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataRegistry, UserDataStorage};
|
||||
use crate::util::{
|
||||
assert_stack, check_stack, get_destructed_userdata_metatable, get_internal_userdata, get_main_state,
|
||||
get_userdata, init_error_registry, init_internal_metatable, init_userdata_metatable, pop_error,
|
||||
@@ -711,45 +711,45 @@ impl RawLua {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn make_userdata<T>(&self, data: UserDataVariant<T>) -> Result<AnyUserData>
|
||||
pub(crate) unsafe fn make_userdata<T>(&self, data: UserDataStorage<T>) -> Result<AnyUserData>
|
||||
where
|
||||
T: UserData + 'static,
|
||||
{
|
||||
self.make_userdata_with_metatable(data, || {
|
||||
// Check if userdata/metatable is already registered
|
||||
let type_id = TypeId::of::<T>();
|
||||
if let Some(&table_id) = (*self.extra.get()).registered_userdata.get(&type_id) {
|
||||
if let Some(&table_id) = (*self.extra.get()).registered_userdata_t.get(&type_id) {
|
||||
return Ok(table_id as Integer);
|
||||
}
|
||||
|
||||
// Create a new metatable from `UserData` definition
|
||||
let mut registry = const { UserDataRegistry::new() };
|
||||
let mut registry = UserDataRegistry::new(type_id);
|
||||
T::register(&mut registry);
|
||||
|
||||
self.register_userdata_metatable(registry)
|
||||
self.create_userdata_metatable(registry)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn make_any_userdata<T>(&self, data: UserDataVariant<T>) -> Result<AnyUserData>
|
||||
pub(crate) unsafe fn make_any_userdata<T>(&self, data: UserDataStorage<T>) -> Result<AnyUserData>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
self.make_userdata_with_metatable(data, || {
|
||||
// Check if userdata/metatable is already registered
|
||||
let type_id = TypeId::of::<T>();
|
||||
if let Some(&table_id) = (*self.extra.get()).registered_userdata.get(&type_id) {
|
||||
if let Some(&table_id) = (*self.extra.get()).registered_userdata_t.get(&type_id) {
|
||||
return Ok(table_id as Integer);
|
||||
}
|
||||
|
||||
// Create an empty metatable
|
||||
let registry = const { UserDataRegistry::new() };
|
||||
self.register_userdata_metatable::<T>(registry)
|
||||
let registry = UserDataRegistry::<T>::new(type_id);
|
||||
self.create_userdata_metatable(registry)
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn make_userdata_with_metatable<T>(
|
||||
&self,
|
||||
data: UserDataVariant<T>,
|
||||
data: UserDataStorage<T>,
|
||||
get_metatable_id: impl FnOnce() -> Result<Integer>,
|
||||
) -> Result<AnyUserData> {
|
||||
let state = self.state();
|
||||
@@ -760,10 +760,7 @@ impl RawLua {
|
||||
ffi::lua_pushnil(state);
|
||||
ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, get_metatable_id()?);
|
||||
let protect = !self.unlikely_memory_error();
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
crate::util::push_userdata(state, data, protect)?;
|
||||
#[cfg(feature = "lua54")]
|
||||
crate::util::push_userdata_uv(state, data, crate::userdata::USER_VALUE_MAXSLOT as c_int, protect)?;
|
||||
ffi::lua_replace(state, -3);
|
||||
ffi::lua_setmetatable(state, -2);
|
||||
|
||||
@@ -782,12 +779,31 @@ impl RawLua {
|
||||
Ok(AnyUserData(self.pop_ref(), SubtypeId::None))
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn register_userdata_metatable<T: 'static>(
|
||||
pub(crate) unsafe fn create_userdata_metatable<T>(
|
||||
&self,
|
||||
mut registry: UserDataRegistry<T>,
|
||||
registry: UserDataRegistry<T>,
|
||||
) -> Result<Integer> {
|
||||
let state = self.state();
|
||||
let _sg = StackGuard::new(state);
|
||||
let type_id = registry.type_id();
|
||||
|
||||
self.push_userdata_metatable(registry)?;
|
||||
|
||||
let mt_ptr = ffi::lua_topointer(state, -1);
|
||||
let id = protect_lua!(state, 1, 0, |state| {
|
||||
ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
|
||||
})?;
|
||||
|
||||
if let Some(type_id) = type_id {
|
||||
(*self.extra.get()).registered_userdata_t.insert(type_id, id);
|
||||
}
|
||||
self.register_userdata_metatable(mt_ptr, type_id);
|
||||
|
||||
Ok(id as Integer)
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn push_userdata_metatable<T>(&self, mut registry: UserDataRegistry<T>) -> Result<()> {
|
||||
let state = self.state();
|
||||
let _sg = StackGuard::with_top(state, ffi::lua_gettop(state) + 1);
|
||||
check_stack(state, 13)?;
|
||||
|
||||
// Prepare metatable, add meta methods first and then meta fields
|
||||
@@ -922,7 +938,7 @@ impl RawLua {
|
||||
let extra_init = None;
|
||||
#[cfg(not(feature = "luau"))]
|
||||
let extra_init: Option<fn(*mut ffi::lua_State) -> Result<()>> = Some(|state| {
|
||||
ffi::lua_pushcfunction(state, crate::util::userdata_destructor::<UserDataVariant<T>>);
|
||||
ffi::lua_pushcfunction(state, crate::util::userdata_destructor::<UserDataStorage<T>>);
|
||||
rawset_field(state, -2, "__gc")
|
||||
});
|
||||
|
||||
@@ -938,44 +954,21 @@ impl RawLua {
|
||||
// Pop extra tables to get metatable on top of the stack
|
||||
ffi::lua_pop(state, extra_tables_count);
|
||||
|
||||
let mt_ptr = ffi::lua_topointer(state, -1);
|
||||
let id = protect_lua!(state, 1, 0, |state| {
|
||||
ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
|
||||
})?;
|
||||
|
||||
let type_id = TypeId::of::<T>();
|
||||
(*self.extra.get()).registered_userdata.insert(type_id, id);
|
||||
(*self.extra.get())
|
||||
.registered_userdata_mt
|
||||
.insert(mt_ptr, Some(type_id));
|
||||
|
||||
Ok(id as Integer)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// #[inline]
|
||||
// pub(crate) unsafe fn register_raw_userdata_metatable(
|
||||
// &self,
|
||||
// ptr: *const c_void,
|
||||
// type_id: Option<TypeId>,
|
||||
// ) {
|
||||
// (*self.extra.get())
|
||||
// .registered_userdata_mt
|
||||
// .insert(ptr, type_id);
|
||||
// }
|
||||
#[inline(always)]
|
||||
pub(crate) unsafe fn register_userdata_metatable(&self, mt_ptr: *const c_void, type_id: Option<TypeId>) {
|
||||
(*self.extra.get()).registered_userdata_mt.insert(mt_ptr, type_id);
|
||||
}
|
||||
|
||||
// #[inline]
|
||||
// pub(crate) unsafe fn deregister_raw_userdata_metatable(&self, ptr: *const c_void) {
|
||||
// (*self.extra.get()).registered_userdata_mt.remove(&ptr);
|
||||
// if (*self.extra.get()).last_checked_userdata_mt.0 == ptr {
|
||||
// (*self.extra.get()).last_checked_userdata_mt = (ptr::null(), None);
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[inline(always)]
|
||||
// pub(crate) unsafe fn get_userdata_ref<T: 'static>(&self, idx: c_int) -> Result<UserDataRef<T>> {
|
||||
// let guard = self.lua().lock_arc();
|
||||
// (*get_userdata::<UserDataVariant<T>>(self.state(), idx)).try_make_ref(guard)
|
||||
// }
|
||||
#[inline(always)]
|
||||
pub(crate) unsafe fn deregister_userdata_metatable(&self, mt_ptr: *const c_void) {
|
||||
(*self.extra.get()).registered_userdata_mt.remove(&mt_ptr);
|
||||
if (*self.extra.get()).last_checked_userdata_mt.0 == mt_ptr {
|
||||
(*self.extra.get()).last_checked_userdata_mt = (ptr::null(), None);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns `TypeId` for the userdata ref, checking that it's registered and not destructed.
|
||||
//
|
||||
@@ -1028,8 +1021,6 @@ impl RawLua {
|
||||
|
||||
// Creates a Function out of a Callback containing a 'static Fn.
|
||||
pub(crate) fn create_callback(&self, func: Callback) -> Result<Function> {
|
||||
// This is non-scoped version of the callback (upvalue is always valid)
|
||||
// TODO: add a scoped version
|
||||
unsafe extern "C-unwind" fn call_callback(state: *mut ffi::lua_State) -> c_int {
|
||||
let upvalue = get_userdata::<CallbackUpvalue>(state, ffi::lua_upvalueindex(1));
|
||||
callback_error_ext(state, (*upvalue).extra.get(), |extra, nargs| {
|
||||
@@ -1037,8 +1028,10 @@ impl RawLua {
|
||||
// The lock must be already held as the callback is executed
|
||||
let rawlua = (*extra).raw_lua();
|
||||
let _guard = StateGuard::new(rawlua, state);
|
||||
let func = &*(*upvalue).data;
|
||||
func(rawlua, nargs)
|
||||
match (*upvalue).data {
|
||||
Some(ref func) => func(rawlua, nargs),
|
||||
None => Err(Error::CallbackDestructed),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1047,6 +1040,7 @@ impl RawLua {
|
||||
let _sg = StackGuard::new(state);
|
||||
check_stack(state, 4)?;
|
||||
|
||||
let func = Some(func);
|
||||
let extra = XRc::clone(&self.extra);
|
||||
let protect = !self.unlikely_memory_error();
|
||||
push_internal_userdata(state, CallbackUpvalue { data: func, extra }, protect)?;
|
||||
|
||||
+3
-1
@@ -52,12 +52,14 @@ pub(crate) type Callback = Box<dyn Fn(&RawLua, c_int) -> Result<c_int> + Send +
|
||||
#[cfg(not(feature = "send"))]
|
||||
pub(crate) type Callback = Box<dyn Fn(&RawLua, c_int) -> Result<c_int> + 'static>;
|
||||
|
||||
pub(crate) type ScopedCallback<'s> = Box<dyn Fn(&RawLua, c_int) -> Result<c_int> + 's>;
|
||||
|
||||
pub(crate) struct Upvalue<T> {
|
||||
pub(crate) data: T,
|
||||
pub(crate) extra: XRc<UnsafeCell<ExtraData>>,
|
||||
}
|
||||
|
||||
pub(crate) type CallbackUpvalue = Upvalue<Callback>;
|
||||
pub(crate) type CallbackUpvalue = Upvalue<Option<Callback>>;
|
||||
|
||||
#[cfg(all(feature = "async", feature = "send"))]
|
||||
pub(crate) type AsyncCallback =
|
||||
|
||||
+38
-62
@@ -2,7 +2,7 @@ use std::any::TypeId;
|
||||
use std::ffi::CStr;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::os::raw::{c_char, c_void};
|
||||
use std::string::String as StdString;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
@@ -16,7 +16,7 @@ use {
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::function::Function;
|
||||
use crate::state::{Lua, LuaGuard};
|
||||
use crate::state::Lua;
|
||||
use crate::string::String;
|
||||
use crate::table::{Table, TablePairs};
|
||||
use crate::types::{MaybeSend, SubtypeId, ValueRef};
|
||||
@@ -24,14 +24,11 @@ use crate::util::{check_stack, get_userdata, take_userdata, StackGuard};
|
||||
use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Value};
|
||||
|
||||
// Re-export for convenience
|
||||
pub(crate) use cell::UserDataVariant;
|
||||
pub(crate) use cell::UserDataStorage;
|
||||
pub use cell::{UserDataRef, UserDataRefMut};
|
||||
pub(crate) use registry::UserDataProxy;
|
||||
pub use registry::UserDataRegistry;
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
pub(crate) const USER_VALUE_MAXSLOT: usize = 8;
|
||||
|
||||
/// Kinds of metamethods that can be overridden.
|
||||
///
|
||||
/// Currently, this mechanism does not allow overriding the `__gc` metamethod, since there is
|
||||
@@ -650,8 +647,9 @@ pub struct AnyUserData(pub(crate) ValueRef, pub(crate) SubtypeId);
|
||||
|
||||
impl AnyUserData {
|
||||
/// Checks whether the type of this userdata is `T`.
|
||||
#[inline]
|
||||
pub fn is<T: 'static>(&self) -> bool {
|
||||
self.inspect::<T, _, _>(|_, _| Ok(())).is_ok()
|
||||
self.inspect::<T, _, _>(|_| Ok(())).is_ok()
|
||||
}
|
||||
|
||||
/// Borrow this userdata immutably if it is of type `T`.
|
||||
@@ -659,10 +657,18 @@ impl AnyUserData {
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns a `UserDataBorrowError` if the userdata is already mutably borrowed. Returns a
|
||||
/// `UserDataTypeMismatch` if the userdata is not of type `T`.
|
||||
/// `UserDataTypeMismatch` if the userdata is not of type `T` or if it's scoped.
|
||||
#[inline]
|
||||
pub fn borrow<T: 'static>(&self) -> Result<UserDataRef<T>> {
|
||||
self.inspect(|variant, _| variant.try_borrow_owned())
|
||||
self.inspect(|ud| ud.try_borrow_owned())
|
||||
}
|
||||
|
||||
/// Borrow this userdata immutably if it is of type `T`, passing the borrowed value
|
||||
/// to the closure.
|
||||
///
|
||||
/// This method is the only way to borrow scoped userdata (created inside [`Lua::scope`]).
|
||||
pub fn borrow_scoped<T: 'static, R>(&self, f: impl FnOnce(&T) -> R) -> Result<R> {
|
||||
self.inspect(|ud| ud.try_borrow_scoped(|ud| f(ud)))
|
||||
}
|
||||
|
||||
/// Borrow this userdata mutably if it is of type `T`.
|
||||
@@ -670,10 +676,18 @@ impl AnyUserData {
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns a `UserDataBorrowMutError` if the userdata cannot be mutably borrowed.
|
||||
/// Returns a `UserDataTypeMismatch` if the userdata is not of type `T`.
|
||||
/// Returns a `UserDataTypeMismatch` if the userdata is not of type `T` or if it's scoped.
|
||||
#[inline]
|
||||
pub fn borrow_mut<T: 'static>(&self) -> Result<UserDataRefMut<T>> {
|
||||
self.inspect(|variant, _| variant.try_borrow_owned_mut())
|
||||
self.inspect(|ud| ud.try_borrow_owned_mut())
|
||||
}
|
||||
|
||||
/// Borrow this userdata mutably if it is of type `T`, passing the borrowed value
|
||||
/// to the closure.
|
||||
///
|
||||
/// This method is the only way to borrow scoped userdata (created inside [`Lua::scope`]).
|
||||
pub fn borrow_mut_scoped<T: 'static, R>(&self, f: impl FnOnce(&mut T) -> R) -> Result<R> {
|
||||
self.inspect(|ud| ud.try_borrow_scoped_mut(|ud| f(ud)))
|
||||
}
|
||||
|
||||
/// Takes the value out of this userdata.
|
||||
@@ -692,8 +706,8 @@ impl AnyUserData {
|
||||
match type_id {
|
||||
Some(type_id) if type_id == TypeId::of::<T>() => {
|
||||
// Try to borrow userdata exclusively
|
||||
let _ = (*get_userdata::<UserDataVariant<T>>(state, -1)).try_borrow_mut()?;
|
||||
take_userdata::<UserDataVariant<T>>(state).into_inner()
|
||||
let _ = (*get_userdata::<UserDataStorage<T>>(state, -1)).try_borrow_mut()?;
|
||||
take_userdata::<UserDataStorage<T>>(state).into_inner()
|
||||
}
|
||||
_ => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
@@ -754,29 +768,16 @@ impl AnyUserData {
|
||||
lua.push_userdata_ref(&self.0)?;
|
||||
lua.push(v)?;
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
if n < USER_VALUE_MAXSLOT {
|
||||
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!(state, 2, 0, |state| {
|
||||
if getuservalue_table(state, -2) != ffi::LUA_TTABLE {
|
||||
if ffi::lua_getuservalue(state, -2) != ffi::LUA_TTABLE {
|
||||
// Create a new table to use as uservalue
|
||||
ffi::lua_pop(state, 1);
|
||||
ffi::lua_newtable(state);
|
||||
ffi::lua_pushvalue(state, -1);
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
ffi::lua_setiuservalue(state, -4, USER_VALUE_MAXSLOT as c_int);
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
ffi::lua_setuservalue(state, -4);
|
||||
}
|
||||
ffi::lua_pushvalue(state, -2);
|
||||
#[cfg(feature = "lua54")]
|
||||
ffi::lua_rawseti(state, -2, (n - USER_VALUE_MAXSLOT + 1) as ffi::lua_Integer);
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
ffi::lua_rawseti(state, -2, n as ffi::lua_Integer);
|
||||
})?;
|
||||
|
||||
@@ -806,21 +807,12 @@ impl AnyUserData {
|
||||
|
||||
lua.push_userdata_ref(&self.0)?;
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
if n < USER_VALUE_MAXSLOT {
|
||||
ffi::lua_getiuservalue(state, -1, n as c_int);
|
||||
return V::from_lua(lua.pop_value(), lua.lua());
|
||||
}
|
||||
|
||||
// Multiple (extra) user values are emulated by storing them in a table
|
||||
protect_lua!(state, 1, 1, |state| {
|
||||
if getuservalue_table(state, -1) != ffi::LUA_TTABLE {
|
||||
if ffi::lua_getuservalue(state, -1) != ffi::LUA_TTABLE {
|
||||
ffi::lua_pushnil(state);
|
||||
return;
|
||||
}
|
||||
#[cfg(feature = "lua54")]
|
||||
ffi::lua_rawgeti(state, -1, (n - USER_VALUE_MAXSLOT + 1) as ffi::lua_Integer);
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
ffi::lua_rawgeti(state, -1, n as ffi::lua_Integer);
|
||||
})?;
|
||||
|
||||
@@ -851,15 +843,11 @@ impl AnyUserData {
|
||||
|
||||
// Multiple (extra) user values are emulated by storing them in a table
|
||||
protect_lua!(state, 2, 0, |state| {
|
||||
if getuservalue_table(state, -2) != ffi::LUA_TTABLE {
|
||||
if ffi::lua_getuservalue(state, -2) != ffi::LUA_TTABLE {
|
||||
// Create a new table to use as uservalue
|
||||
ffi::lua_pop(state, 1);
|
||||
ffi::lua_newtable(state);
|
||||
ffi::lua_pushvalue(state, -1);
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
ffi::lua_setiuservalue(state, -4, USER_VALUE_MAXSLOT as c_int);
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
ffi::lua_setuservalue(state, -4);
|
||||
}
|
||||
ffi::lua_pushlstring(state, name.as_ptr() as *const c_char, name.len());
|
||||
@@ -885,7 +873,7 @@ impl AnyUserData {
|
||||
|
||||
// Multiple (extra) user values are emulated by storing them in a table
|
||||
protect_lua!(state, 1, 1, |state| {
|
||||
if getuservalue_table(state, -1) != ffi::LUA_TTABLE {
|
||||
if ffi::lua_getuservalue(state, -1) != ffi::LUA_TTABLE {
|
||||
ffi::lua_pushnil(state);
|
||||
return;
|
||||
}
|
||||
@@ -998,29 +986,24 @@ impl AnyUserData {
|
||||
let is_serializable = || unsafe {
|
||||
// Userdata must be registered and not destructed
|
||||
let _ = lua.get_userdata_ref_type_id(&self.0)?;
|
||||
|
||||
let ud = &*get_userdata::<UserDataVariant<()>>(lua.ref_thread(), self.0.index);
|
||||
match ud {
|
||||
UserDataVariant::Serializable(..) => Result::Ok(true),
|
||||
_ => Result::Ok(false),
|
||||
}
|
||||
let ud = &*get_userdata::<UserDataStorage<()>>(lua.ref_thread(), self.0.index);
|
||||
Ok::<_, Error>((*ud).is_serializable())
|
||||
};
|
||||
is_serializable().unwrap_or(false)
|
||||
}
|
||||
|
||||
pub(crate) fn inspect<'a, T, F, R>(&'a self, func: F) -> Result<R>
|
||||
pub(crate) fn inspect<T, F, R>(&self, func: F) -> Result<R>
|
||||
where
|
||||
T: 'static,
|
||||
F: FnOnce(&'a UserDataVariant<T>, LuaGuard) -> Result<R>,
|
||||
F: FnOnce(&UserDataStorage<T>) -> Result<R>,
|
||||
{
|
||||
let lua = self.0.lua.lock();
|
||||
unsafe {
|
||||
let type_id = lua.get_userdata_ref_type_id(&self.0)?;
|
||||
match type_id {
|
||||
Some(type_id) if type_id == TypeId::of::<T>() => {
|
||||
let ref_thread = lua.ref_thread();
|
||||
let ud = get_userdata::<UserDataVariant<T>>(ref_thread, self.0.index);
|
||||
func(&*ud, lua)
|
||||
let ud = get_userdata::<UserDataStorage<T>>(lua.ref_thread(), self.0.index);
|
||||
func(&*ud)
|
||||
}
|
||||
_ => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
@@ -1041,13 +1024,6 @@ impl AsRef<AnyUserData> for AnyUserData {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn getuservalue_table(state: *mut ffi::lua_State, idx: c_int) -> c_int {
|
||||
#[cfg(feature = "lua54")]
|
||||
return ffi::lua_getiuservalue(state, idx, USER_VALUE_MAXSLOT as c_int);
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
return ffi::lua_getuservalue(state, idx);
|
||||
}
|
||||
|
||||
/// Handle to a `UserData` metatable.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UserDataMetatable(pub(crate) Table);
|
||||
@@ -1146,7 +1122,7 @@ impl Serialize for AnyUserData {
|
||||
let _ = lua
|
||||
.get_userdata_ref_type_id(&self.0)
|
||||
.map_err(ser::Error::custom)?;
|
||||
let ud = &*get_userdata::<UserDataVariant<()>>(lua.ref_thread(), self.0.index);
|
||||
let ud = &*get_userdata::<UserDataStorage<()>>(lua.ref_thread(), self.0.index);
|
||||
ud.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
+135
-26
@@ -1,5 +1,5 @@
|
||||
use std::any::{type_name, TypeId};
|
||||
use std::cell::UnsafeCell;
|
||||
use std::cell::{RefCell, UnsafeCell};
|
||||
use std::fmt;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::raw::c_int;
|
||||
@@ -22,6 +22,11 @@ type DynSerialize = dyn erased_serde::Serialize;
|
||||
#[cfg(all(feature = "serialize", feature = "send"))]
|
||||
type DynSerialize = dyn erased_serde::Serialize + Send;
|
||||
|
||||
pub(crate) enum UserDataStorage<T> {
|
||||
Owned(UserDataVariant<T>),
|
||||
Scoped(ScopedUserDataVariant<T>),
|
||||
}
|
||||
|
||||
// A enum for storing userdata values.
|
||||
// It's stored inside a Lua VM and protected by the outer `ReentrantMutex`.
|
||||
pub(crate) enum UserDataVariant<T> {
|
||||
@@ -42,39 +47,34 @@ impl<T> Clone for UserDataVariant<T> {
|
||||
}
|
||||
|
||||
impl<T> UserDataVariant<T> {
|
||||
#[inline(always)]
|
||||
pub(crate) fn new(data: T) -> Self {
|
||||
Self::Default(XRc::new(UserDataCell::new(data)))
|
||||
}
|
||||
|
||||
// Immutably borrows the wrapped value in-place.
|
||||
#[inline(always)]
|
||||
pub(crate) fn try_borrow(&self) -> Result<UserDataBorrowRef<T>> {
|
||||
fn try_borrow(&self) -> Result<UserDataBorrowRef<T>> {
|
||||
UserDataBorrowRef::try_from(self)
|
||||
}
|
||||
|
||||
// Immutably borrows the wrapped value and returns an owned reference.
|
||||
#[inline(always)]
|
||||
pub(crate) fn try_borrow_owned(&self) -> Result<UserDataRef<T>> {
|
||||
fn try_borrow_owned(&self) -> Result<UserDataRef<T>> {
|
||||
UserDataRef::try_from(self.clone())
|
||||
}
|
||||
|
||||
// Mutably borrows the wrapped value in-place.
|
||||
#[inline(always)]
|
||||
pub(crate) fn try_borrow_mut(&self) -> Result<UserDataBorrowMut<T>> {
|
||||
fn try_borrow_mut(&self) -> Result<UserDataBorrowMut<T>> {
|
||||
UserDataBorrowMut::try_from(self)
|
||||
}
|
||||
|
||||
// Mutably borrows the wrapped value and returns an owned reference.
|
||||
#[inline(always)]
|
||||
pub(crate) fn try_borrow_owned_mut(&self) -> Result<UserDataRefMut<T>> {
|
||||
fn try_borrow_owned_mut(&self) -> Result<UserDataRefMut<T>> {
|
||||
UserDataRefMut::try_from(self.clone())
|
||||
}
|
||||
|
||||
// Returns the wrapped value.
|
||||
//
|
||||
// This method checks that we have exclusive access to the value.
|
||||
pub(crate) fn into_inner(self) -> Result<T> {
|
||||
fn into_inner(self) -> Result<T> {
|
||||
if !self.raw_lock().try_lock_exclusive() {
|
||||
return Err(Error::UserDataBorrowMutError);
|
||||
}
|
||||
@@ -108,20 +108,10 @@ impl<T> UserDataVariant<T> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
impl<T: Serialize + MaybeSend + 'static> UserDataVariant<T> {
|
||||
#[inline(always)]
|
||||
pub(crate) fn new_ser(data: T) -> Self {
|
||||
let data = Box::new(data) as Box<DynSerialize>;
|
||||
Self::Serializable(XRc::new(UserDataCell::new(data)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
impl Serialize for UserDataVariant<()> {
|
||||
impl Serialize for UserDataStorage<()> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
|
||||
match self {
|
||||
Self::Default(_) => Err(serde::ser::Error::custom("cannot serialize <userdata>")),
|
||||
Self::Serializable(inner) => unsafe {
|
||||
Self::Owned(UserDataVariant::Serializable(inner)) => unsafe {
|
||||
// We need to borrow the inner value exclusively to serialize it.
|
||||
#[cfg(feature = "send")]
|
||||
let _guard = self.try_borrow_mut().map_err(serde::ser::Error::custom)?;
|
||||
@@ -130,6 +120,7 @@ impl Serialize for UserDataVariant<()> {
|
||||
let _guard = self.try_borrow().map_err(serde::ser::Error::custom)?;
|
||||
(*inner.value.get()).serialize(serializer)
|
||||
},
|
||||
_ => Err(serde::ser::Error::custom("cannot serialize <userdata>")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,7 +136,7 @@ unsafe impl<T: Send> Sync for UserDataCell<T> {}
|
||||
|
||||
impl<T> UserDataCell<T> {
|
||||
#[inline(always)]
|
||||
pub fn new(value: T) -> Self {
|
||||
fn new(value: T) -> Self {
|
||||
UserDataCell {
|
||||
raw_lock: RawLock::INIT,
|
||||
value: UnsafeCell::new(value),
|
||||
@@ -207,7 +198,7 @@ impl<T: 'static> FromLua for UserDataRef<T> {
|
||||
let type_id = lua.get_userdata_type_id(idx)?;
|
||||
match type_id {
|
||||
Some(type_id) if type_id == TypeId::of::<T>() => {
|
||||
(*get_userdata::<UserDataVariant<T>>(lua.state(), idx)).try_borrow_owned()
|
||||
(*get_userdata::<UserDataStorage<T>>(lua.state(), idx)).try_borrow_owned()
|
||||
}
|
||||
_ => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
@@ -275,7 +266,7 @@ impl<T: 'static> FromLua for UserDataRefMut<T> {
|
||||
let type_id = lua.get_userdata_type_id(idx)?;
|
||||
match type_id {
|
||||
Some(type_id) if type_id == TypeId::of::<T>() => {
|
||||
(*get_userdata::<UserDataVariant<T>>(lua.state(), idx)).try_borrow_owned_mut()
|
||||
(*get_userdata::<UserDataStorage<T>>(lua.state(), idx)).try_borrow_owned_mut()
|
||||
}
|
||||
_ => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
@@ -363,6 +354,124 @@ fn try_value_to_userdata<T>(value: Value) -> Result<AnyUserData> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum ScopedUserDataVariant<T> {
|
||||
Ref(*const T),
|
||||
RefMut(RefCell<*mut T>),
|
||||
Boxed(RefCell<*mut T>),
|
||||
}
|
||||
|
||||
impl<T> Drop for ScopedUserDataVariant<T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
if let Self::Boxed(value) = self {
|
||||
if let Ok(value) = value.try_borrow_mut() {
|
||||
unsafe { drop(Box::from_raw(*value)) };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> UserDataStorage<T> {
|
||||
#[inline(always)]
|
||||
pub(crate) fn new(data: T) -> Self {
|
||||
Self::Owned(UserDataVariant::Default(XRc::new(UserDataCell::new(data))))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn new_ref(data: &T) -> Self {
|
||||
Self::Scoped(ScopedUserDataVariant::Ref(data))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn new_ref_mut(data: &mut T) -> Self {
|
||||
Self::Scoped(ScopedUserDataVariant::RefMut(RefCell::new(data)))
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
#[inline(always)]
|
||||
pub(crate) fn new_ser(data: T) -> Self
|
||||
where
|
||||
T: Serialize + MaybeSend,
|
||||
{
|
||||
let data = Box::new(data) as Box<DynSerialize>;
|
||||
Self::Owned(UserDataVariant::Serializable(XRc::new(UserDataCell::new(data))))
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
#[inline(always)]
|
||||
pub(crate) fn is_serializable(&self) -> bool {
|
||||
matches!(self, Self::Owned(UserDataVariant::Serializable(_)))
|
||||
}
|
||||
|
||||
// Immutably borrows the wrapped value and returns an owned reference.
|
||||
#[inline(always)]
|
||||
pub(crate) fn try_borrow_owned(&self) -> Result<UserDataRef<T>> {
|
||||
match self {
|
||||
Self::Owned(data) => data.try_borrow_owned(),
|
||||
Self::Scoped(_) => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn try_borrow_mut(&self) -> Result<UserDataBorrowMut<T>> {
|
||||
match self {
|
||||
Self::Owned(data) => data.try_borrow_mut(),
|
||||
Self::Scoped(_) => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
}
|
||||
|
||||
// Mutably borrows the wrapped value and returns an owned reference.
|
||||
#[inline(always)]
|
||||
pub(crate) fn try_borrow_owned_mut(&self) -> Result<UserDataRefMut<T>> {
|
||||
match self {
|
||||
Self::Owned(data) => data.try_borrow_owned_mut(),
|
||||
Self::Scoped(_) => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn into_inner(self) -> Result<T> {
|
||||
match self {
|
||||
Self::Owned(data) => data.into_inner(),
|
||||
Self::Scoped(_) => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> UserDataStorage<T> {
|
||||
#[inline(always)]
|
||||
pub(crate) fn new_scoped(data: T) -> Self {
|
||||
let data = Box::into_raw(Box::new(data));
|
||||
Self::Scoped(ScopedUserDataVariant::Boxed(RefCell::new(data)))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn try_borrow_scoped<R>(&self, f: impl FnOnce(&T) -> R) -> Result<R> {
|
||||
match self {
|
||||
Self::Owned(data) => Ok(f(&*data.try_borrow()?)),
|
||||
Self::Scoped(ScopedUserDataVariant::Ref(value)) => Ok(f(unsafe { &**value })),
|
||||
Self::Scoped(ScopedUserDataVariant::RefMut(value) | ScopedUserDataVariant::Boxed(value)) => {
|
||||
let t = value.try_borrow().map_err(|_| Error::UserDataBorrowError)?;
|
||||
Ok(f(unsafe { &**t }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn try_borrow_scoped_mut<R>(&self, f: impl FnOnce(&mut T) -> R) -> Result<R> {
|
||||
match self {
|
||||
Self::Owned(data) => Ok(f(&mut *data.try_borrow_mut()?)),
|
||||
Self::Scoped(ScopedUserDataVariant::Ref(_)) => Err(Error::UserDataBorrowMutError),
|
||||
Self::Scoped(ScopedUserDataVariant::RefMut(value) | ScopedUserDataVariant::Boxed(value)) => {
|
||||
let mut t = value
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| Error::UserDataBorrowMutError)?;
|
||||
Ok(f(unsafe { &mut **t }))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod assertions {
|
||||
use super::*;
|
||||
|
||||
+121
-64
@@ -3,7 +3,7 @@
|
||||
use std::any::TypeId;
|
||||
use std::cell::RefCell;
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_int;
|
||||
use std::os::raw::c_void;
|
||||
use std::string::String as StdString;
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
@@ -11,12 +11,11 @@ use crate::state::{Lua, RawLua};
|
||||
use crate::types::{Callback, MaybeSend};
|
||||
use crate::userdata::{
|
||||
AnyUserData, MetaMethod, UserData, UserDataFields, UserDataMethods, UserDataRef, UserDataRefMut,
|
||||
UserDataStorage,
|
||||
};
|
||||
use crate::util::{get_userdata, short_type_name};
|
||||
use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Value};
|
||||
|
||||
use super::cell::{UserDataBorrowMut, UserDataBorrowRef, UserDataVariant};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
use {
|
||||
crate::types::AsyncCallback,
|
||||
@@ -25,8 +24,14 @@ use {
|
||||
|
||||
type StaticFieldCallback = Box<dyn FnOnce(&RawLua) -> Result<()> + 'static>;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) enum UserDataTypeId {
|
||||
Shared(TypeId),
|
||||
Unique(usize),
|
||||
}
|
||||
|
||||
/// Handle to registry for userdata methods and metamethods.
|
||||
pub struct UserDataRegistry<T: 'static> {
|
||||
pub struct UserDataRegistry<T> {
|
||||
// Fields
|
||||
pub(crate) fields: Vec<(String, StaticFieldCallback)>,
|
||||
pub(crate) field_getters: Vec<(String, Callback)>,
|
||||
@@ -41,11 +46,13 @@ pub struct UserDataRegistry<T: 'static> {
|
||||
#[cfg(feature = "async")]
|
||||
pub(crate) async_meta_methods: Vec<(String, AsyncCallback)>,
|
||||
|
||||
pub(crate) type_id: UserDataTypeId,
|
||||
_type: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: 'static> UserDataRegistry<T> {
|
||||
pub(crate) const fn new() -> Self {
|
||||
impl<T> UserDataRegistry<T> {
|
||||
#[inline]
|
||||
pub(crate) fn new(type_id: TypeId) -> Self {
|
||||
UserDataRegistry {
|
||||
fields: Vec::new(),
|
||||
field_getters: Vec::new(),
|
||||
@@ -57,11 +64,38 @@ impl<T: 'static> UserDataRegistry<T> {
|
||||
meta_methods: Vec::new(),
|
||||
#[cfg(feature = "async")]
|
||||
async_meta_methods: Vec::new(),
|
||||
type_id: UserDataTypeId::Shared(type_id),
|
||||
_type: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn box_method<M, A, R>(name: &str, method: M) -> Callback
|
||||
#[inline]
|
||||
pub(crate) fn new_unique(ud_ptr: *const c_void) -> Self {
|
||||
UserDataRegistry {
|
||||
fields: Vec::new(),
|
||||
field_getters: Vec::new(),
|
||||
field_setters: Vec::new(),
|
||||
meta_fields: Vec::new(),
|
||||
methods: Vec::new(),
|
||||
#[cfg(feature = "async")]
|
||||
async_methods: Vec::new(),
|
||||
meta_methods: Vec::new(),
|
||||
#[cfg(feature = "async")]
|
||||
async_meta_methods: Vec::new(),
|
||||
type_id: UserDataTypeId::Unique(ud_ptr as usize),
|
||||
_type: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn type_id(&self) -> Option<TypeId> {
|
||||
match self.type_id {
|
||||
UserDataTypeId::Shared(type_id) => Some(type_id),
|
||||
UserDataTypeId::Unique(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn box_method<M, A, R>(&self, name: &str, method: M) -> Callback
|
||||
where
|
||||
M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
|
||||
A: FromLuaMulti,
|
||||
@@ -74,6 +108,7 @@ impl<T: 'static> UserDataRegistry<T> {
|
||||
};
|
||||
}
|
||||
|
||||
let target_type_id = self.type_id;
|
||||
Box::new(move |rawlua, nargs| unsafe {
|
||||
if nargs == 0 {
|
||||
let err = Error::from_lua_conversion("missing argument", "userdata", None);
|
||||
@@ -85,17 +120,34 @@ impl<T: 'static> UserDataRegistry<T> {
|
||||
// Self was at position 1, so we pass 2 here
|
||||
let args = A::from_stack_args(nargs - 1, 2, Some(&name), rawlua);
|
||||
|
||||
match try_self_arg!(rawlua.get_userdata_type_id(self_index)) {
|
||||
Some(id) if id == TypeId::of::<T>() => {
|
||||
let ud = try_self_arg!(borrow_userdata_ref::<T>(state, self_index));
|
||||
method(rawlua.lua(), &ud, args?)?.push_into_stack_multi(rawlua)
|
||||
match target_type_id {
|
||||
// This branch is for `'static` userdata that share type metatable
|
||||
UserDataTypeId::Shared(target_type_id) => {
|
||||
match try_self_arg!(rawlua.get_userdata_type_id(self_index)) {
|
||||
Some(self_type_id) if self_type_id == target_type_id => {
|
||||
let ud = get_userdata::<UserDataStorage<T>>(state, self_index);
|
||||
try_self_arg!((*ud).try_borrow_scoped(|ud| {
|
||||
method(rawlua.lua(), ud, args?)?.push_into_stack_multi(rawlua)
|
||||
}))
|
||||
}
|
||||
_ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)),
|
||||
}
|
||||
}
|
||||
UserDataTypeId::Unique(target_ptr) => {
|
||||
match get_userdata::<UserDataStorage<T>>(state, self_index) {
|
||||
ud if ud as usize == target_ptr => {
|
||||
try_self_arg!((*ud).try_borrow_scoped(|ud| {
|
||||
method(rawlua.lua(), ud, args?)?.push_into_stack_multi(rawlua)
|
||||
}))
|
||||
}
|
||||
_ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)),
|
||||
}
|
||||
}
|
||||
_ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn box_method_mut<M, A, R>(name: &str, method: M) -> Callback
|
||||
fn box_method_mut<M, A, R>(&self, name: &str, method: M) -> Callback
|
||||
where
|
||||
M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
|
||||
A: FromLuaMulti,
|
||||
@@ -109,6 +161,7 @@ impl<T: 'static> UserDataRegistry<T> {
|
||||
}
|
||||
|
||||
let method = RefCell::new(method);
|
||||
let target_type_id = self.type_id;
|
||||
Box::new(move |rawlua, nargs| unsafe {
|
||||
let mut method = method.try_borrow_mut().map_err(|_| Error::RecursiveMutCallback)?;
|
||||
if nargs == 0 {
|
||||
@@ -121,19 +174,37 @@ impl<T: 'static> UserDataRegistry<T> {
|
||||
// Self was at position 1, so we pass 2 here
|
||||
let args = A::from_stack_args(nargs - 1, 2, Some(&name), rawlua);
|
||||
|
||||
match try_self_arg!(rawlua.get_userdata_type_id(self_index)) {
|
||||
Some(id) if id == TypeId::of::<T>() => {
|
||||
let mut ud = try_self_arg!(borrow_userdata_mut::<T>(state, self_index));
|
||||
method(rawlua.lua(), &mut ud, args?)?.push_into_stack_multi(rawlua)
|
||||
match target_type_id {
|
||||
// This branch is for `'static` userdata that share type metatable
|
||||
UserDataTypeId::Shared(target_type_id) => {
|
||||
match try_self_arg!(rawlua.get_userdata_type_id(self_index)) {
|
||||
Some(self_type_id) if self_type_id == target_type_id => {
|
||||
let ud = get_userdata::<UserDataStorage<T>>(state, self_index);
|
||||
try_self_arg!((*ud).try_borrow_scoped_mut(|ud| {
|
||||
method(rawlua.lua(), ud, args?)?.push_into_stack_multi(rawlua)
|
||||
}))
|
||||
}
|
||||
_ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)),
|
||||
}
|
||||
}
|
||||
UserDataTypeId::Unique(target_ptr) => {
|
||||
match get_userdata::<UserDataStorage<T>>(state, self_index) {
|
||||
ud if ud as usize == target_ptr => {
|
||||
try_self_arg!((*ud).try_borrow_scoped_mut(|ud| {
|
||||
method(rawlua.lua(), ud, args?)?.push_into_stack_multi(rawlua)
|
||||
}))
|
||||
}
|
||||
_ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)),
|
||||
}
|
||||
}
|
||||
_ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
fn box_async_method<M, A, MR, R>(name: &str, method: M) -> AsyncCallback
|
||||
fn box_async_method<M, A, MR, R>(&self, name: &str, method: M) -> AsyncCallback
|
||||
where
|
||||
T: 'static,
|
||||
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
|
||||
A: FromLuaMulti,
|
||||
MR: Future<Output = Result<R>> + MaybeSend + 'static,
|
||||
@@ -171,8 +242,9 @@ impl<T: 'static> UserDataRegistry<T> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
fn box_async_method_mut<M, A, MR, R>(name: &str, method: M) -> AsyncCallback
|
||||
fn box_async_method_mut<M, A, MR, R>(&self, name: &str, method: M) -> AsyncCallback
|
||||
where
|
||||
T: 'static,
|
||||
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
|
||||
A: FromLuaMulti,
|
||||
MR: Future<Output = Result<R>> + MaybeSend + 'static,
|
||||
@@ -209,7 +281,7 @@ impl<T: 'static> UserDataRegistry<T> {
|
||||
})
|
||||
}
|
||||
|
||||
fn box_function<F, A, R>(name: &str, function: F) -> Callback
|
||||
fn box_function<F, A, R>(&self, name: &str, function: F) -> Callback
|
||||
where
|
||||
F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
|
||||
A: FromLuaMulti,
|
||||
@@ -222,7 +294,7 @@ impl<T: 'static> UserDataRegistry<T> {
|
||||
})
|
||||
}
|
||||
|
||||
fn box_function_mut<F, A, R>(name: &str, function: F) -> Callback
|
||||
fn box_function_mut<F, A, R>(&self, name: &str, function: F) -> Callback
|
||||
where
|
||||
F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
|
||||
A: FromLuaMulti,
|
||||
@@ -240,7 +312,7 @@ impl<T: 'static> UserDataRegistry<T> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
fn box_async_function<F, A, FR, R>(name: &str, function: F) -> AsyncCallback
|
||||
fn box_async_function<F, A, FR, R>(&self, name: &str, function: F) -> AsyncCallback
|
||||
where
|
||||
F: Fn(Lua, A) -> FR + MaybeSend + 'static,
|
||||
A: FromLuaMulti,
|
||||
@@ -282,7 +354,7 @@ fn get_function_name<T>(name: &str) -> StdString {
|
||||
format!("{}.{name}", short_type_name::<T>())
|
||||
}
|
||||
|
||||
impl<T: 'static> UserDataFields<T> for UserDataRegistry<T> {
|
||||
impl<T> UserDataFields<T> for UserDataRegistry<T> {
|
||||
fn add_field<V>(&mut self, name: impl ToString, value: V)
|
||||
where
|
||||
V: IntoLua + 'static,
|
||||
@@ -300,7 +372,7 @@ impl<T: 'static> UserDataFields<T> for UserDataRegistry<T> {
|
||||
R: IntoLua,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_method(&name, move |lua, data, ()| method(lua, data));
|
||||
let callback = self.box_method(&name, move |lua, data, ()| method(lua, data));
|
||||
self.field_getters.push((name, callback));
|
||||
}
|
||||
|
||||
@@ -310,7 +382,7 @@ impl<T: 'static> UserDataFields<T> for UserDataRegistry<T> {
|
||||
A: FromLua,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_method_mut(&name, method);
|
||||
let callback = self.box_method_mut(&name, method);
|
||||
self.field_setters.push((name, callback));
|
||||
}
|
||||
|
||||
@@ -320,7 +392,7 @@ impl<T: 'static> UserDataFields<T> for UserDataRegistry<T> {
|
||||
R: IntoLua,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_function(&name, function);
|
||||
let callback = self.box_function(&name, function);
|
||||
self.field_getters.push((name, callback));
|
||||
}
|
||||
|
||||
@@ -330,7 +402,7 @@ impl<T: 'static> UserDataFields<T> for UserDataRegistry<T> {
|
||||
A: FromLua,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_function_mut(&name, move |lua, (data, val)| function(lua, data, val));
|
||||
let callback = self.box_function_mut(&name, move |lua, (data, val)| function(lua, data, val));
|
||||
self.field_setters.push((name, callback));
|
||||
}
|
||||
|
||||
@@ -363,7 +435,7 @@ impl<T: 'static> UserDataFields<T> for UserDataRegistry<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> UserDataMethods<T> for UserDataRegistry<T> {
|
||||
impl<T> UserDataMethods<T> for UserDataRegistry<T> {
|
||||
fn add_method<M, A, R>(&mut self, name: impl ToString, method: M)
|
||||
where
|
||||
M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
|
||||
@@ -371,7 +443,7 @@ impl<T: 'static> UserDataMethods<T> for UserDataRegistry<T> {
|
||||
R: IntoLuaMulti,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_method(&name, method);
|
||||
let callback = self.box_method(&name, method);
|
||||
self.methods.push((name, callback));
|
||||
}
|
||||
|
||||
@@ -382,33 +454,35 @@ impl<T: 'static> UserDataMethods<T> for UserDataRegistry<T> {
|
||||
R: IntoLuaMulti,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_method_mut(&name, method);
|
||||
let callback = self.box_method_mut(&name, method);
|
||||
self.methods.push((name, callback));
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
fn add_async_method<M, A, MR, R>(&mut self, name: impl ToString, method: M)
|
||||
where
|
||||
T: 'static,
|
||||
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
|
||||
A: FromLuaMulti,
|
||||
MR: Future<Output = Result<R>> + MaybeSend + 'static,
|
||||
R: IntoLuaMulti,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_async_method(&name, method);
|
||||
let callback = self.box_async_method(&name, method);
|
||||
self.async_methods.push((name, callback));
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl ToString, method: M)
|
||||
where
|
||||
T: 'static,
|
||||
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
|
||||
A: FromLuaMulti,
|
||||
MR: Future<Output = Result<R>> + MaybeSend + 'static,
|
||||
R: IntoLuaMulti,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_async_method_mut(&name, method);
|
||||
let callback = self.box_async_method_mut(&name, method);
|
||||
self.async_methods.push((name, callback));
|
||||
}
|
||||
|
||||
@@ -419,7 +493,7 @@ impl<T: 'static> UserDataMethods<T> for UserDataRegistry<T> {
|
||||
R: IntoLuaMulti,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_function(&name, function);
|
||||
let callback = self.box_function(&name, function);
|
||||
self.methods.push((name, callback));
|
||||
}
|
||||
|
||||
@@ -430,7 +504,7 @@ impl<T: 'static> UserDataMethods<T> for UserDataRegistry<T> {
|
||||
R: IntoLuaMulti,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_function_mut(&name, function);
|
||||
let callback = self.box_function_mut(&name, function);
|
||||
self.methods.push((name, callback));
|
||||
}
|
||||
|
||||
@@ -443,7 +517,7 @@ impl<T: 'static> UserDataMethods<T> for UserDataRegistry<T> {
|
||||
R: IntoLuaMulti,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_async_function(&name, function);
|
||||
let callback = self.box_async_function(&name, function);
|
||||
self.async_methods.push((name, callback));
|
||||
}
|
||||
|
||||
@@ -454,7 +528,7 @@ impl<T: 'static> UserDataMethods<T> for UserDataRegistry<T> {
|
||||
R: IntoLuaMulti,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_method(&name, method);
|
||||
let callback = self.box_method(&name, method);
|
||||
self.meta_methods.push((name, callback));
|
||||
}
|
||||
|
||||
@@ -465,33 +539,35 @@ impl<T: 'static> UserDataMethods<T> for UserDataRegistry<T> {
|
||||
R: IntoLuaMulti,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_method_mut(&name, method);
|
||||
let callback = self.box_method_mut(&name, method);
|
||||
self.meta_methods.push((name, callback));
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
|
||||
fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl ToString, method: M)
|
||||
where
|
||||
T: 'static,
|
||||
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
|
||||
A: FromLuaMulti,
|
||||
MR: Future<Output = Result<R>> + MaybeSend + 'static,
|
||||
R: IntoLuaMulti,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_async_method(&name, method);
|
||||
let callback = self.box_async_method(&name, method);
|
||||
self.async_meta_methods.push((name, callback));
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
|
||||
fn add_async_meta_method_mut<M, A, MR, R>(&mut self, name: impl ToString, method: M)
|
||||
where
|
||||
T: 'static,
|
||||
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
|
||||
A: FromLuaMulti,
|
||||
MR: Future<Output = Result<R>> + MaybeSend + 'static,
|
||||
R: IntoLuaMulti,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_async_method_mut(&name, method);
|
||||
let callback = self.box_async_method_mut(&name, method);
|
||||
self.async_meta_methods.push((name, callback));
|
||||
}
|
||||
|
||||
@@ -502,7 +578,7 @@ impl<T: 'static> UserDataMethods<T> for UserDataRegistry<T> {
|
||||
R: IntoLuaMulti,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_function(&name, function);
|
||||
let callback = self.box_function(&name, function);
|
||||
self.meta_methods.push((name, callback));
|
||||
}
|
||||
|
||||
@@ -513,7 +589,7 @@ impl<T: 'static> UserDataMethods<T> for UserDataRegistry<T> {
|
||||
R: IntoLuaMulti,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_function_mut(&name, function);
|
||||
let callback = self.box_function_mut(&name, function);
|
||||
self.meta_methods.push((name, callback));
|
||||
}
|
||||
|
||||
@@ -526,36 +602,17 @@ impl<T: 'static> UserDataMethods<T> for UserDataRegistry<T> {
|
||||
R: IntoLuaMulti,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let callback = Self::box_async_function(&name, function);
|
||||
let callback = self.box_async_function(&name, function);
|
||||
self.async_meta_methods.push((name, callback));
|
||||
}
|
||||
}
|
||||
|
||||
// Borrow the userdata in-place from the Lua stack
|
||||
#[inline(always)]
|
||||
unsafe fn borrow_userdata_ref<'a, T>(
|
||||
state: *mut ffi::lua_State,
|
||||
index: c_int,
|
||||
) -> Result<UserDataBorrowRef<'a, T>> {
|
||||
let ud = get_userdata::<UserDataVariant<T>>(state, index);
|
||||
(*ud).try_borrow()
|
||||
}
|
||||
|
||||
// Borrow the userdata mutably in-place from the Lua stack
|
||||
#[inline(always)]
|
||||
unsafe fn borrow_userdata_mut<'a, T>(
|
||||
state: *mut ffi::lua_State,
|
||||
index: c_int,
|
||||
) -> Result<UserDataBorrowMut<'a, T>> {
|
||||
let ud = get_userdata::<UserDataVariant<T>>(state, index);
|
||||
(*ud).try_borrow_mut()
|
||||
}
|
||||
|
||||
macro_rules! lua_userdata_impl {
|
||||
($type:ty) => {
|
||||
impl<T: UserData + 'static> UserData for $type {
|
||||
fn register(registry: &mut UserDataRegistry<Self>) {
|
||||
let mut orig_registry = UserDataRegistry::new();
|
||||
let type_id = TypeId::of::<T>();
|
||||
let mut orig_registry = UserDataRegistry::new(type_id);
|
||||
T::register(&mut orig_registry);
|
||||
|
||||
// Copy all fields, methods, etc. from the original registry
|
||||
|
||||
+1
-1
@@ -365,7 +365,7 @@ pub(crate) unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<(
|
||||
// Create destructed userdata metatable
|
||||
|
||||
unsafe extern "C-unwind" fn destructed_error(state: *mut ffi::lua_State) -> c_int {
|
||||
callback_error(state, |_| Err(Error::CallbackDestructed))
|
||||
callback_error(state, |_| Err(Error::UserDataDestructed))
|
||||
}
|
||||
|
||||
push_table(state, 0, 26, true)?;
|
||||
|
||||
+2
-3
@@ -17,10 +17,9 @@ pub(crate) use userdata::{
|
||||
DESTRUCTED_USERDATA_METATABLE,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub(crate) use userdata::push_uninit_userdata;
|
||||
pub(crate) use userdata::push_userdata;
|
||||
#[cfg(feature = "lua54")]
|
||||
pub(crate) use userdata::push_userdata_uv;
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub(crate) use userdata::userdata_destructor;
|
||||
|
||||
+17
-29
@@ -83,46 +83,34 @@ pub(crate) unsafe fn get_internal_userdata<T: TypeKey>(
|
||||
|
||||
// Internally uses 3 stack spaces, does not call checkstack.
|
||||
#[inline]
|
||||
pub(crate) unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool) -> Result<()> {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
let ud = if protect {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub(crate) unsafe fn push_uninit_userdata<T>(state: *mut ffi::lua_State, protect: bool) -> Result<*mut T> {
|
||||
if protect {
|
||||
protect_lua!(state, 0, 1, |state| {
|
||||
ffi::lua_newuserdata(state, std::mem::size_of::<T>()) as *mut T
|
||||
})?
|
||||
})
|
||||
} else {
|
||||
ffi::lua_newuserdata(state, std::mem::size_of::<T>()) as *mut T
|
||||
};
|
||||
Ok(ffi::lua_newuserdata(state, std::mem::size_of::<T>()) as *mut T)
|
||||
}
|
||||
}
|
||||
|
||||
// Internally uses 3 stack spaces, does not call checkstack.
|
||||
#[inline]
|
||||
pub(crate) unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool) -> Result<*mut T> {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
let ud_ptr = push_uninit_userdata(state, protect)?;
|
||||
#[cfg(feature = "luau")]
|
||||
let ud = if protect {
|
||||
let ud_ptr = if protect {
|
||||
protect_lua!(state, 0, 1, |state| { ffi::lua_newuserdata_t::<T>(state) })?
|
||||
} else {
|
||||
ffi::lua_newuserdata_t::<T>(state)
|
||||
};
|
||||
ptr::write(ud, t);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Internally uses 3 stack spaces, does not call checkstack.
|
||||
#[cfg(feature = "lua54")]
|
||||
#[inline]
|
||||
pub(crate) unsafe fn push_userdata_uv<T>(
|
||||
state: *mut ffi::lua_State,
|
||||
t: T,
|
||||
nuvalue: c_int,
|
||||
protect: bool,
|
||||
) -> Result<()> {
|
||||
let ud = if protect {
|
||||
protect_lua!(state, 0, 1, |state| {
|
||||
ffi::lua_newuserdatauv(state, std::mem::size_of::<T>(), nuvalue) as *mut T
|
||||
})?
|
||||
} else {
|
||||
ffi::lua_newuserdatauv(state, std::mem::size_of::<T>(), nuvalue) as *mut T
|
||||
};
|
||||
ptr::write(ud, t);
|
||||
Ok(())
|
||||
ptr::write(ud_ptr, t);
|
||||
Ok(ud_ptr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub(crate) unsafe fn get_userdata<T>(state: *mut ffi::lua_State, index: c_int) -> *mut T {
|
||||
let ud = ffi::lua_touserdata(state, index) as *mut T;
|
||||
mlua_debug_assert!(!ud.is_null(), "userdata pointer is null");
|
||||
|
||||
@@ -7,8 +7,6 @@ fn test_compilation() {
|
||||
t.compile_fail("tests/compile/lua_norefunwindsafe.rs");
|
||||
t.compile_fail("tests/compile/ref_nounwindsafe.rs");
|
||||
t.compile_fail("tests/compile/scope_callback_capture.rs");
|
||||
t.compile_fail("tests/compile/scope_callback_inner.rs");
|
||||
t.compile_fail("tests/compile/scope_callback_outer.rs");
|
||||
t.compile_fail("tests/compile/scope_invariance.rs");
|
||||
t.compile_fail("tests/compile/scope_mutable_aliasing.rs");
|
||||
t.compile_fail("tests/compile/scope_userdata_borrow.rs");
|
||||
@@ -17,7 +15,6 @@ fn test_compilation() {
|
||||
{
|
||||
t.compile_fail("tests/compile/async_any_userdata_method.rs");
|
||||
t.compile_fail("tests/compile/async_nonstatic_userdata.rs");
|
||||
t.compile_fail("tests/compile/async_userdata_method.rs");
|
||||
}
|
||||
|
||||
#[cfg(feature = "send")]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use mlua::{UserDataMethods, Lua};
|
||||
use mlua::{Lua, UserDataMethods};
|
||||
|
||||
fn main() {
|
||||
let lua = Lua::new();
|
||||
@@ -6,9 +6,10 @@ fn main() {
|
||||
lua.register_userdata_type::<String>(|reg| {
|
||||
let s = String::new();
|
||||
let mut s = &s;
|
||||
reg.add_async_method("t", |_, this: &String, ()| async {
|
||||
s = this;
|
||||
reg.add_async_method("t", |_, this, ()| async {
|
||||
s = &*this;
|
||||
Ok(())
|
||||
});
|
||||
}).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -1,20 +1,42 @@
|
||||
error[E0596]: cannot borrow `s` as mutable, as it is a captured variable in a `Fn` closure
|
||||
--> tests/compile/async_any_userdata_method.rs:9:58
|
||||
--> tests/compile/async_any_userdata_method.rs:9:49
|
||||
|
|
||||
9 | reg.add_async_method("t", |_, this: &String, ()| async {
|
||||
| ^^^^^ cannot borrow as mutable
|
||||
10 | s = this;
|
||||
9 | reg.add_async_method("t", |_, this, ()| async {
|
||||
| ^^^^^ cannot borrow as mutable
|
||||
10 | s = &*this;
|
||||
| - mutable borrow occurs due to use of `s` in closure
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> tests/compile/async_any_userdata_method.rs:9:58
|
||||
error[E0373]: async block may outlive the current function, but it borrows `this`, which is owned by the current function
|
||||
--> tests/compile/async_any_userdata_method.rs:9:49
|
||||
|
|
||||
9 | reg.add_async_method("t", |_, this: &String, ()| async {
|
||||
| ___________________________________----------------------_^
|
||||
| | | |
|
||||
| | | return type of closure `{async block@$DIR/tests/compile/async_any_userdata_method.rs:9:58: 9:63}` contains a lifetime `'2`
|
||||
9 | reg.add_async_method("t", |_, this, ()| async {
|
||||
| ^^^^^ may outlive borrowed value `this`
|
||||
10 | s = &*this;
|
||||
| ---- `this` is borrowed here
|
||||
|
|
||||
note: async block is returned here
|
||||
--> tests/compile/async_any_userdata_method.rs:9:49
|
||||
|
|
||||
9 | reg.add_async_method("t", |_, this, ()| async {
|
||||
| _________________________________________________^
|
||||
10 | | s = &*this;
|
||||
11 | | Ok(())
|
||||
12 | | });
|
||||
| |_________^
|
||||
help: to force the async block to take ownership of `this` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
9 | reg.add_async_method("t", |_, this, ()| async move {
|
||||
| ++++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> tests/compile/async_any_userdata_method.rs:9:49
|
||||
|
|
||||
9 | reg.add_async_method("t", |_, this, ()| async {
|
||||
| ___________________________________-------------_^
|
||||
| | | |
|
||||
| | | return type of closure `{async block@$DIR/tests/compile/async_any_userdata_method.rs:9:49: 9:54}` contains a lifetime `'2`
|
||||
| | lifetime `'1` represents this closure's body
|
||||
10 | | s = this;
|
||||
10 | | s = &*this;
|
||||
11 | | Ok(())
|
||||
12 | | });
|
||||
| |_________^ returning this value requires that `'1` must outlive `'2`
|
||||
@@ -28,53 +50,31 @@ error[E0597]: `s` does not live long enough
|
||||
| - binding `s` declared here
|
||||
8 | let mut s = &s;
|
||||
| ^^ borrowed value does not live long enough
|
||||
9 | / reg.add_async_method("t", |_, this: &String, ()| async {
|
||||
10 | | s = this;
|
||||
9 | / reg.add_async_method("t", |_, this, ()| async {
|
||||
10 | | s = &*this;
|
||||
11 | | Ok(())
|
||||
12 | | });
|
||||
| |__________- argument requires that `s` is borrowed for `'static`
|
||||
13 | }).unwrap();
|
||||
13 | })
|
||||
| - `s` dropped here while still borrowed
|
||||
|
||||
error[E0521]: borrowed data escapes outside of closure
|
||||
--> tests/compile/async_any_userdata_method.rs:9:9
|
||||
|
|
||||
6 | lua.register_userdata_type::<String>(|reg| {
|
||||
| ---
|
||||
| |
|
||||
| `reg` is a reference that is only valid in the closure body
|
||||
| has type `&mut LuaUserDataRegistry<'1, std::string::String>`
|
||||
...
|
||||
9 | / reg.add_async_method("t", |_, this: &String, ()| async {
|
||||
10 | | s = this;
|
||||
11 | | Ok(())
|
||||
12 | | });
|
||||
| | ^
|
||||
| | |
|
||||
| |__________`reg` escapes the closure body here
|
||||
| argument requires that `'1` must outlive `'static`
|
||||
|
|
||||
= note: requirement occurs because of a mutable reference to `LuaUserDataRegistry<'_, std::string::String>`
|
||||
= note: mutable references are invariant over their type parameter
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
|
||||
error[E0373]: closure may outlive the current function, but it borrows `s`, which is owned by the current function
|
||||
--> tests/compile/async_any_userdata_method.rs:9:35
|
||||
|
|
||||
9 | reg.add_async_method("t", |_, this: &String, ()| async {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ may outlive borrowed value `s`
|
||||
10 | s = this;
|
||||
9 | reg.add_async_method("t", |_, this, ()| async {
|
||||
| ^^^^^^^^^^^^^ may outlive borrowed value `s`
|
||||
10 | s = &*this;
|
||||
| - `s` is borrowed here
|
||||
|
|
||||
note: function requires argument type to outlive `'static`
|
||||
--> tests/compile/async_any_userdata_method.rs:9:9
|
||||
|
|
||||
9 | / reg.add_async_method("t", |_, this: &String, ()| async {
|
||||
10 | | s = this;
|
||||
9 | / reg.add_async_method("t", |_, this, ()| async {
|
||||
10 | | s = &*this;
|
||||
11 | | Ok(())
|
||||
12 | | });
|
||||
| |__________^
|
||||
help: to force the closure to take ownership of `s` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
9 | reg.add_async_method("t", move |_, this: &String, ()| async {
|
||||
9 | reg.add_async_method("t", move |_, this, ()| async {
|
||||
| ++++
|
||||
|
||||
@@ -4,8 +4,8 @@ fn main() {
|
||||
#[derive(Clone)]
|
||||
struct MyUserData<'a>(&'a i64);
|
||||
|
||||
impl<'a> UserData for MyUserData<'a> {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
impl UserData for MyUserData<'_> {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_async_method("print", |_, data, ()| async move {
|
||||
println!("{}", data.0);
|
||||
Ok(())
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
error: lifetime may not live long enough
|
||||
--> tests/compile/async_nonstatic_userdata.rs:9:13
|
||||
|
|
||||
7 | impl<'a> UserData for MyUserData<'a> {
|
||||
| -- lifetime `'a` defined here
|
||||
8 | fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
7 | impl UserData for MyUserData<'_> {
|
||||
| -- lifetime `'1` appears in the `impl`'s self type
|
||||
8 | fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
9 | / methods.add_async_method("print", |_, data, ()| async move {
|
||||
10 | | println!("{}", data.0);
|
||||
11 | | Ok(())
|
||||
12 | | });
|
||||
| |______________^ requires that `'a` must outlive `'static`
|
||||
| |______________^ requires that `'1` must outlive `'static`
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
use mlua::{UserData, UserDataMethods};
|
||||
|
||||
struct MyUserData;
|
||||
|
||||
impl UserData for MyUserData {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_async_method("method", |_, this: &'static Self, ()| async {
|
||||
Ok(())
|
||||
});
|
||||
// ^ lifetime may not live long enough
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -1,17 +0,0 @@
|
||||
warning: unused variable: `this`
|
||||
--> tests/compile/async_userdata_method.rs:7:48
|
||||
|
|
||||
7 | methods.add_async_method("method", |_, this: &'static Self, ()| async {
|
||||
| ^^^^ help: if this is intentional, prefix it with an underscore: `_this`
|
||||
|
|
||||
= note: `#[warn(unused_variables)]` on by default
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> tests/compile/async_userdata_method.rs:7:9
|
||||
|
|
||||
6 | fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
| ---- lifetime `'lua` defined here
|
||||
7 | / methods.add_async_method("method", |_, this: &'static Self, ()| async {
|
||||
8 | | Ok(())
|
||||
9 | | });
|
||||
| |__________^ argument requires that `'lua` must outlive `'static`
|
||||
@@ -6,7 +6,5 @@ fn main() {
|
||||
let test = Test(0);
|
||||
|
||||
let lua = Lua::new();
|
||||
let _ = lua.create_function(|_, ()| -> Result<i32> {
|
||||
Ok(test.0)
|
||||
});
|
||||
let _ = lua.create_function(|_, ()| -> Result<i32> { Ok(test.0) });
|
||||
}
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
error[E0373]: closure may outlive the current function, but it borrows `test.0`, which is owned by the current function
|
||||
--> tests/compile/function_borrow.rs:9:33
|
||||
|
|
||||
9 | let _ = lua.create_function(|_, ()| -> Result<i32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ may outlive borrowed value `test.0`
|
||||
10 | Ok(test.0)
|
||||
| ------ `test.0` is borrowed here
|
||||
|
|
||||
--> tests/compile/function_borrow.rs:9:33
|
||||
|
|
||||
9 | let _ = lua.create_function(|_, ()| -> Result<i32> { Ok(test.0) });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ ------ `test.0` is borrowed here
|
||||
| |
|
||||
| may outlive borrowed value `test.0`
|
||||
|
|
||||
note: function requires argument type to outlive `'static`
|
||||
--> tests/compile/function_borrow.rs:9:13
|
||||
|
|
||||
9 | let _ = lua.create_function(|_, ()| -> Result<i32> {
|
||||
| _____________^
|
||||
10 | | Ok(test.0)
|
||||
11 | | });
|
||||
| |______^
|
||||
--> tests/compile/function_borrow.rs:9:13
|
||||
|
|
||||
9 | let _ = lua.create_function(|_, ()| -> Result<i32> { Ok(test.0) });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: to force the closure to take ownership of `test.0` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
9 | let _ = lua.create_function(move |_, ()| -> Result<i32> {
|
||||
| ++++
|
||||
|
|
||||
9 | let _ = lua.create_function(move |_, ()| -> Result<i32> { Ok(test.0) });
|
||||
| ++++
|
||||
|
||||
@@ -1,32 +1,36 @@
|
||||
error[E0277]: the type `UnsafeCell<*mut lua_State>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
error[E0277]: the type `UnsafeCell<mlua::state::raw::RawLua>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/lua_norefunwindsafe.rs:7:18
|
||||
|
|
||||
7 | catch_unwind(|| lua.create_table().unwrap());
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<*mut lua_State>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<mlua::state::raw::RawLua>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: within `mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<*mut lua_State>`, which is required by `{closure@$DIR/tests/compile/lua_norefunwindsafe.rs:7:18: 7:20}: UnwindSafe`
|
||||
note: required because it appears within the type `Cell<*mut lua_State>`
|
||||
--> $RUST/core/src/cell.rs
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::state::raw::RawLua>`, which is required by `{closure@$DIR/tests/compile/lua_norefunwindsafe.rs:7:18: 7:20}: UnwindSafe`
|
||||
note: required because it appears within the type `lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>`
|
||||
--> $CARGO/lock_api-0.4.12/src/remutex.rs
|
||||
|
|
||||
| pub struct Cell<T: ?Sized> {
|
||||
| ^^^^
|
||||
note: required because it appears within the type `mlua::state::raw::RawLua`
|
||||
--> src/state/raw.rs
|
||||
| pub struct ReentrantMutex<R, G, T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
|
|
||||
| pub struct RawLua {
|
||||
| ^^^^^^
|
||||
note: required because it appears within the type `mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>`
|
||||
--> src/types/sync.rs
|
||||
| struct ArcInner<T: ?Sized> {
|
||||
| ^^^^^^^^
|
||||
note: required because it appears within the type `PhantomData<alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>>`
|
||||
--> $RUST/core/src/marker.rs
|
||||
|
|
||||
| pub(crate) struct ReentrantMutex<T>(T);
|
||||
| ^^^^^^^^^^^^^^
|
||||
= note: required for `Rc<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>` to implement `RefUnwindSafe`
|
||||
| pub struct PhantomData<T: ?Sized>;
|
||||
| ^^^^^^^^^^^
|
||||
note: required because it appears within the type `Arc<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
|
|
||||
| pub struct Arc<
|
||||
| ^^^
|
||||
note: required because it appears within the type `Lua`
|
||||
--> src/state.rs
|
||||
|
|
||||
| pub struct Lua(XRc<ReentrantMutex<RawLua>>);
|
||||
| pub struct Lua {
|
||||
| ^^^
|
||||
= note: required for `&Lua` to implement `UnwindSafe`
|
||||
note: required because it's used within this closure
|
||||
@@ -40,31 +44,49 @@ note: required by a bound in `std::panic::catch_unwind`
|
||||
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
| ^^^^^^^^^^ required by this bound in `catch_unwind`
|
||||
|
||||
error[E0277]: the type `UnsafeCell<mlua::state::extra::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
error[E0277]: the type `UnsafeCell<usize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/lua_norefunwindsafe.rs:7:18
|
||||
|
|
||||
7 | catch_unwind(|| lua.create_table().unwrap());
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<mlua::state::extra::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<usize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::state::extra::ExtraData>`, which is required by `{closure@$DIR/tests/compile/lua_norefunwindsafe.rs:7:18: 7:20}: UnwindSafe`
|
||||
= note: required for `Rc<UnsafeCell<mlua::state::extra::ExtraData>>` to implement `RefUnwindSafe`
|
||||
note: required because it appears within the type `mlua::state::raw::RawLua`
|
||||
--> src/state/raw.rs
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<usize>`, which is required by `{closure@$DIR/tests/compile/lua_norefunwindsafe.rs:7:18: 7:20}: UnwindSafe`
|
||||
note: required because it appears within the type `Cell<usize>`
|
||||
--> $RUST/core/src/cell.rs
|
||||
|
|
||||
| pub struct RawLua {
|
||||
| ^^^^^^
|
||||
note: required because it appears within the type `mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>`
|
||||
--> src/types/sync.rs
|
||||
| pub struct Cell<T: ?Sized> {
|
||||
| ^^^^
|
||||
note: required because it appears within the type `lock_api::remutex::RawReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId>`
|
||||
--> $CARGO/lock_api-0.4.12/src/remutex.rs
|
||||
|
|
||||
| pub(crate) struct ReentrantMutex<T>(T);
|
||||
| ^^^^^^^^^^^^^^
|
||||
= note: required for `Rc<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>` to implement `RefUnwindSafe`
|
||||
| pub struct RawReentrantMutex<R, G> {
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>`
|
||||
--> $CARGO/lock_api-0.4.12/src/remutex.rs
|
||||
|
|
||||
| pub struct ReentrantMutex<R, G, T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
|
|
||||
| struct ArcInner<T: ?Sized> {
|
||||
| ^^^^^^^^
|
||||
note: required because it appears within the type `PhantomData<alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>>`
|
||||
--> $RUST/core/src/marker.rs
|
||||
|
|
||||
| pub struct PhantomData<T: ?Sized>;
|
||||
| ^^^^^^^^^^^
|
||||
note: required because it appears within the type `Arc<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
|
|
||||
| pub struct Arc<
|
||||
| ^^^
|
||||
note: required because it appears within the type `Lua`
|
||||
--> src/state.rs
|
||||
|
|
||||
| pub struct Lua(XRc<ReentrantMutex<RawLua>>);
|
||||
| pub struct Lua {
|
||||
| ^^^
|
||||
= note: required for `&Lua` to implement `UnwindSafe`
|
||||
note: required because it's used within this closure
|
||||
|
||||
@@ -8,10 +8,8 @@ fn main() -> Result<()> {
|
||||
|
||||
let data = Rc::new(Cell::new(0));
|
||||
|
||||
lua.create_function(move |_, ()| {
|
||||
Ok(data.get())
|
||||
})?
|
||||
.call::<i32>(())?;
|
||||
lua.create_function(move |_, ()| Ok(data.get()))?
|
||||
.call::<i32>(())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,28 +1,25 @@
|
||||
error[E0277]: `Rc<Cell<i32>>` cannot be sent between threads safely
|
||||
--> tests/compile/non_send.rs:11:25
|
||||
|
|
||||
11 | lua.create_function(move |_, ()| {
|
||||
| --------------- ^-----------
|
||||
| | |
|
||||
| _________|_______________within this `{closure@$DIR/tests/compile/non_send.rs:11:25: 11:37}`
|
||||
| | |
|
||||
| | required by a bound introduced by this call
|
||||
12 | | Ok(data.get())
|
||||
13 | | })?
|
||||
| |_____^ `Rc<Cell<i32>>` cannot be sent between threads safely
|
||||
11 | lua.create_function(move |_, ()| Ok(data.get()))?
|
||||
| --------------- ------------^^^^^^^^^^^^^^^
|
||||
| | |
|
||||
| | `Rc<Cell<i32>>` cannot be sent between threads safely
|
||||
| | within this `{closure@$DIR/tests/compile/non_send.rs:11:25: 11:37}`
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: within `{closure@$DIR/tests/compile/non_send.rs:11:25: 11:37}`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
|
||||
= help: within `{closure@$DIR/tests/compile/non_send.rs:11:25: 11:37}`, the trait `Send` is not implemented for `Rc<Cell<i32>>`, which is required by `{closure@$DIR/tests/compile/non_send.rs:11:25: 11:37}: MaybeSend`
|
||||
note: required because it's used within this closure
|
||||
--> tests/compile/non_send.rs:11:25
|
||||
|
|
||||
11 | lua.create_function(move |_, ()| {
|
||||
11 | lua.create_function(move |_, ()| Ok(data.get()))?
|
||||
| ^^^^^^^^^^^^
|
||||
= note: required for `{closure@$DIR/tests/compile/non_send.rs:11:25: 11:37}` to implement `mlua::types::MaybeSend`
|
||||
= note: required for `{closure@$DIR/tests/compile/non_send.rs:11:25: 11:37}` to implement `MaybeSend`
|
||||
note: required by a bound in `Lua::create_function`
|
||||
--> src/lua.rs
|
||||
--> src/state.rs
|
||||
|
|
||||
| pub fn create_function<'lua, A, R, F>(&'lua self, func: F) -> Result<Function<'lua>>
|
||||
| pub fn create_function<F, A, R>(&self, func: F) -> Result<Function>
|
||||
| --------------- required by a bound in this associated function
|
||||
...
|
||||
| F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static,
|
||||
| ^^^^^^^^^ required by this bound in `Lua::create_function`
|
||||
| where
|
||||
| F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
|
||||
| ^^^^^^^^^ required by this bound in `Lua::create_function`
|
||||
|
||||
@@ -1,3 +1,54 @@
|
||||
error[E0277]: the type `UnsafeCell<mlua::state::raw::RawLua>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:18
|
||||
|
|
||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<mlua::state::raw::RawLua>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: within `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::state::raw::RawLua>`, which is required by `{closure@$DIR/tests/compile/ref_nounwindsafe.rs:8:18: 8:25}: UnwindSafe`
|
||||
note: required because it appears within the type `lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>`
|
||||
--> $CARGO/lock_api-0.4.12/src/remutex.rs
|
||||
|
|
||||
| pub struct ReentrantMutex<R, G, T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
|
|
||||
| struct ArcInner<T: ?Sized> {
|
||||
| ^^^^^^^^
|
||||
= note: required for `NonNull<alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>>` to implement `UnwindSafe`
|
||||
note: required because it appears within the type `std::sync::Weak<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
|
|
||||
| pub struct Weak<
|
||||
| ^^^^
|
||||
note: required because it appears within the type `mlua::state::WeakLua`
|
||||
--> src/state.rs
|
||||
|
|
||||
| pub(crate) struct WeakLua(XWeak<ReentrantMutex<RawLua>>);
|
||||
| ^^^^^^^
|
||||
note: required because it appears within the type `mlua::types::ValueRef`
|
||||
--> src/types.rs
|
||||
|
|
||||
| pub(crate) struct ValueRef {
|
||||
| ^^^^^^^^
|
||||
note: required because it appears within the type `LuaTable`
|
||||
--> src/table.rs
|
||||
|
|
||||
| pub struct Table(pub(crate) ValueRef);
|
||||
| ^^^^^
|
||||
note: required because it's used within this closure
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:18
|
||||
|
|
||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
||||
| ^^^^^^^
|
||||
note: required by a bound in `std::panic::catch_unwind`
|
||||
--> $RUST/std/src/panic.rs
|
||||
|
|
||||
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
| ^^^^^^^^^^ required by this bound in `catch_unwind`
|
||||
|
||||
error[E0277]: the type `UnsafeCell<usize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:18
|
||||
|
|
||||
@@ -6,138 +57,30 @@ error[E0277]: the type `UnsafeCell<usize>` may contain interior mutability and a
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: within `rc::RcBox<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<usize>`, which is required by `{closure@$DIR/tests/compile/ref_nounwindsafe.rs:8:18: 8:25}: UnwindSafe`
|
||||
= help: within `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<usize>`, which is required by `{closure@$DIR/tests/compile/ref_nounwindsafe.rs:8:18: 8:25}: UnwindSafe`
|
||||
note: required because it appears within the type `Cell<usize>`
|
||||
--> $RUST/core/src/cell.rs
|
||||
|
|
||||
| pub struct Cell<T: ?Sized> {
|
||||
| ^^^^
|
||||
note: required because it appears within the type `rc::RcBox<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/rc.rs
|
||||
note: required because it appears within the type `lock_api::remutex::RawReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId>`
|
||||
--> $CARGO/lock_api-0.4.12/src/remutex.rs
|
||||
|
|
||||
| struct RcBox<T: ?Sized> {
|
||||
| ^^^^^
|
||||
= note: required for `NonNull<rc::RcBox<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>>` to implement `UnwindSafe`
|
||||
note: required because it appears within the type `std::rc::Weak<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/rc.rs
|
||||
|
|
||||
| pub struct Weak<
|
||||
| ^^^^
|
||||
note: required because it appears within the type `mlua::state::WeakLua`
|
||||
--> src/state.rs
|
||||
|
|
||||
| pub(crate) struct WeakLua(XWeak<ReentrantMutex<RawLua>>);
|
||||
| ^^^^^^^
|
||||
note: required because it appears within the type `mlua::types::ValueRef`
|
||||
--> src/types.rs
|
||||
|
|
||||
| pub(crate) struct ValueRef {
|
||||
| ^^^^^^^^
|
||||
note: required because it appears within the type `LuaTable`
|
||||
--> src/table.rs
|
||||
|
|
||||
| pub struct Table(pub(crate) ValueRef);
|
||||
| ^^^^^
|
||||
note: required because it's used within this closure
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:18
|
||||
|
|
||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
||||
| ^^^^^^^
|
||||
note: required by a bound in `std::panic::catch_unwind`
|
||||
--> $RUST/std/src/panic.rs
|
||||
|
|
||||
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
| ^^^^^^^^^^ required by this bound in `catch_unwind`
|
||||
|
||||
error[E0277]: the type `UnsafeCell<*mut lua_State>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:18
|
||||
|
|
||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<*mut lua_State>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: within `rc::RcBox<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<*mut lua_State>`, which is required by `{closure@$DIR/tests/compile/ref_nounwindsafe.rs:8:18: 8:25}: UnwindSafe`
|
||||
note: required because it appears within the type `Cell<*mut lua_State>`
|
||||
--> $RUST/core/src/cell.rs
|
||||
|
|
||||
| pub struct Cell<T: ?Sized> {
|
||||
| ^^^^
|
||||
note: required because it appears within the type `mlua::state::raw::RawLua`
|
||||
--> src/state/raw.rs
|
||||
|
|
||||
| pub struct RawLua {
|
||||
| ^^^^^^
|
||||
note: required because it appears within the type `mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>`
|
||||
--> src/types/sync.rs
|
||||
|
|
||||
| pub(crate) struct ReentrantMutex<T>(T);
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `rc::RcBox<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/rc.rs
|
||||
|
|
||||
| struct RcBox<T: ?Sized> {
|
||||
| ^^^^^
|
||||
= note: required for `NonNull<rc::RcBox<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>>` to implement `UnwindSafe`
|
||||
note: required because it appears within the type `std::rc::Weak<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/rc.rs
|
||||
|
|
||||
| pub struct Weak<
|
||||
| ^^^^
|
||||
note: required because it appears within the type `mlua::state::WeakLua`
|
||||
--> src/state.rs
|
||||
|
|
||||
| pub(crate) struct WeakLua(XWeak<ReentrantMutex<RawLua>>);
|
||||
| ^^^^^^^
|
||||
note: required because it appears within the type `mlua::types::ValueRef`
|
||||
--> src/types.rs
|
||||
|
|
||||
| pub(crate) struct ValueRef {
|
||||
| ^^^^^^^^
|
||||
note: required because it appears within the type `LuaTable`
|
||||
--> src/table.rs
|
||||
|
|
||||
| pub struct Table(pub(crate) ValueRef);
|
||||
| ^^^^^
|
||||
note: required because it's used within this closure
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:18
|
||||
|
|
||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
||||
| ^^^^^^^
|
||||
note: required by a bound in `std::panic::catch_unwind`
|
||||
--> $RUST/std/src/panic.rs
|
||||
|
|
||||
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
| ^^^^^^^^^^ required by this bound in `catch_unwind`
|
||||
|
||||
error[E0277]: the type `UnsafeCell<mlua::state::extra::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:18
|
||||
|
|
||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
||||
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<mlua::state::extra::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::state::extra::ExtraData>`, which is required by `{closure@$DIR/tests/compile/ref_nounwindsafe.rs:8:18: 8:25}: UnwindSafe`
|
||||
= note: required for `Rc<UnsafeCell<mlua::state::extra::ExtraData>>` to implement `RefUnwindSafe`
|
||||
note: required because it appears within the type `mlua::state::raw::RawLua`
|
||||
--> src/state/raw.rs
|
||||
|
|
||||
| pub struct RawLua {
|
||||
| ^^^^^^
|
||||
note: required because it appears within the type `mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>`
|
||||
--> src/types/sync.rs
|
||||
|
|
||||
| pub(crate) struct ReentrantMutex<T>(T);
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `rc::RcBox<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/rc.rs
|
||||
|
|
||||
| struct RcBox<T: ?Sized> {
|
||||
| ^^^^^
|
||||
= note: required for `NonNull<rc::RcBox<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>>` to implement `UnwindSafe`
|
||||
note: required because it appears within the type `std::rc::Weak<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/rc.rs
|
||||
| pub struct RawReentrantMutex<R, G> {
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>`
|
||||
--> $CARGO/lock_api-0.4.12/src/remutex.rs
|
||||
|
|
||||
| pub struct ReentrantMutex<R, G, T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
|
|
||||
| struct ArcInner<T: ?Sized> {
|
||||
| ^^^^^^^^
|
||||
= note: required for `NonNull<alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>>` to implement `UnwindSafe`
|
||||
note: required because it appears within the type `std::sync::Weak<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
|
||||
--> $RUST/alloc/src/sync.rs
|
||||
|
|
||||
| pub struct Weak<
|
||||
| ^^^^
|
||||
|
||||
@@ -4,14 +4,10 @@ fn main() {
|
||||
let lua = Lua::new();
|
||||
lua.scope(|scope| {
|
||||
let mut inner: Option<Table> = None;
|
||||
let f = scope
|
||||
.create_function_mut(move |_, t: Table| {
|
||||
if let Some(old) = inner.take() {
|
||||
// Access old callback `Lua`.
|
||||
}
|
||||
inner = Some(t);
|
||||
Ok(())
|
||||
})?;
|
||||
let f = scope.create_function_mut(|_, t: Table| {
|
||||
inner = Some(t);
|
||||
Ok(())
|
||||
})?;
|
||||
f.call::<()>(lua.create_table()?)?;
|
||||
Ok(())
|
||||
});
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
error[E0599]: no method named `scope` found for struct `Lua` in the current scope
|
||||
--> tests/compile/scope_callback_capture.rs:5:9
|
||||
|
|
||||
5 | lua.scope(|scope| {
|
||||
| ----^^^^^ method not found in `Lua`
|
||||
error[E0373]: closure may outlive the current function, but it borrows `inner`, which is owned by the current function
|
||||
--> tests/compile/scope_callback_capture.rs:7:43
|
||||
|
|
||||
5 | lua.scope(|scope| {
|
||||
| ----- has type `&'1 mut mlua::scope::Scope<'1, '_>`
|
||||
6 | let mut inner: Option<Table> = None;
|
||||
7 | let f = scope.create_function_mut(|_, t: Table| {
|
||||
| ^^^^^^^^^^^^^ may outlive borrowed value `inner`
|
||||
8 | inner = Some(t);
|
||||
| ----- `inner` is borrowed here
|
||||
|
|
||||
note: function requires argument type to outlive `'1`
|
||||
--> tests/compile/scope_callback_capture.rs:7:17
|
||||
|
|
||||
7 | let f = scope.create_function_mut(|_, t: Table| {
|
||||
| _________________^
|
||||
8 | | inner = Some(t);
|
||||
9 | | Ok(())
|
||||
10 | | })?;
|
||||
| |__________^
|
||||
help: to force the closure to take ownership of `inner` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
7 | let f = scope.create_function_mut(move |_, t: Table| {
|
||||
| ++++
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
use mlua::{Lua, Table};
|
||||
|
||||
fn main() {
|
||||
let lua = Lua::new();
|
||||
lua.scope(|scope| {
|
||||
let mut inner: Option<Table> = None;
|
||||
let f = scope
|
||||
.create_function_mut(|_, t: Table| {
|
||||
inner = Some(t);
|
||||
Ok(())
|
||||
})?;
|
||||
f.call::<()>(lua.create_table()?)?;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
error[E0599]: no method named `scope` found for struct `Lua` in the current scope
|
||||
--> tests/compile/scope_callback_inner.rs:5:9
|
||||
|
|
||||
5 | lua.scope(|scope| {
|
||||
| ----^^^^^ method not found in `Lua`
|
||||
@@ -1,15 +0,0 @@
|
||||
use mlua::{Lua, Table};
|
||||
|
||||
fn main() {
|
||||
let lua = Lua::new();
|
||||
let mut outer: Option<Table> = None;
|
||||
lua.scope(|scope| {
|
||||
let f = scope
|
||||
.create_function_mut(|_, t: Table| {
|
||||
outer = Some(t);
|
||||
Ok(())
|
||||
})?;
|
||||
f.call::<()>(lua.create_table()?)?;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
error[E0599]: no method named `scope` found for struct `Lua` in the current scope
|
||||
--> tests/compile/scope_callback_outer.rs:6:9
|
||||
|
|
||||
6 | lua.scope(|scope| {
|
||||
| ----^^^^^ method not found in `Lua`
|
||||
@@ -10,12 +10,11 @@ fn main() {
|
||||
let f = {
|
||||
let mut test = Test { field: 0 };
|
||||
|
||||
scope
|
||||
.create_function_mut(|_, ()| {
|
||||
test.field = 42;
|
||||
//~^ error: `test` does not live long enough
|
||||
Ok(())
|
||||
})?
|
||||
scope.create_function_mut(|_, ()| {
|
||||
test.field = 42;
|
||||
//~^ error: `test` does not live long enough
|
||||
Ok(())
|
||||
})?
|
||||
};
|
||||
|
||||
f.call::<()>(())
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
error[E0599]: no method named `scope` found for struct `Lua` in the current scope
|
||||
--> tests/compile/scope_invariance.rs:9:9
|
||||
|
|
||||
9 | lua.scope(|scope| {
|
||||
| ----^^^^^ method not found in `Lua`
|
||||
error[E0373]: closure may outlive the current function, but it borrows `test.field`, which is owned by the current function
|
||||
--> tests/compile/scope_invariance.rs:13:39
|
||||
|
|
||||
9 | lua.scope(|scope| {
|
||||
| ----- has type `&'1 mut mlua::scope::Scope<'1, '_>`
|
||||
...
|
||||
13 | scope.create_function_mut(|_, ()| {
|
||||
| ^^^^^^^ may outlive borrowed value `test.field`
|
||||
14 | test.field = 42;
|
||||
| ---------- `test.field` is borrowed here
|
||||
|
|
||||
note: function requires argument type to outlive `'1`
|
||||
--> tests/compile/scope_invariance.rs:13:13
|
||||
|
|
||||
13 | / scope.create_function_mut(|_, ()| {
|
||||
14 | | test.field = 42;
|
||||
15 | | //~^ error: `test` does not live long enough
|
||||
16 | | Ok(())
|
||||
17 | | })?
|
||||
| |______________^
|
||||
help: to force the closure to take ownership of `test.field` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
13 | scope.create_function_mut(move |_, ()| {
|
||||
| ++++
|
||||
|
||||
@@ -2,14 +2,14 @@ use mlua::{Lua, UserData};
|
||||
|
||||
fn main() {
|
||||
struct MyUserData<'a>(&'a mut i32);
|
||||
impl<'a> UserData for MyUserData<'a> {}
|
||||
impl UserData for MyUserData<'_> {}
|
||||
|
||||
let mut i = 1;
|
||||
|
||||
let lua = Lua::new();
|
||||
lua.scope(|scope| {
|
||||
let _a = scope.create_nonstatic_userdata(MyUserData(&mut i)).unwrap();
|
||||
let _b = scope.create_nonstatic_userdata(MyUserData(&mut i)).unwrap();
|
||||
let _a = scope.create_userdata(MyUserData(&mut i)).unwrap();
|
||||
let _b = scope.create_userdata(MyUserData(&mut i)).unwrap();
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
error[E0599]: no method named `scope` found for struct `Lua` in the current scope
|
||||
--> tests/compile/scope_mutable_aliasing.rs:10:9
|
||||
error[E0499]: cannot borrow `i` as mutable more than once at a time
|
||||
--> tests/compile/scope_mutable_aliasing.rs:12:51
|
||||
|
|
||||
10 | lua.scope(|scope| {
|
||||
| ----^^^^^ method not found in `Lua`
|
||||
| ----- has type `&mut mlua::scope::Scope<'_, '1>`
|
||||
11 | let _a = scope.create_userdata(MyUserData(&mut i)).unwrap();
|
||||
| -----------------------------------------
|
||||
| | |
|
||||
| | first mutable borrow occurs here
|
||||
| argument requires that `i` is borrowed for `'1`
|
||||
12 | let _b = scope.create_userdata(MyUserData(&mut i)).unwrap();
|
||||
| ^^^^^^ second mutable borrow occurs here
|
||||
|
||||
@@ -3,16 +3,16 @@ use mlua::{Lua, UserData};
|
||||
fn main() {
|
||||
// Should not allow userdata borrow to outlive lifetime of AnyUserData handle
|
||||
struct MyUserData<'a>(&'a i32);
|
||||
impl<'a> UserData for MyUserData<'a> {}
|
||||
impl UserData for MyUserData<'_> {}
|
||||
|
||||
let igood = 1;
|
||||
|
||||
let lua = Lua::new();
|
||||
lua.scope(|scope| {
|
||||
let _ugood = scope.create_nonstatic_userdata(MyUserData(&igood)).unwrap();
|
||||
let _ugood = scope.create_userdata(MyUserData(&igood)).unwrap();
|
||||
let _ubad = {
|
||||
let ibad = 42;
|
||||
scope.create_nonstatic_userdata(MyUserData(&ibad)).unwrap();
|
||||
scope.create_userdata(MyUserData(&ibad)).unwrap();
|
||||
};
|
||||
Ok(())
|
||||
});
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
error[E0599]: no method named `scope` found for struct `Lua` in the current scope
|
||||
--> tests/compile/scope_userdata_borrow.rs:11:9
|
||||
error[E0597]: `ibad` does not live long enough
|
||||
--> tests/compile/scope_userdata_borrow.rs:15:46
|
||||
|
|
||||
11 | lua.scope(|scope| {
|
||||
| ----^^^^^ method not found in `Lua`
|
||||
| ----- has type `&mut mlua::scope::Scope<'_, '1>`
|
||||
...
|
||||
14 | let ibad = 42;
|
||||
| ---- binding `ibad` declared here
|
||||
15 | scope.create_userdata(MyUserData(&ibad)).unwrap();
|
||||
| ---------------------------------^^^^^--
|
||||
| | |
|
||||
| | borrowed value does not live long enough
|
||||
| argument requires that `ibad` is borrowed for `'1`
|
||||
16 | };
|
||||
| - `ibad` dropped here while still borrowed
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
use mlua::{AnyUserData, Lua, Table, UserData, Result};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
let globals = lua.globals();
|
||||
|
||||
// Should not allow userdata borrow to outlive lifetime of AnyUserData handle
|
||||
struct MyUserData;
|
||||
impl UserData for MyUserData {};
|
||||
let _userdata_ref;
|
||||
{
|
||||
let touter = globals.get::<Table>("touter")?;
|
||||
touter.set("userdata", lua.create_userdata(MyUserData)?)?;
|
||||
let userdata = touter.get::<AnyUserData>("userdata")?;
|
||||
_userdata_ref = userdata.borrow::<MyUserData>();
|
||||
//~^ error: `userdata` does not live long enough
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
error[E0597]: `userdata` does not live long enough
|
||||
--> $DIR/userdata_borrow.rs:15:25
|
||||
|
|
||||
15 | _userdata_ref = userdata.borrow::<MyUserData>();
|
||||
| ^^^^^^^^ borrowed value does not live long enough
|
||||
16 | //~^ error: `userdata` does not live long enough
|
||||
17 | }
|
||||
| - `userdata` dropped here while still borrowed
|
||||
18 | Ok(())
|
||||
19 | }
|
||||
| - borrow might be used here, when `_userdata_ref` is dropped and runs the destructor for type `std::result::Result<std::cell::Ref<'_, main::MyUserData>, mlua::error::Error>`
|
||||
|
|
||||
= note: values in a scope are dropped in the opposite order they are defined
|
||||
@@ -1,11 +1,10 @@
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use std::string::String as StdString;
|
||||
use std::sync::Arc;
|
||||
|
||||
use mlua::{
|
||||
AnyUserData, Error, Function, Lua, MetaMethod, Result, String, UserData, UserDataFields,
|
||||
UserDataMethods,
|
||||
AnyUserData, Error, Function, Lua, MetaMethod, ObjectLike, Result, String, UserData, UserDataFields,
|
||||
UserDataMethods, UserDataRegistry,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -14,20 +13,20 @@ fn test_scope_func() -> Result<()> {
|
||||
|
||||
let rc = Rc::new(Cell::new(0));
|
||||
lua.scope(|scope| {
|
||||
let r = rc.clone();
|
||||
let rc2 = rc.clone();
|
||||
let f = scope.create_function(move |_, ()| {
|
||||
r.set(42);
|
||||
rc2.set(42);
|
||||
Ok(())
|
||||
})?;
|
||||
lua.globals().set("bad", f.clone())?;
|
||||
f.call::<_, ()>(())?;
|
||||
lua.globals().set("f", &f)?;
|
||||
f.call::<()>(())?;
|
||||
assert_eq!(Rc::strong_count(&rc), 2);
|
||||
Ok(())
|
||||
})?;
|
||||
assert_eq!(rc.get(), 42);
|
||||
assert_eq!(Rc::strong_count(&rc), 1);
|
||||
|
||||
match lua.globals().get::<_, Function>("bad")?.call::<_, ()>(()) {
|
||||
match lua.globals().get::<Function>("f")?.call::<()>(()) {
|
||||
Err(Error::CallbackError { ref cause, .. }) => match *cause.as_ref() {
|
||||
Error::CallbackDestructed => {}
|
||||
ref err => panic!("wrong error type {:?}", err),
|
||||
@@ -49,7 +48,7 @@ fn test_scope_capture() -> Result<()> {
|
||||
i = 42;
|
||||
Ok(())
|
||||
})?
|
||||
.call::<_, ()>(())
|
||||
.call::<()>(())
|
||||
})?;
|
||||
assert_eq!(i, 42);
|
||||
|
||||
@@ -61,12 +60,8 @@ fn test_scope_outer_lua_access() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let table = lua.create_table()?;
|
||||
lua.scope(|scope| {
|
||||
scope
|
||||
.create_function_mut(|_, ()| table.set("a", "b"))?
|
||||
.call::<_, ()>(())
|
||||
})?;
|
||||
assert_eq!(table.get::<_, String>("a")?, "b");
|
||||
lua.scope(|scope| scope.create_function(|_, ()| table.set("a", "b"))?.call::<()>(()))?;
|
||||
assert_eq!(table.get::<String>("a")?, "b");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -75,11 +70,11 @@ fn test_scope_outer_lua_access() -> Result<()> {
|
||||
fn test_scope_userdata_fields() -> Result<()> {
|
||||
struct MyUserData<'a>(&'a Cell<i64>);
|
||||
|
||||
impl<'a> UserData for MyUserData<'a> {
|
||||
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
fields.add_field("field", "hello");
|
||||
fields.add_field_method_get("val", |_, data| Ok(data.0.get()));
|
||||
fields.add_field_method_set("val", |_, data, val| {
|
||||
impl UserData for MyUserData<'_> {
|
||||
fn register(reg: &mut UserDataRegistry<Self>) {
|
||||
reg.add_field("field", "hello");
|
||||
reg.add_field_method_get("val", |_, data| Ok(data.0.get()));
|
||||
reg.add_field_method_set("val", |_, data, val| {
|
||||
data.0.set(val);
|
||||
Ok(())
|
||||
});
|
||||
@@ -101,7 +96,7 @@ fn test_scope_userdata_fields() -> Result<()> {
|
||||
)
|
||||
.eval()?;
|
||||
|
||||
lua.scope(|scope| f.call::<_, ()>(scope.create_nonstatic_userdata(MyUserData(&i))?))?;
|
||||
lua.scope(|scope| f.call::<()>(scope.create_userdata(MyUserData(&i))?))?;
|
||||
|
||||
assert_eq!(i.get(), 44);
|
||||
|
||||
@@ -112,14 +107,14 @@ fn test_scope_userdata_fields() -> Result<()> {
|
||||
fn test_scope_userdata_methods() -> Result<()> {
|
||||
struct MyUserData<'a>(&'a Cell<i64>);
|
||||
|
||||
impl<'a> UserData for MyUserData<'a> {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_method("inc", |_, data, ()| {
|
||||
impl UserData for MyUserData<'_> {
|
||||
fn register(reg: &mut UserDataRegistry<Self>) {
|
||||
reg.add_method("inc", |_, data, ()| {
|
||||
data.0.set(data.0.get() + 1);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_method("dec", |_, data, ()| {
|
||||
reg.add_method("dec", |_, data, ()| {
|
||||
data.0.set(data.0.get() - 1);
|
||||
Ok(())
|
||||
});
|
||||
@@ -142,7 +137,7 @@ fn test_scope_userdata_methods() -> Result<()> {
|
||||
)
|
||||
.eval()?;
|
||||
|
||||
lua.scope(|scope| f.call::<_, ()>(scope.create_nonstatic_userdata(MyUserData(&i))?))?;
|
||||
lua.scope(|scope| f.call::<()>(scope.create_userdata(MyUserData(&i))?))?;
|
||||
|
||||
assert_eq!(i.get(), 44);
|
||||
|
||||
@@ -150,19 +145,19 @@ fn test_scope_userdata_methods() -> Result<()> {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scope_userdata_functions() -> Result<()> {
|
||||
fn test_scope_userdata_ops() -> Result<()> {
|
||||
struct MyUserData<'a>(&'a i64);
|
||||
|
||||
impl<'a> UserData for MyUserData<'a> {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_meta_method(MetaMethod::Add, |lua, this, ()| {
|
||||
impl UserData for MyUserData<'_> {
|
||||
fn register(reg: &mut UserDataRegistry<Self>) {
|
||||
reg.add_meta_method(MetaMethod::Add, |lua, this, ()| {
|
||||
let globals = lua.globals();
|
||||
globals.set("i", globals.get::<_, i64>("i")? + this.0)?;
|
||||
globals.set("i", globals.get::<i64>("i")? + this.0)?;
|
||||
Ok(())
|
||||
});
|
||||
methods.add_meta_method(MetaMethod::Sub, |lua, this, ()| {
|
||||
reg.add_meta_method(MetaMethod::Sub, |lua, this, ()| {
|
||||
let globals = lua.globals();
|
||||
globals.set("i", globals.get::<_, i64>("i")? + this.0)?;
|
||||
globals.set("i", globals.get::<i64>("i")? + this.0)?;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
@@ -184,9 +179,34 @@ fn test_scope_userdata_functions() -> Result<()> {
|
||||
)
|
||||
.eval::<Function>()?;
|
||||
|
||||
lua.scope(|scope| f.call::<_, ()>(scope.create_nonstatic_userdata(MyUserData(&dummy))?))?;
|
||||
lua.scope(|scope| f.call::<()>(scope.create_userdata(MyUserData(&dummy))?))?;
|
||||
|
||||
assert_eq!(lua.globals().get::<_, i64>("i")?, 3);
|
||||
assert_eq!(lua.globals().get::<i64>("i")?, 3);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scope_userdata_values() -> Result<()> {
|
||||
struct MyUserData<'a>(&'a i64);
|
||||
|
||||
impl UserData for MyUserData<'_> {
|
||||
fn register(registry: &mut UserDataRegistry<Self>) {
|
||||
registry.add_method("get", |_, data, ()| Ok(*data.0));
|
||||
}
|
||||
}
|
||||
|
||||
let lua = Lua::new();
|
||||
|
||||
let i = 42;
|
||||
let data = MyUserData(&i);
|
||||
lua.scope(|scope| {
|
||||
let ud = scope.create_userdata(data)?;
|
||||
assert_eq!(ud.call_method::<i64>("get", &ud)?, 42);
|
||||
ud.set_user_value("user_value")?;
|
||||
assert_eq!(ud.user_value::<String>()?, "user_value");
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -196,8 +216,8 @@ fn test_scope_userdata_mismatch() -> Result<()> {
|
||||
struct MyUserData<'a>(&'a Cell<i64>);
|
||||
|
||||
impl<'a> UserData for MyUserData<'a> {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_method("inc", |_, data, ()| {
|
||||
fn register(reg: &mut UserDataRegistry<Self>) {
|
||||
reg.add_method("inc", |_, data, ()| {
|
||||
data.0.set(data.0.get() + 1);
|
||||
Ok(())
|
||||
});
|
||||
@@ -208,13 +228,7 @@ fn test_scope_userdata_mismatch() -> Result<()> {
|
||||
|
||||
lua.load(
|
||||
r#"
|
||||
function okay(a, b)
|
||||
a.inc(a)
|
||||
b.inc(b)
|
||||
end
|
||||
function bad(a, b)
|
||||
a.inc(b)
|
||||
end
|
||||
function inc(a, b) a.inc(b) end
|
||||
"#,
|
||||
)
|
||||
.exec()?;
|
||||
@@ -222,29 +236,22 @@ fn test_scope_userdata_mismatch() -> Result<()> {
|
||||
let a = Cell::new(1);
|
||||
let b = Cell::new(1);
|
||||
|
||||
let okay: Function = lua.globals().get("okay")?;
|
||||
let bad: Function = lua.globals().get("bad")?;
|
||||
|
||||
let inc: Function = lua.globals().get("inc")?;
|
||||
lua.scope(|scope| {
|
||||
let au = scope.create_nonstatic_userdata(MyUserData(&a))?;
|
||||
let bu = scope.create_nonstatic_userdata(MyUserData(&b))?;
|
||||
assert!(okay.call::<_, ()>((au.clone(), bu.clone())).is_ok());
|
||||
match bad.call::<_, ()>((au, bu)) {
|
||||
let au = scope.create_userdata(MyUserData(&a))?;
|
||||
let bu = scope.create_userdata(MyUserData(&b))?;
|
||||
assert!(inc.call::<()>((&au, &au)).is_ok());
|
||||
match inc.call::<()>((&au, &bu)) {
|
||||
Err(Error::CallbackError { ref cause, .. }) => match cause.as_ref() {
|
||||
Error::BadArgument {
|
||||
to,
|
||||
pos,
|
||||
name,
|
||||
cause,
|
||||
} => {
|
||||
Error::BadArgument { to, pos, name, cause } => {
|
||||
assert_eq!(to.as_deref(), Some("MyUserData.inc"));
|
||||
assert_eq!(*pos, 1);
|
||||
assert_eq!(name.as_deref(), Some("self"));
|
||||
assert!(matches!(*cause.as_ref(), Error::UserDataTypeMismatch));
|
||||
}
|
||||
other => panic!("wrong error type {:?}", other),
|
||||
other => panic!("wrong error type {other:?}"),
|
||||
},
|
||||
Err(other) => panic!("wrong error type {:?}", other),
|
||||
Err(other) => panic!("wrong error type {other:?}"),
|
||||
Ok(_) => panic!("incorrectly returned Ok"),
|
||||
}
|
||||
Ok(())
|
||||
@@ -257,114 +264,46 @@ fn test_scope_userdata_mismatch() -> Result<()> {
|
||||
fn test_scope_userdata_drop() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
struct MyUserData(#[allow(unused)] Rc<()>);
|
||||
struct MyUserData<'a>(&'a Cell<i64>, #[allow(unused)] Rc<()>);
|
||||
|
||||
impl UserData for MyUserData {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_method("method", |_, _, ()| Ok(()));
|
||||
}
|
||||
}
|
||||
|
||||
struct MyUserDataArc(#[allow(unused)] Arc<()>);
|
||||
|
||||
impl UserData for MyUserDataArc {}
|
||||
|
||||
let rc = Rc::new(());
|
||||
let arc = Arc::new(());
|
||||
lua.scope(|scope| {
|
||||
let ud = scope.create_userdata(MyUserData(rc.clone()))?;
|
||||
ud.set_user_value(MyUserDataArc(arc.clone()))?;
|
||||
lua.globals().set("ud", ud)?;
|
||||
assert_eq!(Rc::strong_count(&rc), 2);
|
||||
assert_eq!(Arc::strong_count(&arc), 2);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
lua.gc_collect()?;
|
||||
assert_eq!(Rc::strong_count(&rc), 1);
|
||||
assert_eq!(Arc::strong_count(&arc), 1);
|
||||
|
||||
match lua.load("ud:method()").exec() {
|
||||
Err(Error::CallbackError { ref cause, .. }) => match cause.as_ref() {
|
||||
Error::CallbackDestructed => {}
|
||||
err => panic!("expected CallbackDestructed, got {:?}", err),
|
||||
},
|
||||
r => panic!("improper return for destructed userdata: {:?}", r),
|
||||
};
|
||||
|
||||
let ud = lua.globals().get::<_, AnyUserData>("ud")?;
|
||||
match ud.borrow::<MyUserData>() {
|
||||
Ok(_) => panic!("succesfull borrow for destructed userdata"),
|
||||
Err(Error::UserDataDestructed) => {}
|
||||
Err(err) => panic!("improper borrow error for destructed userdata: {:?}", err),
|
||||
}
|
||||
|
||||
match ud.get_metatable() {
|
||||
Ok(_) => panic!("successful metatable retrieval of destructed userdata"),
|
||||
Err(Error::UserDataDestructed) => {}
|
||||
Err(err) => panic!(
|
||||
"improper metatable error for destructed userdata: {:?}",
|
||||
err
|
||||
),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scope_nonstatic_userdata_drop() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
struct MyUserData<'a>(&'a Cell<i64>, #[allow(unused)] Arc<()>);
|
||||
|
||||
impl<'a> UserData for MyUserData<'a> {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_method("inc", |_, data, ()| {
|
||||
impl UserData for MyUserData<'_> {
|
||||
fn register(reg: &mut UserDataRegistry<Self>) {
|
||||
reg.add_method("inc", |_, data, ()| {
|
||||
data.0.set(data.0.get() + 1);
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
struct MyUserDataArc(#[allow(unused)] Arc<()>);
|
||||
|
||||
impl UserData for MyUserDataArc {}
|
||||
|
||||
let i = Cell::new(1);
|
||||
let arc = Arc::new(());
|
||||
let (i, rc) = (Cell::new(1), Rc::new(()));
|
||||
lua.scope(|scope| {
|
||||
let ud = scope.create_nonstatic_userdata(MyUserData(&i, arc.clone()))?;
|
||||
ud.set_user_value(MyUserDataArc(arc.clone()))?;
|
||||
let ud = scope.create_userdata(MyUserData(&i, rc.clone()))?;
|
||||
lua.globals().set("ud", ud)?;
|
||||
lua.load("ud:inc()").exec()?;
|
||||
assert_eq!(Arc::strong_count(&arc), 3);
|
||||
assert_eq!(Rc::strong_count(&rc), 2);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
lua.gc_collect()?;
|
||||
assert_eq!(Arc::strong_count(&arc), 1);
|
||||
assert_eq!(Rc::strong_count(&rc), 1);
|
||||
assert_eq!(i.get(), 2);
|
||||
|
||||
match lua.load("ud:inc()").exec() {
|
||||
Err(Error::CallbackError { ref cause, .. }) => match cause.as_ref() {
|
||||
Error::CallbackDestructed => {}
|
||||
err => panic!("expected CallbackDestructed, got {:?}", err),
|
||||
Error::UserDataDestructed => {}
|
||||
err => panic!("expected UserDataDestructed, got {err:?}"),
|
||||
},
|
||||
r => panic!("improper return for destructed userdata: {:?}", r),
|
||||
r => panic!("improper return for destructed userdata: {r:?}"),
|
||||
};
|
||||
|
||||
let ud = lua.globals().get::<_, AnyUserData>("ud")?;
|
||||
match ud.borrow::<MyUserData>() {
|
||||
let ud = lua.globals().get::<AnyUserData>("ud")?;
|
||||
match ud.borrow_scoped::<MyUserData, _>(|_| Ok::<_, Error>(())) {
|
||||
Ok(_) => panic!("succesfull borrow for destructed userdata"),
|
||||
Err(Error::UserDataDestructed) => {}
|
||||
Err(err) => panic!("improper borrow error for destructed userdata: {:?}", err),
|
||||
Err(err) => panic!("improper borrow error for destructed userdata: {err:?}"),
|
||||
}
|
||||
match ud.get_metatable() {
|
||||
Ok(_) => panic!("successful metatable retrieval of destructed userdata"),
|
||||
Err(Error::UserDataDestructed) => {}
|
||||
Err(err) => panic!(
|
||||
"improper metatable error for destructed userdata: {:?}",
|
||||
err
|
||||
),
|
||||
Err(err) => panic!("improper metatable error for destructed userdata: {err:?}"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -377,7 +316,7 @@ fn test_scope_userdata_ref() -> Result<()> {
|
||||
struct MyUserData(Cell<i64>);
|
||||
|
||||
impl UserData for MyUserData {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("inc", |_, data, ()| {
|
||||
data.0.set(data.0.get() + 1);
|
||||
Ok(())
|
||||
@@ -407,7 +346,7 @@ fn test_scope_userdata_ref_mut() -> Result<()> {
|
||||
struct MyUserData(i64);
|
||||
|
||||
impl UserData for MyUserData {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method_mut("inc", |_, data, ()| {
|
||||
data.0 += 1;
|
||||
Ok(())
|
||||
@@ -438,8 +377,9 @@ fn test_scope_any_userdata() -> Result<()> {
|
||||
reg.add_meta_method("__tostring", |_, data, ()| Ok(data.clone()));
|
||||
})?;
|
||||
|
||||
let data = StdString::from("foo");
|
||||
lua.scope(|scope| {
|
||||
let ud = scope.create_any_userdata(StdString::from("foo"))?;
|
||||
let ud = scope.create_any_userdata_ref(&data)?;
|
||||
lua.globals().set("ud", ud)?;
|
||||
lua.load("assert(tostring(ud) == 'foo')").exec()
|
||||
})?;
|
||||
@@ -447,10 +387,10 @@ fn test_scope_any_userdata() -> Result<()> {
|
||||
// Check that userdata is destructed
|
||||
match lua.load("tostring(ud)").exec() {
|
||||
Err(Error::CallbackError { ref cause, .. }) => match cause.as_ref() {
|
||||
Error::CallbackDestructed => {}
|
||||
err => panic!("expected CallbackDestructed, got {:?}", err),
|
||||
Error::UserDataDestructed => {}
|
||||
err => panic!("expected CallbackDestructed, got {err:?}"),
|
||||
},
|
||||
r => panic!("improper return for destructed userdata: {:?}", r),
|
||||
r => panic!("improper return for destructed userdata: {r:?}"),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
@@ -495,7 +435,7 @@ fn modify_userdata(lua: &Lua, ud: AnyUserData) -> Result<()> {
|
||||
)
|
||||
.eval()?;
|
||||
|
||||
f.call(ud)?;
|
||||
f.call::<()>(ud)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -71,50 +71,6 @@ fn test_serialize() -> Result<(), Box<dyn StdError>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_serialize_in_scope() -> LuaResult<()> {
|
||||
// #[derive(Serialize, Clone)]
|
||||
// struct MyUserData(i64, String);
|
||||
|
||||
// impl UserData for MyUserData {}
|
||||
|
||||
// let lua = Lua::new();
|
||||
// lua.scope(|scope| {
|
||||
// let ud = scope.create_ser_userdata(MyUserData(-5, "test userdata".into()))?;
|
||||
// assert_eq!(
|
||||
// serde_json::to_value(&ud).unwrap(),
|
||||
// serde_json::json!((-5, "test userdata"))
|
||||
// );
|
||||
// Ok(())
|
||||
// })?;
|
||||
|
||||
// lua.scope(|scope| {
|
||||
// let ud = scope.create_ser_userdata(MyUserData(-5, "test userdata".into()))?;
|
||||
// lua.globals().set("ud", ud)
|
||||
// })?;
|
||||
// let val = lua.load("ud").eval::<Value>()?;
|
||||
// match serde_json::to_value(&val) {
|
||||
// Ok(v) => panic!("expected destructed error, got {}", v),
|
||||
// Err(e) if e.to_string().contains("destructed") => {}
|
||||
// Err(e) => panic!("expected destructed error, got {}", e),
|
||||
// }
|
||||
|
||||
// struct MyUserDataRef<'a>(#[allow(unused)] &'a ());
|
||||
|
||||
// impl<'a> UserData for MyUserDataRef<'a> {}
|
||||
|
||||
// lua.scope(|scope| {
|
||||
// let ud = scope.create_nonstatic_userdata(MyUserDataRef(&()))?;
|
||||
// match serde_json::to_value(&ud) {
|
||||
// Ok(v) => panic!("expected serialization error, got {}", v),
|
||||
// Err(serde_json::Error { .. }) => {}
|
||||
// };
|
||||
// Ok(())
|
||||
// })?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_serialize_any_userdata() -> Result<(), Box<dyn StdError>> {
|
||||
let lua = Lua::new();
|
||||
|
||||
+2
-2
@@ -336,8 +336,8 @@ fn test_userdata_take() -> Result<()> {
|
||||
}
|
||||
match lua.load("userdata:num()").exec() {
|
||||
Err(Error::CallbackError { ref cause, .. }) => match cause.as_ref() {
|
||||
Error::CallbackDestructed => {}
|
||||
err => panic!("expected `CallbackDestructed`, got {:?}", err),
|
||||
Error::UserDataDestructed => {}
|
||||
err => panic!("expected `UserDataDestructed`, got {:?}", err),
|
||||
},
|
||||
r => panic!("improper return for destructed userdata: {:?}", r),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user