Remove explicit lifetime from UserDataMethods and UserDataFields traits.

Pass `'static` arguments to async functions and require `'static` Future.
(in future we can use async closures to make it more elegant).
This commit is contained in:
Alex Orlenko
2024-08-23 00:05:24 +01:00
parent 8092f00930
commit 9931709ecd
18 changed files with 403 additions and 361 deletions
+7 -6
View File
@@ -513,10 +513,10 @@ impl PartialEq for Function {
}
}
pub(crate) struct WrappedFunction(pub(crate) Callback<'static>);
pub(crate) struct WrappedFunction(pub(crate) Callback);
#[cfg(feature = "async")]
pub(crate) struct WrappedAsyncFunction(pub(crate) AsyncCallback<'static>);
pub(crate) struct WrappedAsyncFunction(pub(crate) AsyncCallback);
impl Function {
/// Wraps a Rust function or closure, returning an opaque type that implements [`IntoLua`]
@@ -558,15 +558,16 @@ impl Function {
where
A: FromLuaMulti,
R: IntoLuaMulti,
F: Fn(&Lua, A) -> FR + MaybeSend + 'static,
F: Fn(Lua, A) -> FR + MaybeSend + 'static,
FR: Future<Output = Result<R>> + MaybeSend + 'static,
{
WrappedAsyncFunction(Box::new(move |lua, args| unsafe {
let args = match A::from_lua_args(args, 1, None, lua) {
WrappedAsyncFunction(Box::new(move |rawlua, nargs| unsafe {
let args = match A::from_stack_args(nargs, 1, None, rawlua) {
Ok(args) => args,
Err(e) => return Box::pin(future::ready(Err(e))),
};
let fut = func(lua, args);
let lua = rawlua.lua().clone();
let fut = func(lua.clone(), args);
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
}))
}
+10 -17
View File
@@ -137,13 +137,6 @@ impl LuaOptions {
}
}
#[cfg(not(feature = "module"))]
impl Drop for Lua {
fn drop(&mut self) {
let _ = self.gc_collect();
}
}
impl fmt::Debug for Lua {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Lua({:p})", self.lock().state())
@@ -1138,7 +1131,7 @@ impl Lua {
/// use std::time::Duration;
/// use mlua::{Lua, Result};
///
/// async fn sleep(_lua: &Lua, n: u64) -> Result<&'static str> {
/// async fn sleep(_lua: Lua, n: u64) -> Result<&'static str> {
/// tokio::time::sleep(Duration::from_millis(n)).await;
/// Ok("done")
/// }
@@ -1157,20 +1150,20 @@ impl Lua {
/// [`AsyncThread`]: crate::AsyncThread
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
pub fn create_async_function<'lua, 'a, F, A, FR, R>(&'lua self, func: F) -> Result<Function>
pub fn create_async_function<F, A, FR, R>(&self, func: F) -> Result<Function>
where
'lua: 'a,
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
F: Fn(Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
FR: Future<Output = Result<R>> + MaybeSend + 'a,
FR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti,
{
(self.lock()).create_async_callback(Box::new(move |lua, args| unsafe {
let args = match A::from_lua_args(args, 1, None, lua) {
(self.lock()).create_async_callback(Box::new(move |rawlua, nargs| unsafe {
let args = match A::from_stack_args(nargs, 1, None, rawlua) {
Ok(args) => args,
Err(e) => return Box::pin(future::ready(Err(e))),
};
let fut = func(lua, args);
let lua = rawlua.lua().clone();
let fut = func(lua.clone(), args);
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
}))
}
@@ -1274,11 +1267,11 @@ impl Lua {
/// struct MyUserData(i32);
///
/// impl UserData for MyUserData {
/// fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) {
/// fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
/// fields.add_field_method_get("val", |_, this| Ok(this.0));
/// }
///
/// fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) {
/// fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
/// methods.add_function("new", |_, value: i32| Ok(MyUserData(value)));
/// }
/// }
+1 -4
View File
@@ -1053,7 +1053,6 @@ impl RawLua {
let _sg = StackGuard::new(state);
check_stack(state, 4)?;
let func = mem::transmute::<Callback, Callback<'static>>(func);
let extra = XRc::clone(&self.extra);
let protect = !self.unlikely_memory_error();
push_internal_userdata(state, CallbackUpvalue { data: func, extra }, protect)?;
@@ -1090,9 +1089,8 @@ impl RawLua {
let rawlua = (*extra).raw_lua();
let _guard = StateGuard::new(rawlua, state);
let args = MultiValue::from_stack_multi(nargs, rawlua)?;
let func = &*(*upvalue).data;
let fut = func(rawlua.lua(), args);
let fut = func(rawlua, nargs);
let extra = XRc::clone(&(*upvalue).extra);
let protect = !rawlua.unlikely_memory_error();
push_internal_userdata(state, AsyncPollUpvalue { data: fut, extra }, protect)?;
@@ -1152,7 +1150,6 @@ impl RawLua {
let _sg = StackGuard::new(state);
check_stack(state, 4)?;
let func = mem::transmute::<AsyncCallback, AsyncCallback<'static>>(func);
let extra = XRc::clone(&self.extra);
let protect = !self.unlikely_memory_error();
let upvalue = AsyncCallbackUpvalue { data: func, extra };
+4 -8
View File
@@ -12,9 +12,6 @@ use crate::error::Result;
use crate::hook::Debug;
use crate::state::{ExtraData, Lua, RawLua, WeakLua};
#[cfg(feature = "async")]
use crate::value::MultiValue;
#[cfg(all(feature = "async", feature = "send"))]
pub(crate) type BoxFuture<'a, T> = futures_util::future::BoxFuture<'a, T>;
@@ -52,21 +49,20 @@ unsafe impl Send for LightUserData {}
#[cfg(feature = "send")]
unsafe impl Sync for LightUserData {}
pub(crate) type Callback<'a> = Box<dyn Fn(&'a RawLua, c_int) -> Result<c_int> + 'static>;
pub(crate) type Callback = Box<dyn Fn(&RawLua, c_int) -> Result<c_int> + 'static>;
pub(crate) struct Upvalue<T> {
pub(crate) data: T,
pub(crate) extra: XRc<UnsafeCell<ExtraData>>,
}
pub(crate) type CallbackUpvalue = Upvalue<Callback<'static>>;
pub(crate) type CallbackUpvalue = Upvalue<Callback>;
#[cfg(feature = "async")]
pub(crate) type AsyncCallback<'a> =
Box<dyn Fn(&'a Lua, MultiValue) -> BoxFuture<'a, Result<c_int>> + 'static>;
pub(crate) type AsyncCallback = Box<dyn Fn(&RawLua, c_int) -> BoxFuture<'static, Result<c_int>> + 'static>;
#[cfg(feature = "async")]
pub(crate) type AsyncCallbackUpvalue = Upvalue<AsyncCallback<'static>>;
pub(crate) type AsyncCallbackUpvalue = Upvalue<AsyncCallback>;
#[cfg(feature = "async")]
pub(crate) type AsyncPollUpvalue = Upvalue<BoxFuture<'static, Result<c_int>>>;
+35 -41
View File
@@ -248,7 +248,7 @@ impl AsRef<str> for MetaMethod {
/// Method registry for [`UserData`] implementors.
///
/// [`UserData`]: crate::UserData
pub trait UserDataMethods<'a, T> {
pub trait UserDataMethods<T> {
/// Add a regular method which accepts a `&T` as the first parameter.
///
/// Regular methods are implemented by overriding the `__index` metamethod and returning the
@@ -258,7 +258,7 @@ pub trait UserDataMethods<'a, T> {
/// be used as a fall-back if no regular method is found.
fn add_method<M, A, R>(&mut self, name: impl ToString, method: M)
where
M: Fn(&'a Lua, &T, A) -> Result<R> + MaybeSend + 'static,
M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti;
@@ -269,7 +269,7 @@ pub trait UserDataMethods<'a, T> {
/// [`add_method`]: #method.add_method
fn add_method_mut<M, A, R>(&mut self, name: impl ToString, method: M)
where
M: FnMut(&'a Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti;
@@ -285,9 +285,9 @@ pub trait UserDataMethods<'a, T> {
fn add_async_method<M, A, MR, R>(&mut self, name: impl ToString, method: M)
where
T: 'static,
M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static,
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti;
/// Add an async method which accepts a `&mut T` as the first parameter and returns Future.
@@ -302,9 +302,9 @@ pub trait UserDataMethods<'a, T> {
fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl ToString, method: M)
where
T: 'static,
M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static,
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti;
/// Add a regular method as a function which accepts generic arguments, the first argument will
@@ -319,7 +319,7 @@ pub trait UserDataMethods<'a, T> {
/// [`add_method_mut`]: #method.add_method_mut
fn add_function<F, A, R>(&mut self, name: impl ToString, function: F)
where
F: Fn(&'a Lua, A) -> Result<R> + MaybeSend + 'static,
F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti;
@@ -330,7 +330,7 @@ pub trait UserDataMethods<'a, T> {
/// [`add_function`]: #method.add_function
fn add_function_mut<F, A, R>(&mut self, name: impl ToString, function: F)
where
F: FnMut(&'a Lua, A) -> Result<R> + MaybeSend + 'static,
F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti;
@@ -346,9 +346,9 @@ pub trait UserDataMethods<'a, T> {
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_function<F, A, FR, R>(&mut self, name: impl ToString, function: F)
where
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
F: Fn(Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
FR: Future<Output = Result<R>> + MaybeSend + 'a,
FR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti;
/// Add a metamethod which accepts a `&T` as the first parameter.
@@ -361,7 +361,7 @@ pub trait UserDataMethods<'a, T> {
/// [`add_meta_function`]: #method.add_meta_function
fn add_meta_method<M, A, R>(&mut self, name: impl ToString, method: M)
where
M: Fn(&'a Lua, &T, A) -> Result<R> + MaybeSend + 'static,
M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti;
@@ -375,7 +375,7 @@ pub trait UserDataMethods<'a, T> {
/// [`add_meta_function`]: #method.add_meta_function
fn add_meta_method_mut<M, A, R>(&mut self, name: impl ToString, method: M)
where
M: FnMut(&'a Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti;
@@ -391,9 +391,9 @@ pub trait UserDataMethods<'a, T> {
fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl ToString, method: M)
where
T: 'static,
M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static,
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti;
/// Add an async metamethod which accepts a `&mut T` as the first parameter and returns Future.
@@ -408,9 +408,9 @@ pub trait UserDataMethods<'a, T> {
fn add_async_meta_method_mut<M, A, MR, R>(&mut self, name: impl ToString, method: M)
where
T: 'static,
M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static,
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti;
/// Add a metamethod which accepts generic arguments.
@@ -420,7 +420,7 @@ pub trait UserDataMethods<'a, T> {
/// userdata of type `T`.
fn add_meta_function<F, A, R>(&mut self, name: impl ToString, function: F)
where
F: Fn(&'a Lua, A) -> Result<R> + MaybeSend + 'static,
F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti;
@@ -431,7 +431,7 @@ pub trait UserDataMethods<'a, T> {
/// [`add_meta_function`]: #method.add_meta_function
fn add_meta_function_mut<F, A, R>(&mut self, name: impl ToString, function: F)
where
F: FnMut(&'a Lua, A) -> Result<R> + MaybeSend + 'static,
F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti;
@@ -446,16 +446,16 @@ pub trait UserDataMethods<'a, T> {
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl ToString, function: F)
where
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
F: Fn(Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
FR: Future<Output = Result<R>> + MaybeSend + 'a,
FR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti;
}
/// Field registry for [`UserData`] implementors.
///
/// [`UserData`]: crate::UserData
pub trait UserDataFields<'a, T> {
pub trait UserDataFields<T> {
/// Add a static field to the `UserData`.
///
/// Static fields are implemented by updating the `__index` metamethod and returning the
@@ -478,7 +478,7 @@ pub trait UserDataFields<'a, T> {
/// be used as a fall-back if no regular field or method are found.
fn add_field_method_get<M, R>(&mut self, name: impl ToString, method: M)
where
M: Fn(&'a Lua, &T) -> Result<R> + MaybeSend + 'static,
M: Fn(&Lua, &T) -> Result<R> + MaybeSend + 'static,
R: IntoLua;
/// Add a regular field setter as a method which accepts a `&mut T` as the first parameter.
@@ -491,7 +491,7 @@ pub trait UserDataFields<'a, T> {
/// will be used as a fall-back if no regular field is found.
fn add_field_method_set<M, A>(&mut self, name: impl ToString, method: M)
where
M: FnMut(&'a Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
M: FnMut(&Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
A: FromLua;
/// Add a regular field getter as a function which accepts a generic [`AnyUserData`] of type `T`
@@ -503,7 +503,7 @@ pub trait UserDataFields<'a, T> {
/// [`add_field_method_get`]: #method.add_field_method_get
fn add_field_function_get<F, R>(&mut self, name: impl ToString, function: F)
where
F: Fn(&'a Lua, AnyUserData) -> Result<R> + MaybeSend + 'static,
F: Fn(&Lua, AnyUserData) -> Result<R> + MaybeSend + 'static,
R: IntoLua;
/// Add a regular field setter as a function which accepts a generic [`AnyUserData`] of type `T`
@@ -515,7 +515,7 @@ pub trait UserDataFields<'a, T> {
/// [`add_field_method_set`]: #method.add_field_method_set
fn add_field_function_set<F, A>(&mut self, name: impl ToString, function: F)
where
F: FnMut(&'a Lua, AnyUserData, A) -> Result<()> + MaybeSend + 'static,
F: FnMut(&Lua, AnyUserData, A) -> Result<()> + MaybeSend + 'static,
A: FromLua;
/// Add a metatable field.
@@ -540,7 +540,7 @@ pub trait UserDataFields<'a, T> {
/// like `__gc` or `__metatable`.
fn add_meta_field_with<F, R>(&mut self, name: impl ToString, f: F)
where
F: Fn(&'a Lua) -> Result<R> + MaybeSend + 'static,
F: Fn(&Lua) -> Result<R> + MaybeSend + 'static,
R: IntoLua;
}
@@ -579,12 +579,12 @@ pub trait UserDataFields<'a, T> {
/// struct MyUserData(i32);
///
/// impl UserData for MyUserData {
/// fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) {
/// fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
/// fields.add_field_method_get("val", |_, this| Ok(this.0));
/// }
///
/// fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) {
/// methods.add_method_mut("add", |_, this, value: i32| {
/// fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
/// methods.add_method_mut("add", |_, mut this, value: i32| {
/// this.0 += value;
/// Ok(())
/// });
@@ -614,11 +614,11 @@ pub trait UserDataFields<'a, T> {
pub trait UserData: Sized {
/// Adds custom fields specific to this userdata.
#[allow(unused_variables)]
fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) {}
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {}
/// Adds custom methods and operators specific to this userdata.
#[allow(unused_variables)]
fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) {}
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {}
/// Registers this type for use in Lua.
///
@@ -663,7 +663,7 @@ impl AnyUserData {
/// `UserDataTypeMismatch` if the userdata is not of type `T`.
#[inline]
pub fn borrow<T: 'static>(&self) -> Result<UserDataRef<T>> {
self.inspect(|variant, guard| variant.try_make_ref(guard))
self.inspect(|variant, _| variant.try_borrow_owned())
}
/// Borrow this userdata mutably if it is of type `T`.
@@ -674,7 +674,7 @@ impl AnyUserData {
/// Returns a `UserDataTypeMismatch` if the userdata is not of type `T`.
#[inline]
pub fn borrow_mut<T: 'static>(&self) -> Result<UserDataRefMut<T>> {
self.inspect(|variant, guard| variant.try_make_mut_ref(guard))
self.inspect(|variant, _| variant.try_borrow_owned_mut())
}
/// Takes the value out of this userdata.
@@ -940,13 +940,6 @@ impl AnyUserData {
self.0.to_pointer()
}
#[cfg(feature = "async")]
#[inline]
pub(crate) fn type_id(&self) -> Result<Option<TypeId>> {
let lua = self.0.lua.lock();
unsafe { lua.get_userdata_ref_type_id(&self.0) }
}
/// Returns a type name of this `UserData` (from a metatable field).
pub(crate) fn type_name(&self) -> Result<Option<StdString>> {
match self.1 {
@@ -1182,6 +1175,7 @@ where
mod cell;
mod ext;
mod lock;
mod registry;
#[cfg(test)]
+113 -138
View File
@@ -1,34 +1,42 @@
use std::any::{type_name, TypeId};
use std::cell::{Cell, UnsafeCell};
use std::cell::UnsafeCell;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::os::raw::c_int;
use std::rc::Rc;
#[cfg(feature = "serialize")]
use serde::ser::{Serialize, Serializer};
use crate::error::{Error, Result};
use crate::state::{Lua, LuaGuard, RawLua};
use crate::state::{Lua, RawLua};
use crate::types::{MaybeSend, XRc};
use crate::userdata::AnyUserData;
use crate::util::get_userdata;
use crate::value::{FromLua, Value};
use super::lock::{RawLock, UserDataLock};
#[cfg(all(feature = "serialize", not(feature = "send")))]
type DynSerialize = dyn erased_serde::Serialize;
#[cfg(all(feature = "serialize", feature = "send"))]
type DynSerialize = dyn erased_serde::Serialize + Send;
// A enum for storing userdata values.
// It's stored inside a Lua VM and protected by the outer `ReentrantMutex`.
pub(crate) enum UserDataVariant<T> {
Default(Rc<InnerRefCell<T>>),
Default(XRc<UserDataCell<T>>),
#[cfg(feature = "serialize")]
Serializable(Rc<InnerRefCell<Box<dyn erased_serde::Serialize>>>),
Serializable(XRc<UserDataCell<ForceSync<Box<DynSerialize>>>>),
}
impl<T> Clone for UserDataVariant<T> {
#[inline]
fn clone(&self) -> Self {
match self {
Self::Default(inner) => Self::Default(Rc::clone(inner)),
Self::Default(inner) => Self::Default(XRc::clone(inner)),
#[cfg(feature = "serialize")]
Self::Serializable(inner) => UserDataVariant::Serializable(Rc::clone(inner)),
Self::Serializable(inner) => Self::Serializable(XRc::clone(inner)),
}
}
}
@@ -36,54 +44,56 @@ impl<T> Clone for UserDataVariant<T> {
impl<T> UserDataVariant<T> {
#[inline(always)]
pub(crate) fn new(data: T) -> Self {
Self::Default(Rc::new(InnerRefCell::new(data)))
Self::Default(XRc::new(UserDataCell::new(data)))
}
// Immutably borrows the wrapped value in-place.
#[inline(always)]
pub(crate) unsafe fn try_borrow(&self) -> Result<UserDataBorrowRef<T>> {
pub(crate) 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_make_ref(&self, guard: LuaGuard) -> Result<UserDataRef<T>> {
UserDataRef::try_from(self.clone(), guard)
pub(crate) fn try_borrow_owned(&self) -> Result<UserDataRef<T>> {
UserDataRef::try_from(self.clone())
}
// Mutably borrows the wrapped value in-place.
#[inline(always)]
pub(crate) unsafe fn try_borrow_mut(&self) -> Result<UserDataBorrowMut<T>> {
pub(crate) 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_make_mut_ref(&self, guard: LuaGuard) -> Result<UserDataRefMut<T>> {
UserDataRefMut::try_from(self.clone(), guard)
pub(crate) 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> {
set_writing(self.flag())?;
if !self.raw_lock().try_lock_exclusive() {
return Err(Error::UserDataBorrowMutError);
}
Ok(match self {
Self::Default(inner) => Rc::into_inner(inner).unwrap().value.into_inner(),
Self::Default(inner) => XRc::into_inner(inner).unwrap().value.into_inner(),
#[cfg(feature = "serialize")]
Self::Serializable(inner) => unsafe {
let raw = Box::into_raw(Rc::into_inner(inner).unwrap().value.into_inner());
let raw = Box::into_raw(XRc::into_inner(inner).unwrap().value.into_inner().0);
*Box::from_raw(raw as *mut T)
},
})
}
#[inline(always)]
fn flag(&self) -> &Cell<BorrowFlag> {
fn raw_lock(&self) -> &RawLock {
match self {
Self::Default(inner) => &inner.borrow,
Self::Default(inner) => &inner.raw_lock,
#[cfg(feature = "serialize")]
Self::Serializable(inner) => &inner.borrow,
Self::Serializable(inner) => &inner.raw_lock,
}
}
@@ -98,11 +108,12 @@ impl<T> UserDataVariant<T> {
}
#[cfg(feature = "serialize")]
impl<T: Serialize + 'static> UserDataVariant<T> {
impl<T: Serialize + MaybeSend + 'static> UserDataVariant<T> {
#[inline(always)]
pub(crate) fn new_ser(data: T) -> Self {
let data = Box::new(data) as Box<dyn erased_serde::Serialize>;
Self::Serializable(Rc::new(InnerRefCell::new(data)))
let data = Box::new(data) as Box<DynSerialize>;
let data = ForceSync(data);
Self::Serializable(XRc::new(UserDataCell::new(data)))
}
}
@@ -110,29 +121,34 @@ impl<T: Serialize + 'static> UserDataVariant<T> {
impl Serialize for UserDataVariant<()> {
fn serialize<S: Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
match self {
UserDataVariant::Default(_) => Err(serde::ser::Error::custom("cannot serialize <userdata>")),
UserDataVariant::Serializable(inner) => unsafe {
let _ = self.try_borrow().map_err(serde::ser::Error::custom)?;
(*inner.value.get()).serialize(serializer)
Self::Default(_) => Err(serde::ser::Error::custom("cannot serialize <userdata>")),
Self::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)?;
// No need to do this if the `send` feature is disabled.
#[cfg(not(feature = "send"))]
let _guard = self.try_borrow().map_err(serde::ser::Error::custom)?;
(*inner.value.get()).0.serialize(serializer)
},
}
}
}
//
// Inspired by `std::cell::RefCell`` implementation
//
pub(crate) struct InnerRefCell<T> {
borrow: Cell<BorrowFlag>,
/// A type that provides interior mutability for a userdata value (thread-safe).
pub(crate) struct UserDataCell<T> {
raw_lock: RawLock,
value: UnsafeCell<T>,
}
impl<T> InnerRefCell<T> {
unsafe impl<T: Send> Send for UserDataCell<T> {}
unsafe impl<T: Send + Sync> Sync for UserDataCell<T> {}
impl<T> UserDataCell<T> {
#[inline(always)]
pub fn new(value: T) -> Self {
InnerRefCell {
borrow: Cell::new(UNUSED),
UserDataCell {
raw_lock: RawLock::INIT,
value: UnsafeCell::new(value),
}
}
@@ -141,25 +157,21 @@ impl<T> InnerRefCell<T> {
/// A wrapper type for a [`UserData`] value that provides read access.
///
/// It implements [`FromLua`] and can be used to receive a typed userdata from Lua.
pub struct UserDataRef<T> {
variant: UserDataVariant<T>,
#[allow(unused)]
guard: LuaGuard,
}
pub struct UserDataRef<T>(UserDataVariant<T>);
impl<T> Deref for UserDataRef<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { &*self.variant.as_ptr() }
unsafe { &*self.0.as_ptr() }
}
}
impl<T> Drop for UserDataRef<T> {
#[inline]
fn drop(&mut self) {
unset_reading(self.variant.flag());
unsafe { self.0.raw_lock().unlock_shared() };
}
}
@@ -175,11 +187,15 @@ impl<T: fmt::Display> fmt::Display for UserDataRef<T> {
}
}
impl<T> UserDataRef<T> {
impl<T> TryFrom<UserDataVariant<T>> for UserDataRef<T> {
type Error = Error;
#[inline]
fn try_from(variant: UserDataVariant<T>, guard: LuaGuard) -> Result<Self> {
set_reading(variant.flag())?;
Ok(UserDataRef { variant, guard })
fn try_from(variant: UserDataVariant<T>) -> Result<Self> {
if !variant.raw_lock().try_lock_shared() {
return Err(Error::UserDataBorrowError);
}
Ok(UserDataRef(variant))
}
}
@@ -192,8 +208,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>() => {
let guard = lua.lua().lock_arc();
(*get_userdata::<UserDataVariant<T>>(lua.state(), idx)).try_make_ref(guard)
(*get_userdata::<UserDataVariant<T>>(lua.state(), idx)).try_borrow_owned()
}
_ => Err(Error::UserDataTypeMismatch),
}
@@ -203,32 +218,28 @@ impl<T: 'static> FromLua for UserDataRef<T> {
/// A wrapper type for a mutably borrowed value from a `AnyUserData`.
///
/// It implements [`FromLua`] and can be used to receive a typed userdata from Lua.
pub struct UserDataRefMut<T> {
variant: UserDataVariant<T>,
#[allow(unused)]
guard: LuaGuard,
}
pub struct UserDataRefMut<T>(UserDataVariant<T>);
impl<T> Deref for UserDataRefMut<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { &*self.variant.as_ptr() }
unsafe { &*self.0.as_ptr() }
}
}
impl<T> DerefMut for UserDataRefMut<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.variant.as_ptr() }
unsafe { &mut *self.0.as_ptr() }
}
}
impl<T> Drop for UserDataRefMut<T> {
#[inline]
fn drop(&mut self) {
unset_writing(self.variant.flag());
unsafe { self.0.raw_lock().unlock_exclusive() };
}
}
@@ -244,11 +255,15 @@ impl<T: fmt::Display> fmt::Display for UserDataRefMut<T> {
}
}
impl<T> UserDataRefMut<T> {
fn try_from(variant: UserDataVariant<T>, guard: LuaGuard) -> Result<Self> {
// There must currently be no existing references
set_writing(variant.flag())?;
Ok(UserDataRefMut { variant, guard })
impl<T> TryFrom<UserDataVariant<T>> for UserDataRefMut<T> {
type Error = Error;
#[inline]
fn try_from(variant: UserDataVariant<T>) -> Result<Self> {
if !variant.raw_lock().try_lock_exclusive() {
return Err(Error::UserDataBorrowMutError);
}
Ok(UserDataRefMut(variant))
}
}
@@ -261,73 +276,20 @@ 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>() => {
let guard = lua.lua().lock_arc();
(*get_userdata::<UserDataVariant<T>>(lua.state(), idx)).try_make_mut_ref(guard)
(*get_userdata::<UserDataVariant<T>>(lua.state(), idx)).try_borrow_owned_mut()
}
_ => Err(Error::UserDataTypeMismatch),
}
}
}
// Positive values represent the number of `Ref` active. Negative values
// represent the number of `RefMut` active. Multiple `RefMut`s can only be
// active at a time if they refer to distinct, nonoverlapping components of a
// `RefCell` (e.g., different ranges of a slice).
type BorrowFlag = isize;
const UNUSED: BorrowFlag = 0;
#[inline(always)]
fn is_writing(x: BorrowFlag) -> bool {
x < UNUSED
}
#[inline(always)]
fn is_reading(x: BorrowFlag) -> bool {
x > UNUSED
}
#[inline(always)]
fn set_writing(borrow: &Cell<BorrowFlag>) -> Result<()> {
let flag = borrow.get();
if flag != UNUSED {
return Err(Error::UserDataBorrowMutError);
}
borrow.set(UNUSED - 1);
Ok(())
}
#[inline(always)]
fn set_reading(borrow: &Cell<BorrowFlag>) -> Result<()> {
let flag = borrow.get().wrapping_add(1);
if !is_reading(flag) {
return Err(Error::UserDataBorrowError);
}
borrow.set(flag);
Ok(())
}
#[inline(always)]
#[track_caller]
fn unset_writing(borrow: &Cell<BorrowFlag>) {
let flag = borrow.get();
debug_assert!(is_writing(flag));
borrow.set(flag + 1);
}
#[inline(always)]
#[track_caller]
fn unset_reading(borrow: &Cell<BorrowFlag>) {
let flag = borrow.get();
debug_assert!(is_reading(flag));
borrow.set(flag - 1);
}
/// A type that provides read access to a userdata value (borrowing the value).
pub(crate) struct UserDataBorrowRef<'a, T>(&'a UserDataVariant<T>);
impl<'a, T> Drop for UserDataBorrowRef<'a, T> {
#[inline]
fn drop(&mut self) {
unset_reading(self.0.flag());
unsafe { self.0.raw_lock().unlock_shared() };
}
}
@@ -336,6 +298,7 @@ impl<'a, T> Deref for UserDataBorrowRef<'a, T> {
#[inline]
fn deref(&self) -> &T {
// SAFETY: `UserDataBorrowRef` is only created with shared access to the value.
unsafe { &*self.0.as_ptr() }
}
}
@@ -345,25 +308,19 @@ impl<'a, T> TryFrom<&'a UserDataVariant<T>> for UserDataBorrowRef<'a, T> {
#[inline(always)]
fn try_from(variant: &'a UserDataVariant<T>) -> Result<Self> {
set_reading(variant.flag())?;
if !variant.raw_lock().try_lock_shared() {
return Err(Error::UserDataBorrowError);
}
Ok(UserDataBorrowRef(variant))
}
}
impl<'a, T> UserDataBorrowRef<'a, T> {
#[inline(always)]
pub(crate) fn get_ref(&self) -> &'a T {
// SAFETY: `UserDataBorrowRef` is only created when the borrow flag is set to reading.
unsafe { &*self.0.as_ptr() }
}
}
pub(crate) struct UserDataBorrowMut<'a, T>(&'a UserDataVariant<T>);
impl<'a, T> Drop for UserDataBorrowMut<'a, T> {
#[inline]
fn drop(&mut self) {
unset_writing(self.0.flag());
unsafe { self.0.raw_lock().unlock_exclusive() };
}
}
@@ -388,18 +345,17 @@ impl<'a, T> TryFrom<&'a UserDataVariant<T>> for UserDataBorrowMut<'a, T> {
#[inline(always)]
fn try_from(variant: &'a UserDataVariant<T>) -> Result<Self> {
set_writing(variant.flag())?;
if !variant.raw_lock().try_lock_exclusive() {
return Err(Error::UserDataBorrowMutError);
}
Ok(UserDataBorrowMut(variant))
}
}
impl<'a, T> UserDataBorrowMut<'a, T> {
#[inline(always)]
pub(crate) fn get_mut(&mut self) -> &'a mut T {
// SAFETY: `UserDataBorrowMut` is only created when the borrow flag is set to writing.
unsafe { &mut *self.0.as_ptr() }
}
}
#[repr(transparent)]
pub(crate) struct ForceSync<T>(T);
unsafe impl<T: Send> Sync for ForceSync<T> {}
#[inline]
fn try_value_to_userdata<T>(value: Value) -> Result<AnyUserData> {
@@ -417,6 +373,25 @@ fn try_value_to_userdata<T>(value: Value) -> Result<AnyUserData> {
mod assertions {
use super::*;
static_assertions::assert_not_impl_all!(UserDataRef<()>: Sync, Send);
static_assertions::assert_not_impl_all!(UserDataRefMut<()>: Sync, Send);
#[cfg(feature = "send")]
static_assertions::assert_impl_all!(UserDataRef<()>: Send, Sync);
#[cfg(feature = "send")]
static_assertions::assert_not_impl_all!(UserDataRef<std::rc::Rc<()>>: Send, Sync);
#[cfg(feature = "send")]
static_assertions::assert_impl_all!(UserDataRefMut<()>: Sync, Send);
#[cfg(feature = "send")]
static_assertions::assert_not_impl_all!(UserDataRefMut<std::rc::Rc<()>>: Send, Sync);
#[cfg(feature = "send")]
static_assertions::assert_impl_all!(UserDataBorrowRef<'_, ()>: Send, Sync);
#[cfg(feature = "send")]
static_assertions::assert_impl_all!(UserDataBorrowMut<'_, ()>: Send, Sync);
#[cfg(not(feature = "send"))]
static_assertions::assert_not_impl_all!(UserDataRef<()>: Send, Sync);
#[cfg(not(feature = "send"))]
static_assertions::assert_not_impl_all!(UserDataRefMut<()>: Send, Sync);
#[cfg(not(feature = "send"))]
static_assertions::assert_not_impl_all!(UserDataBorrowRef<'_, ()>: Send, Sync);
#[cfg(not(feature = "send"))]
static_assertions::assert_not_impl_all!(UserDataBorrowMut<'_, ()>: Send, Sync);
}
+93
View File
@@ -0,0 +1,93 @@
pub(crate) trait UserDataLock {
const INIT: Self;
fn try_lock_shared(&self) -> bool;
fn try_lock_exclusive(&self) -> bool;
unsafe fn unlock_shared(&self);
unsafe fn unlock_exclusive(&self);
}
pub(crate) use lock_impl::RawLock;
#[cfg(not(feature = "send"))]
mod lock_impl {
use std::cell::Cell;
// Positive values represent the number of read references.
// Negative values represent the number of write references (only one allowed).
pub(crate) type RawLock = Cell<isize>;
const UNUSED: isize = 0;
impl super::UserDataLock for RawLock {
#[allow(clippy::declare_interior_mutable_const)]
const INIT: Self = Cell::new(UNUSED);
#[inline(always)]
fn try_lock_shared(&self) -> bool {
let flag = self.get().wrapping_add(1);
if flag <= UNUSED {
return false;
}
self.set(flag);
true
}
#[inline(always)]
fn try_lock_exclusive(&self) -> bool {
let flag = self.get();
if flag != UNUSED {
return false;
}
self.set(UNUSED - 1);
true
}
#[inline(always)]
unsafe fn unlock_shared(&self) {
let flag = self.get();
debug_assert!(flag > UNUSED);
self.set(flag - 1);
}
#[inline(always)]
unsafe fn unlock_exclusive(&self) {
let flag = self.get();
debug_assert!(flag < UNUSED);
self.set(flag + 1);
}
}
}
#[cfg(feature = "send")]
mod lock_impl {
use parking_lot::lock_api::RawRwLock;
pub(crate) type RawLock = parking_lot::RawRwLock;
impl super::UserDataLock for RawLock {
#[allow(clippy::declare_interior_mutable_const)]
const INIT: Self = <Self as parking_lot::lock_api::RawRwLock>::INIT;
#[inline(always)]
fn try_lock_shared(&self) -> bool {
RawRwLock::try_lock_shared(self)
}
#[inline(always)]
fn try_lock_exclusive(&self) -> bool {
RawRwLock::try_lock_exclusive(self)
}
#[inline(always)]
unsafe fn unlock_shared(&self) {
RawRwLock::unlock_shared(self)
}
#[inline(always)]
unsafe fn unlock_exclusive(&self) {
RawRwLock::unlock_exclusive(self)
}
}
}
+102 -109
View File
@@ -9,7 +9,9 @@ use std::string::String as StdString;
use crate::error::{Error, Result};
use crate::state::Lua;
use crate::types::{Callback, MaybeSend};
use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataFields, UserDataMethods};
use crate::userdata::{
AnyUserData, MetaMethod, UserData, UserDataFields, UserDataMethods, UserDataRef, UserDataRefMut,
};
use crate::util::{get_userdata, short_type_name};
use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Value};
@@ -22,25 +24,25 @@ use {
};
/// Handle to registry for userdata methods and metamethods.
pub struct UserDataRegistry<'a, T: 'static> {
pub struct UserDataRegistry<T: 'static> {
// Fields
pub(crate) fields: Vec<(String, Callback<'a>)>,
pub(crate) field_getters: Vec<(String, Callback<'a>)>,
pub(crate) field_setters: Vec<(String, Callback<'a>)>,
pub(crate) meta_fields: Vec<(String, Callback<'a>)>,
pub(crate) fields: Vec<(String, Callback)>,
pub(crate) field_getters: Vec<(String, Callback)>,
pub(crate) field_setters: Vec<(String, Callback)>,
pub(crate) meta_fields: Vec<(String, Callback)>,
// Methods
pub(crate) methods: Vec<(String, Callback<'a>)>,
pub(crate) methods: Vec<(String, Callback)>,
#[cfg(feature = "async")]
pub(crate) async_methods: Vec<(String, AsyncCallback<'a>)>,
pub(crate) meta_methods: Vec<(String, Callback<'a>)>,
pub(crate) async_methods: Vec<(String, AsyncCallback)>,
pub(crate) meta_methods: Vec<(String, Callback)>,
#[cfg(feature = "async")]
pub(crate) async_meta_methods: Vec<(String, AsyncCallback<'a>)>,
pub(crate) async_meta_methods: Vec<(String, AsyncCallback)>,
_type: PhantomData<T>,
}
impl<'a, T: 'static> UserDataRegistry<'a, T> {
impl<T: 'static> UserDataRegistry<T> {
pub(crate) const fn new() -> Self {
UserDataRegistry {
fields: Vec::new(),
@@ -57,9 +59,9 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
}
}
fn box_method<M, A, R>(name: &str, method: M) -> Callback<'a>
fn box_method<M, A, R>(name: &str, method: M) -> Callback
where
M: Fn(&'a Lua, &T, A) -> Result<R> + MaybeSend + 'static,
M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti,
{
@@ -77,13 +79,13 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
}
let state = rawlua.state();
// Find absolute "self" index before processing args
let index = ffi::lua_absindex(state, -nargs);
let self_index = ffi::lua_absindex(state, -nargs);
// 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(index)) {
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, index));
let ud = try_self_arg!(borrow_userdata_ref::<T>(state, self_index));
method(rawlua.lua(), &ud, args?)?.push_into_stack_multi(rawlua)
}
_ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)),
@@ -91,9 +93,9 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
})
}
fn box_method_mut<M, A, R>(name: &str, method: M) -> Callback<'a>
fn box_method_mut<M, A, R>(name: &str, method: M) -> Callback
where
M: FnMut(&'a Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti,
{
@@ -113,13 +115,13 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
}
let state = rawlua.state();
// Find absolute "self" index before processing args
let index = ffi::lua_absindex(state, -nargs);
let self_index = ffi::lua_absindex(state, -nargs);
// 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(index)) {
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, index));
let mut ud = try_self_arg!(borrow_userdata_mut::<T>(state, self_index));
method(rawlua.lua(), &mut ud, args?)?.push_into_stack_multi(rawlua)
}
_ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)),
@@ -128,11 +130,11 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
}
#[cfg(feature = "async")]
fn box_async_method<M, A, MR, R>(name: &str, method: M) -> AsyncCallback<'a>
fn box_async_method<M, A, MR, R>(name: &str, method: M) -> AsyncCallback
where
M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static,
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti,
{
let name = get_function_name::<T>(name);
@@ -145,38 +147,33 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
};
}
Box::new(move |lua, mut args| unsafe {
let this = args
.pop_front()
.ok_or_else(|| Error::from_lua_conversion("missing argument", "userdata", None));
let this = try_self_arg!(AnyUserData::from_lua(try_self_arg!(this), lua));
let args = A::from_lua_args(args, 2, Some(&name), lua);
let (ref_thread, index) = (lua.raw_lua().ref_thread(), this.0.index);
match try_self_arg!(this.type_id()) {
Some(id) if id == TypeId::of::<T>() => {
let ud = try_self_arg!(borrow_userdata_ref::<T>(ref_thread, index));
let args = match args {
Ok(args) => args,
Err(e) => return Box::pin(future::ready(Err(e))),
};
let fut = method(lua, ud.get_ref(), args);
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
}
_ => {
let err = Error::bad_self_argument(&name, Error::UserDataTypeMismatch);
Box::pin(future::ready(Err(err)))
}
Box::new(move |rawlua, nargs| unsafe {
if nargs == 0 {
let err = Error::from_lua_conversion("missing argument", "userdata", None);
try_self_arg!(Err(err));
}
// Stack will be empty when polling the future, keep `self` on the ref thread
let self_ud = try_self_arg!(AnyUserData::from_stack(-nargs, rawlua));
let args = A::from_stack_args(nargs - 1, 2, Some(&name), rawlua);
let self_ud = try_self_arg!(self_ud.borrow());
let args = match args {
Ok(args) => args,
Err(e) => return Box::pin(future::ready(Err(e))),
};
let lua = rawlua.lua().clone();
let fut = method(lua.clone(), self_ud, args);
// Lua is locked when the future is polled
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
})
}
#[cfg(feature = "async")]
fn box_async_method_mut<M, A, MR, R>(name: &str, method: M) -> AsyncCallback<'a>
fn box_async_method_mut<M, A, MR, R>(name: &str, method: M) -> AsyncCallback
where
M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static,
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti,
{
let name = get_function_name::<T>(name);
@@ -189,35 +186,30 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
};
}
Box::new(move |lua, mut args| unsafe {
let this = args
.pop_front()
.ok_or_else(|| Error::from_lua_conversion("missing argument", "userdata", None));
let this = try_self_arg!(AnyUserData::from_lua(try_self_arg!(this), lua));
let args = A::from_lua_args(args, 2, Some(&name), lua);
let (ref_thread, index) = (lua.raw_lua().ref_thread(), this.0.index);
match try_self_arg!(this.type_id()) {
Some(id) if id == TypeId::of::<T>() => {
let mut ud = try_self_arg!(borrow_userdata_mut::<T>(ref_thread, index));
let args = match args {
Ok(args) => args,
Err(e) => return Box::pin(future::ready(Err(e))),
};
let fut = method(lua, ud.get_mut(), args);
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
}
_ => {
let err = Error::bad_self_argument(&name, Error::UserDataTypeMismatch);
Box::pin(future::ready(Err(err)))
}
Box::new(move |rawlua, nargs| unsafe {
if nargs == 0 {
let err = Error::from_lua_conversion("missing argument", "userdata", None);
try_self_arg!(Err(err));
}
// Stack will be empty when polling the future, keep `self` on the ref thread
let self_ud = try_self_arg!(AnyUserData::from_stack(-nargs, rawlua));
let args = A::from_stack_args(nargs - 1, 2, Some(&name), rawlua);
let self_ud = try_self_arg!(self_ud.borrow_mut());
let args = match args {
Ok(args) => args,
Err(e) => return Box::pin(future::ready(Err(e))),
};
let lua = rawlua.lua().clone();
let fut = method(lua.clone(), self_ud, args);
// Lua is locked when the future is polled
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
})
}
fn box_function<F, A, R>(name: &str, function: F) -> Callback<'a>
fn box_function<F, A, R>(name: &str, function: F) -> Callback
where
F: Fn(&'a Lua, A) -> Result<R> + MaybeSend + 'static,
F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti,
{
@@ -228,9 +220,9 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
})
}
fn box_function_mut<F, A, R>(name: &str, function: F) -> Callback<'a>
fn box_function_mut<F, A, R>(name: &str, function: F) -> Callback
where
F: FnMut(&'a Lua, A) -> Result<R> + MaybeSend + 'static,
F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti,
{
@@ -246,20 +238,21 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
}
#[cfg(feature = "async")]
fn box_async_function<F, A, FR, R>(name: &str, function: F) -> AsyncCallback<'a>
fn box_async_function<F, A, FR, R>(name: &str, function: F) -> AsyncCallback
where
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
F: Fn(Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
FR: Future<Output = Result<R>> + MaybeSend + 'a,
FR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti,
{
let name = get_function_name::<T>(name);
Box::new(move |lua, args| unsafe {
let args = match A::from_lua_args(args, 1, Some(&name), lua) {
Box::new(move |rawlua, nargs| unsafe {
let args = match A::from_stack_args(nargs, 1, Some(&name), rawlua) {
Ok(args) => args,
Err(e) => return Box::pin(future::ready(Err(e))),
};
let fut = function(lua, args);
let lua = rawlua.lua().clone();
let fut = function(lua.clone(), args);
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
})
}
@@ -287,19 +280,19 @@ fn get_function_name<T>(name: &str) -> StdString {
format!("{}.{name}", short_type_name::<T>())
}
impl<'a, T: 'static> UserDataFields<'a, T> for UserDataRegistry<'a, T> {
impl<T: 'static> UserDataFields<T> for UserDataRegistry<T> {
fn add_field<V>(&mut self, name: impl ToString, value: V)
where
V: IntoLua + Clone + 'static,
{
let name = name.to_string();
let callback = Box::new(move |lua, _| unsafe { value.clone().push_into_stack_multi(lua) });
let callback: Callback = Box::new(move |lua, _| unsafe { value.clone().push_into_stack_multi(lua) });
self.fields.push((name, callback));
}
fn add_field_method_get<M, R>(&mut self, name: impl ToString, method: M)
where
M: Fn(&'a Lua, &T) -> Result<R> + MaybeSend + 'static,
M: Fn(&Lua, &T) -> Result<R> + MaybeSend + 'static,
R: IntoLua,
{
let name = name.to_string();
@@ -309,7 +302,7 @@ impl<'a, T: 'static> UserDataFields<'a, T> for UserDataRegistry<'a, T> {
fn add_field_method_set<M, A>(&mut self, name: impl ToString, method: M)
where
M: FnMut(&'a Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
M: FnMut(&Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
A: FromLua,
{
let name = name.to_string();
@@ -319,7 +312,7 @@ impl<'a, T: 'static> UserDataFields<'a, T> for UserDataRegistry<'a, T> {
fn add_field_function_get<F, R>(&mut self, name: impl ToString, function: F)
where
F: Fn(&'a Lua, AnyUserData) -> Result<R> + MaybeSend + 'static,
F: Fn(&Lua, AnyUserData) -> Result<R> + MaybeSend + 'static,
R: IntoLua,
{
let name = name.to_string();
@@ -329,7 +322,7 @@ impl<'a, T: 'static> UserDataFields<'a, T> for UserDataRegistry<'a, T> {
fn add_field_function_set<F, A>(&mut self, name: impl ToString, mut function: F)
where
F: FnMut(&'a Lua, AnyUserData, A) -> Result<()> + MaybeSend + 'static,
F: FnMut(&Lua, AnyUserData, A) -> Result<()> + MaybeSend + 'static,
A: FromLua,
{
let name = name.to_string();
@@ -352,7 +345,7 @@ impl<'a, T: 'static> UserDataFields<'a, T> for UserDataRegistry<'a, T> {
fn add_meta_field_with<F, R>(&mut self, name: impl ToString, f: F)
where
F: Fn(&'a Lua) -> Result<R> + MaybeSend + 'static,
F: Fn(&Lua) -> Result<R> + MaybeSend + 'static,
R: IntoLua,
{
let name = name.to_string();
@@ -366,10 +359,10 @@ impl<'a, T: 'static> UserDataFields<'a, T> for UserDataRegistry<'a, T> {
}
}
impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
impl<T: 'static> UserDataMethods<T> for UserDataRegistry<T> {
fn add_method<M, A, R>(&mut self, name: impl ToString, method: M)
where
M: Fn(&'a Lua, &T, A) -> Result<R> + MaybeSend + 'static,
M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti,
{
@@ -380,7 +373,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
fn add_method_mut<M, A, R>(&mut self, name: impl ToString, method: M)
where
M: FnMut(&'a Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti,
{
@@ -392,9 +385,9 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
#[cfg(feature = "async")]
fn add_async_method<M, A, MR, R>(&mut self, name: impl ToString, method: M)
where
M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static,
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti,
{
let name = name.to_string();
@@ -405,9 +398,9 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
#[cfg(feature = "async")]
fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl ToString, method: M)
where
M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static,
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti,
{
let name = name.to_string();
@@ -417,7 +410,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
fn add_function<F, A, R>(&mut self, name: impl ToString, function: F)
where
F: Fn(&'a Lua, A) -> Result<R> + MaybeSend + 'static,
F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti,
{
@@ -428,7 +421,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
fn add_function_mut<F, A, R>(&mut self, name: impl ToString, function: F)
where
F: FnMut(&'a Lua, A) -> Result<R> + MaybeSend + 'static,
F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti,
{
@@ -440,9 +433,9 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
#[cfg(feature = "async")]
fn add_async_function<F, A, FR, R>(&mut self, name: impl ToString, function: F)
where
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
F: Fn(Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
FR: Future<Output = Result<R>> + MaybeSend + 'a,
FR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti,
{
let name = name.to_string();
@@ -452,7 +445,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
fn add_meta_method<M, A, R>(&mut self, name: impl ToString, method: M)
where
M: Fn(&'a Lua, &T, A) -> Result<R> + MaybeSend + 'static,
M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti,
{
@@ -463,7 +456,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
fn add_meta_method_mut<M, A, R>(&mut self, name: impl ToString, method: M)
where
M: FnMut(&'a Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti,
{
@@ -475,9 +468,9 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
#[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
M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static,
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti,
{
let name = name.to_string();
@@ -488,9 +481,9 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
#[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
M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static,
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti,
{
let name = name.to_string();
@@ -500,7 +493,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
fn add_meta_function<F, A, R>(&mut self, name: impl ToString, function: F)
where
F: Fn(&'a Lua, A) -> Result<R> + MaybeSend + 'static,
F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti,
{
@@ -511,7 +504,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
fn add_meta_function_mut<F, A, R>(&mut self, name: impl ToString, function: F)
where
F: FnMut(&'a Lua, A) -> Result<R> + MaybeSend + 'static,
F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
R: IntoLuaMulti,
{
@@ -523,9 +516,9 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl ToString, function: F)
where
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
F: Fn(Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
FR: Future<Output = Result<R>> + MaybeSend + 'a,
FR: Future<Output = Result<R>> + MaybeSend + 'static,
R: IntoLuaMulti,
{
let name = name.to_string();
+2 -2
View File
@@ -21,7 +21,7 @@ impl TypeKey for String {
static CALLBACK_TYPE_KEY: u8 = 0;
impl TypeKey for Callback<'static> {
impl TypeKey for Callback {
#[inline(always)]
fn type_key() -> *const c_void {
&CALLBACK_TYPE_KEY as *const u8 as *const c_void
@@ -41,7 +41,7 @@ impl TypeKey for CallbackUpvalue {
static ASYNC_CALLBACK_TYPE_KEY: u8 = 0;
#[cfg(feature = "async")]
impl TypeKey for AsyncCallback<'static> {
impl TypeKey for AsyncCallback {
#[inline(always)]
fn type_key() -> *const c_void {
&ASYNC_CALLBACK_TYPE_KEY as *const u8 as *const c_void