From 9931709ecda99daa16444cacf22fa0e89b9bd78c Mon Sep 17 00:00:00 2001 From: Alex Orlenko Date: Fri, 23 Aug 2024 00:05:24 +0100 Subject: [PATCH] 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). --- Cargo.toml | 2 +- benches/benchmark.rs | 6 +- examples/async_http_client.rs | 4 +- examples/async_http_server.rs | 2 +- examples/async_tcp_server.rs | 8 +- examples/guided_tour.rs | 2 +- examples/userdata.rs | 4 +- src/function.rs | 13 +- src/state.rs | 27 ++-- src/state/raw.rs | 5 +- src/types.rs | 12 +- src/userdata.rs | 76 +++++----- src/userdata/cell.rs | 251 +++++++++++++++------------------- src/userdata/lock.rs | 93 +++++++++++++ src/userdata/registry.rs | 211 ++++++++++++++-------------- src/util/types.rs | 4 +- tests/async.rs | 8 +- tests/userdata.rs | 36 ++--- 18 files changed, 403 insertions(+), 361 deletions(-) create mode 100644 src/userdata/lock.rs diff --git a/Cargo.toml b/Cargo.toml index 042260fd..3936a4b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ luau-vector4 = ["luau", "ffi/luau-vector4"] vendored = ["ffi/vendored"] module = ["dep:mlua_derive", "ffi/module"] async = ["dep:futures-util"] -send = [] +send = ["parking_lot/send_guard"] serialize = ["dep:serde", "dep:erased-serde", "dep:serde-value"] macros = ["mlua_derive/macros"] unstable = [] diff --git a/benches/benchmark.rs b/benches/benchmark.rs index 5c86bcb5..b5bb2b38 100644 --- a/benches/benchmark.rs +++ b/benches/benchmark.rs @@ -297,7 +297,7 @@ fn userdata_create(c: &mut Criterion) { fn userdata_call_index(c: &mut Criterion) { struct UserData(#[allow(unused)] i64); impl LuaUserData for UserData { - fn add_methods<'a, M: LuaUserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_meta_method(LuaMetaMethod::Index, move |_, _, key: LuaString| Ok(key)); } } @@ -323,7 +323,7 @@ fn userdata_call_index(c: &mut Criterion) { fn userdata_call_method(c: &mut Criterion) { struct UserData(i64); impl LuaUserData for UserData { - fn add_methods<'a, M: LuaUserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_method("add", |_, this, i: i64| Ok(this.0 + i)); } } @@ -353,7 +353,7 @@ fn userdata_call_method(c: &mut Criterion) { fn userdata_async_call_method(c: &mut Criterion) { struct UserData(i64); impl LuaUserData for UserData { - fn add_methods<'a, M: LuaUserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_async_method("add", |_, this, i: i64| async move { task::yield_now().await; Ok(this.0 + i) diff --git a/examples/async_http_client.rs b/examples/async_http_client.rs index ca4eac9a..86568127 100644 --- a/examples/async_http_client.rs +++ b/examples/async_http_client.rs @@ -10,9 +10,9 @@ use mlua::{chunk, ExternalResult, Lua, Result, UserData, UserDataMethods}; struct BodyReader(Incoming); impl UserData for BodyReader { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { // Every call returns a next chunk - methods.add_async_method_mut("read", |lua, reader, ()| async move { + methods.add_async_method_mut("read", |lua, mut reader, ()| async move { if let Some(bytes) = reader.0.frame().await { if let Some(bytes) = bytes.into_lua_err()?.data_ref() { return Some(lua.create_string(&bytes)).transpose(); diff --git a/examples/async_http_server.rs b/examples/async_http_server.rs index 5eb8c970..244a8e4e 100644 --- a/examples/async_http_server.rs +++ b/examples/async_http_server.rs @@ -17,7 +17,7 @@ use mlua::{chunk, Error as LuaError, Function, Lua, String as LuaString, Table, struct LuaRequest(SocketAddr, Request); impl UserData for LuaRequest { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_method("remote_addr", |_, req, ()| Ok((req.0).to_string())); methods.add_method("method", |_, req, ()| Ok((req.1).method().to_string())); methods.add_method("path", |_, req, ()| Ok(req.1.uri().path().to_string())); diff --git a/examples/async_tcp_server.rs b/examples/async_tcp_server.rs index 7ceb3120..7d96dbe2 100644 --- a/examples/async_tcp_server.rs +++ b/examples/async_tcp_server.rs @@ -9,22 +9,22 @@ use mlua::{chunk, BString, Function, Lua, UserData, UserDataMethods}; struct LuaTcpStream(TcpStream); impl UserData for LuaTcpStream { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_method("peer_addr", |_, this, ()| Ok(this.0.peer_addr()?.to_string())); - methods.add_async_method_mut("read", |lua, this, size| async move { + methods.add_async_method_mut("read", |lua, mut this, size| async move { let mut buf = vec![0; size]; let n = this.0.read(&mut buf).await?; buf.truncate(n); lua.create_string(&buf) }); - methods.add_async_method_mut("write", |_, this, data: BString| async move { + methods.add_async_method_mut("write", |_, mut this, data: BString| async move { let n = this.0.write(&data).await?; Ok(n) }); - methods.add_async_method_mut("close", |_, this, ()| async move { + methods.add_async_method_mut("close", |_, mut this, ()| async move { this.0.shutdown().await?; Ok(()) }); diff --git a/examples/guided_tour.rs b/examples/guided_tour.rs index 26706e8d..dd4c649a 100644 --- a/examples/guided_tour.rs +++ b/examples/guided_tour.rs @@ -162,7 +162,7 @@ fn main() -> Result<()> { } impl UserData for Vec2 { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_method("magnitude", |_, vec, ()| { let mag_squared = vec.0 * vec.0 + vec.1 * vec.1; Ok(mag_squared.sqrt()) diff --git a/examples/userdata.rs b/examples/userdata.rs index 8823dfd5..a5cc8ba4 100644 --- a/examples/userdata.rs +++ b/examples/userdata.rs @@ -7,7 +7,7 @@ struct Rectangle { } impl UserData for Rectangle { - fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fn add_fields>(fields: &mut F) { fields.add_field_method_get("length", |_, this| Ok(this.length)); fields.add_field_method_set("length", |_, this, val| { this.length = val; @@ -20,7 +20,7 @@ impl UserData for Rectangle { }); } - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_method("area", |_, this, ()| Ok(this.length * this.width)); methods.add_method("diagonal", |_, this, ()| { Ok((this.length.pow(2) as f64 + this.width.pow(2) as f64).sqrt()) diff --git a/src/function.rs b/src/function.rs index 2d3e37f1..95cb43a7 100644 --- a/src/function.rs +++ b/src/function.rs @@ -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> + 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()) }) })) } diff --git a/src/state.rs b/src/state.rs index ae479d2d..4db87f29 100644 --- a/src/state.rs +++ b/src/state.rs @@ -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 + pub fn create_async_function(&self, func: F) -> Result where - 'lua: 'a, - F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static, + F: Fn(Lua, A) -> FR + MaybeSend + 'static, A: FromLuaMulti, - FR: Future> + MaybeSend + 'a, + FR: Future> + 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>(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>(methods: &mut M) { /// methods.add_function("new", |_, value: i32| Ok(MyUserData(value))); /// } /// } diff --git a/src/state/raw.rs b/src/state/raw.rs index 45c35ad9..795dc2b0 100644 --- a/src/state/raw.rs +++ b/src/state/raw.rs @@ -1053,7 +1053,6 @@ impl RawLua { let _sg = StackGuard::new(state); check_stack(state, 4)?; - let func = mem::transmute::>(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::>(func); let extra = XRc::clone(&self.extra); let protect = !self.unlikely_memory_error(); let upvalue = AsyncCallbackUpvalue { data: func, extra }; diff --git a/src/types.rs b/src/types.rs index 8462a092..89bd75b9 100644 --- a/src/types.rs +++ b/src/types.rs @@ -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 Result + 'static>; +pub(crate) type Callback = Box Result + 'static>; pub(crate) struct Upvalue { pub(crate) data: T, pub(crate) extra: XRc>, } -pub(crate) type CallbackUpvalue = Upvalue>; +pub(crate) type CallbackUpvalue = Upvalue; #[cfg(feature = "async")] -pub(crate) type AsyncCallback<'a> = - Box BoxFuture<'a, Result> + 'static>; +pub(crate) type AsyncCallback = Box BoxFuture<'static, Result> + 'static>; #[cfg(feature = "async")] -pub(crate) type AsyncCallbackUpvalue = Upvalue>; +pub(crate) type AsyncCallbackUpvalue = Upvalue; #[cfg(feature = "async")] pub(crate) type AsyncPollUpvalue = Upvalue>>; diff --git a/src/userdata.rs b/src/userdata.rs index 2ebe46bc..5e8b5a52 100644 --- a/src/userdata.rs +++ b/src/userdata.rs @@ -248,7 +248,7 @@ impl AsRef for MetaMethod { /// Method registry for [`UserData`] implementors. /// /// [`UserData`]: crate::UserData -pub trait UserDataMethods<'a, T> { +pub trait UserDataMethods { /// 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(&mut self, name: impl ToString, method: M) where - M: Fn(&'a Lua, &T, A) -> Result + MaybeSend + 'static, + M: Fn(&Lua, &T, A) -> Result + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti; @@ -269,7 +269,7 @@ pub trait UserDataMethods<'a, T> { /// [`add_method`]: #method.add_method fn add_method_mut(&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: FromLuaMulti, R: IntoLuaMulti; @@ -285,9 +285,9 @@ pub trait UserDataMethods<'a, T> { fn add_async_method(&mut self, name: impl ToString, method: M) where T: 'static, - M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static, + M: Fn(Lua, UserDataRef, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, - MR: Future> + MaybeSend + 'a, + MR: Future> + 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(&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, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, - MR: Future> + MaybeSend + 'a, + MR: Future> + 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(&mut self, name: impl ToString, function: F) where - F: Fn(&'a Lua, A) -> Result + MaybeSend + 'static, + F: Fn(&Lua, A) -> Result + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti; @@ -330,7 +330,7 @@ pub trait UserDataMethods<'a, T> { /// [`add_function`]: #method.add_function fn add_function_mut(&mut self, name: impl ToString, function: F) where - F: FnMut(&'a Lua, A) -> Result + MaybeSend + 'static, + F: FnMut(&Lua, A) -> Result + 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(&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> + MaybeSend + 'a, + FR: Future> + 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(&mut self, name: impl ToString, method: M) where - M: Fn(&'a Lua, &T, A) -> Result + MaybeSend + 'static, + M: Fn(&Lua, &T, A) -> Result + 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(&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: FromLuaMulti, R: IntoLuaMulti; @@ -391,9 +391,9 @@ pub trait UserDataMethods<'a, T> { fn add_async_meta_method(&mut self, name: impl ToString, method: M) where T: 'static, - M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static, + M: Fn(Lua, UserDataRef, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, - MR: Future> + MaybeSend + 'a, + MR: Future> + 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(&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, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, - MR: Future> + MaybeSend + 'a, + MR: Future> + 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(&mut self, name: impl ToString, function: F) where - F: Fn(&'a Lua, A) -> Result + MaybeSend + 'static, + F: Fn(&Lua, A) -> Result + 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(&mut self, name: impl ToString, function: F) where - F: FnMut(&'a Lua, A) -> Result + MaybeSend + 'static, + F: FnMut(&Lua, A) -> Result + 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(&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> + MaybeSend + 'a, + FR: Future> + MaybeSend + 'static, R: IntoLuaMulti; } /// Field registry for [`UserData`] implementors. /// /// [`UserData`]: crate::UserData -pub trait UserDataFields<'a, T> { +pub trait UserDataFields { /// 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(&mut self, name: impl ToString, method: M) where - M: Fn(&'a Lua, &T) -> Result + MaybeSend + 'static, + M: Fn(&Lua, &T) -> Result + 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(&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(&mut self, name: impl ToString, function: F) where - F: Fn(&'a Lua, AnyUserData) -> Result + MaybeSend + 'static, + F: Fn(&Lua, AnyUserData) -> Result + 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(&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(&mut self, name: impl ToString, f: F) where - F: Fn(&'a Lua) -> Result + MaybeSend + 'static, + F: Fn(&Lua) -> Result + 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>(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>(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>(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>(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(&self) -> Result> { - 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(&self) -> Result> { - 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> { - 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> { match self.1 { @@ -1182,6 +1175,7 @@ where mod cell; mod ext; +mod lock; mod registry; #[cfg(test)] diff --git a/src/userdata/cell.rs b/src/userdata/cell.rs index 61d87e2d..c327a86d 100644 --- a/src/userdata/cell.rs +++ b/src/userdata/cell.rs @@ -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 { - Default(Rc>), + Default(XRc>), #[cfg(feature = "serialize")] - Serializable(Rc>>), + Serializable(XRc>>>), } impl Clone for UserDataVariant { #[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 Clone for UserDataVariant { impl UserDataVariant { #[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> { + pub(crate) fn try_borrow(&self) -> Result> { 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::try_from(self.clone(), guard) + pub(crate) fn try_borrow_owned(&self) -> Result> { + UserDataRef::try_from(self.clone()) } // Mutably borrows the wrapped value in-place. #[inline(always)] - pub(crate) unsafe fn try_borrow_mut(&self) -> Result> { + pub(crate) fn try_borrow_mut(&self) -> Result> { 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::try_from(self.clone(), guard) + pub(crate) fn try_borrow_owned_mut(&self) -> Result> { + 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 { - 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 { + 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 UserDataVariant { } #[cfg(feature = "serialize")] -impl UserDataVariant { +impl UserDataVariant { #[inline(always)] pub(crate) fn new_ser(data: T) -> Self { - let data = Box::new(data) as Box; - Self::Serializable(Rc::new(InnerRefCell::new(data))) + let data = Box::new(data) as Box; + let data = ForceSync(data); + Self::Serializable(XRc::new(UserDataCell::new(data))) } } @@ -110,29 +121,34 @@ impl UserDataVariant { impl Serialize for UserDataVariant<()> { fn serialize(&self, serializer: S) -> std::result::Result { match self { - UserDataVariant::Default(_) => Err(serde::ser::Error::custom("cannot serialize ")), - 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 ")), + 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 { - borrow: Cell, +/// A type that provides interior mutability for a userdata value (thread-safe). +pub(crate) struct UserDataCell { + raw_lock: RawLock, value: UnsafeCell, } -impl InnerRefCell { +unsafe impl Send for UserDataCell {} +unsafe impl Sync for UserDataCell {} + +impl UserDataCell { #[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 InnerRefCell { /// 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 { - variant: UserDataVariant, - #[allow(unused)] - guard: LuaGuard, -} +pub struct UserDataRef(UserDataVariant); impl Deref for UserDataRef { type Target = T; #[inline] fn deref(&self) -> &T { - unsafe { &*self.variant.as_ptr() } + unsafe { &*self.0.as_ptr() } } } impl Drop for UserDataRef { #[inline] fn drop(&mut self) { - unset_reading(self.variant.flag()); + unsafe { self.0.raw_lock().unlock_shared() }; } } @@ -175,11 +187,15 @@ impl fmt::Display for UserDataRef { } } -impl UserDataRef { +impl TryFrom> for UserDataRef { + type Error = Error; + #[inline] - fn try_from(variant: UserDataVariant, guard: LuaGuard) -> Result { - set_reading(variant.flag())?; - Ok(UserDataRef { variant, guard }) + fn try_from(variant: UserDataVariant) -> Result { + if !variant.raw_lock().try_lock_shared() { + return Err(Error::UserDataBorrowError); + } + Ok(UserDataRef(variant)) } } @@ -192,8 +208,7 @@ impl FromLua for UserDataRef { let type_id = lua.get_userdata_type_id(idx)?; match type_id { Some(type_id) if type_id == TypeId::of::() => { - let guard = lua.lua().lock_arc(); - (*get_userdata::>(lua.state(), idx)).try_make_ref(guard) + (*get_userdata::>(lua.state(), idx)).try_borrow_owned() } _ => Err(Error::UserDataTypeMismatch), } @@ -203,32 +218,28 @@ impl FromLua for UserDataRef { /// 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 { - variant: UserDataVariant, - #[allow(unused)] - guard: LuaGuard, -} +pub struct UserDataRefMut(UserDataVariant); impl Deref for UserDataRefMut { type Target = T; #[inline] fn deref(&self) -> &Self::Target { - unsafe { &*self.variant.as_ptr() } + unsafe { &*self.0.as_ptr() } } } impl DerefMut for UserDataRefMut { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *self.variant.as_ptr() } + unsafe { &mut *self.0.as_ptr() } } } impl Drop for UserDataRefMut { #[inline] fn drop(&mut self) { - unset_writing(self.variant.flag()); + unsafe { self.0.raw_lock().unlock_exclusive() }; } } @@ -244,11 +255,15 @@ impl fmt::Display for UserDataRefMut { } } -impl UserDataRefMut { - fn try_from(variant: UserDataVariant, guard: LuaGuard) -> Result { - // There must currently be no existing references - set_writing(variant.flag())?; - Ok(UserDataRefMut { variant, guard }) +impl TryFrom> for UserDataRefMut { + type Error = Error; + + #[inline] + fn try_from(variant: UserDataVariant) -> Result { + if !variant.raw_lock().try_lock_exclusive() { + return Err(Error::UserDataBorrowMutError); + } + Ok(UserDataRefMut(variant)) } } @@ -261,73 +276,20 @@ impl FromLua for UserDataRefMut { let type_id = lua.get_userdata_type_id(idx)?; match type_id { Some(type_id) if type_id == TypeId::of::() => { - let guard = lua.lua().lock_arc(); - (*get_userdata::>(lua.state(), idx)).try_make_mut_ref(guard) + (*get_userdata::>(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) -> Result<()> { - let flag = borrow.get(); - if flag != UNUSED { - return Err(Error::UserDataBorrowMutError); - } - borrow.set(UNUSED - 1); - Ok(()) -} - -#[inline(always)] -fn set_reading(borrow: &Cell) -> 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) { - let flag = borrow.get(); - debug_assert!(is_writing(flag)); - borrow.set(flag + 1); -} - -#[inline(always)] -#[track_caller] -fn unset_reading(borrow: &Cell) { - 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); 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> for UserDataBorrowRef<'a, T> { #[inline(always)] fn try_from(variant: &'a UserDataVariant) -> Result { - 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); 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> for UserDataBorrowMut<'a, T> { #[inline(always)] fn try_from(variant: &'a UserDataVariant) -> Result { - 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); + +unsafe impl Sync for ForceSync {} #[inline] fn try_value_to_userdata(value: Value) -> Result { @@ -417,6 +373,25 @@ fn try_value_to_userdata(value: Value) -> Result { 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>: Send, Sync); + #[cfg(feature = "send")] + static_assertions::assert_impl_all!(UserDataRefMut<()>: Sync, Send); + #[cfg(feature = "send")] + static_assertions::assert_not_impl_all!(UserDataRefMut>: 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); } diff --git a/src/userdata/lock.rs b/src/userdata/lock.rs new file mode 100644 index 00000000..7ddf6be4 --- /dev/null +++ b/src/userdata/lock.rs @@ -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; + + 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 = ::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) + } + } +} diff --git a/src/userdata/registry.rs b/src/userdata/registry.rs index de31f307..c7b236f8 100644 --- a/src/userdata/registry.rs +++ b/src/userdata/registry.rs @@ -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 { // 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, } -impl<'a, T: 'static> UserDataRegistry<'a, T> { +impl UserDataRegistry { pub(crate) const fn new() -> Self { UserDataRegistry { fields: Vec::new(), @@ -57,9 +59,9 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> { } } - fn box_method(name: &str, method: M) -> Callback<'a> + fn box_method(name: &str, method: M) -> Callback where - M: Fn(&'a Lua, &T, A) -> Result + MaybeSend + 'static, + M: Fn(&Lua, &T, A) -> Result + 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::() => { - let ud = try_self_arg!(borrow_userdata_ref::(state, index)); + let ud = try_self_arg!(borrow_userdata_ref::(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(name: &str, method: M) -> Callback<'a> + fn box_method_mut(name: &str, method: M) -> Callback where - M: FnMut(&'a Lua, &mut T, A) -> Result + MaybeSend + 'static, + M: FnMut(&Lua, &mut T, A) -> Result + 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::() => { - let mut ud = try_self_arg!(borrow_userdata_mut::(state, index)); + let mut ud = try_self_arg!(borrow_userdata_mut::(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(name: &str, method: M) -> AsyncCallback<'a> + fn box_async_method(name: &str, method: M) -> AsyncCallback where - M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static, + M: Fn(Lua, UserDataRef, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, - MR: Future> + MaybeSend + 'a, + MR: Future> + MaybeSend + 'static, R: IntoLuaMulti, { let name = get_function_name::(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::() => { - let ud = try_self_arg!(borrow_userdata_ref::(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(name: &str, method: M) -> AsyncCallback<'a> + fn box_async_method_mut(name: &str, method: M) -> AsyncCallback where - M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static, + M: Fn(Lua, UserDataRefMut, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, - MR: Future> + MaybeSend + 'a, + MR: Future> + MaybeSend + 'static, R: IntoLuaMulti, { let name = get_function_name::(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::() => { - let mut ud = try_self_arg!(borrow_userdata_mut::(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(name: &str, function: F) -> Callback<'a> + fn box_function(name: &str, function: F) -> Callback where - F: Fn(&'a Lua, A) -> Result + MaybeSend + 'static, + F: Fn(&Lua, A) -> Result + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti, { @@ -228,9 +220,9 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> { }) } - fn box_function_mut(name: &str, function: F) -> Callback<'a> + fn box_function_mut(name: &str, function: F) -> Callback where - F: FnMut(&'a Lua, A) -> Result + MaybeSend + 'static, + F: FnMut(&Lua, A) -> Result + MaybeSend + 'static, A: FromLuaMulti, R: IntoLuaMulti, { @@ -246,20 +238,21 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> { } #[cfg(feature = "async")] - fn box_async_function(name: &str, function: F) -> AsyncCallback<'a> + fn box_async_function(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> + MaybeSend + 'a, + FR: Future> + MaybeSend + 'static, R: IntoLuaMulti, { let name = get_function_name::(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(name: &str) -> StdString { format!("{}.{name}", short_type_name::()) } -impl<'a, T: 'static> UserDataFields<'a, T> for UserDataRegistry<'a, T> { +impl UserDataFields for UserDataRegistry { fn add_field(&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(&mut self, name: impl ToString, method: M) where - M: Fn(&'a Lua, &T) -> Result + MaybeSend + 'static, + M: Fn(&Lua, &T) -> Result + 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(&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(&mut self, name: impl ToString, function: F) where - F: Fn(&'a Lua, AnyUserData) -> Result + MaybeSend + 'static, + F: Fn(&Lua, AnyUserData) -> Result + 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(&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(&mut self, name: impl ToString, f: F) where - F: Fn(&'a Lua) -> Result + MaybeSend + 'static, + F: Fn(&Lua) -> Result + 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 UserDataMethods for UserDataRegistry { fn add_method(&mut self, name: impl ToString, method: M) where - M: Fn(&'a Lua, &T, A) -> Result + MaybeSend + 'static, + M: Fn(&Lua, &T, A) -> Result + 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(&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: 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(&mut self, name: impl ToString, method: M) where - M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static, + M: Fn(Lua, UserDataRef, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, - MR: Future> + MaybeSend + 'a, + MR: Future> + 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(&mut self, name: impl ToString, method: M) where - M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static, + M: Fn(Lua, UserDataRefMut, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, - MR: Future> + MaybeSend + 'a, + MR: Future> + 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(&mut self, name: impl ToString, function: F) where - F: Fn(&'a Lua, A) -> Result + MaybeSend + 'static, + F: Fn(&Lua, A) -> Result + 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(&mut self, name: impl ToString, function: F) where - F: FnMut(&'a Lua, A) -> Result + MaybeSend + 'static, + F: FnMut(&Lua, A) -> Result + 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(&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> + MaybeSend + 'a, + FR: Future> + 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(&mut self, name: impl ToString, method: M) where - M: Fn(&'a Lua, &T, A) -> Result + MaybeSend + 'static, + M: Fn(&Lua, &T, A) -> Result + 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(&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: 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(&mut self, name: impl ToString, method: M) where - M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static, + M: Fn(Lua, UserDataRef, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, - MR: Future> + MaybeSend + 'a, + MR: Future> + 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(&mut self, name: impl ToString, method: M) where - M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static, + M: Fn(Lua, UserDataRefMut, A) -> MR + MaybeSend + 'static, A: FromLuaMulti, - MR: Future> + MaybeSend + 'a, + MR: Future> + 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(&mut self, name: impl ToString, function: F) where - F: Fn(&'a Lua, A) -> Result + MaybeSend + 'static, + F: Fn(&Lua, A) -> Result + 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(&mut self, name: impl ToString, function: F) where - F: FnMut(&'a Lua, A) -> Result + MaybeSend + 'static, + F: FnMut(&Lua, A) -> Result + 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(&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> + MaybeSend + 'a, + FR: Future> + MaybeSend + 'static, R: IntoLuaMulti, { let name = name.to_string(); diff --git a/src/util/types.rs b/src/util/types.rs index d8705411..829b7e9d 100644 --- a/src/util/types.rs +++ b/src/util/types.rs @@ -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 diff --git a/tests/async.rs b/tests/async.rs index 038d14fb..59e178da 100644 --- a/tests/async.rs +++ b/tests/async.rs @@ -378,13 +378,13 @@ async fn test_async_userdata() -> Result<()> { struct MyUserData(u64); impl UserData for MyUserData { - fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_async_method("get_value", |_, data, ()| async move { sleep_ms(10).await; Ok(data.0) }); - methods.add_async_method_mut("set_value", |_, data, n| async move { + methods.add_async_method_mut("set_value", |_, mut data, n| async move { sleep_ms(10).await; data.0 = n; Ok(()) @@ -415,7 +415,7 @@ async fn test_async_userdata() -> Result<()> { #[cfg(not(any(feature = "lua51", feature = "luau")))] methods.add_async_meta_method_mut( mlua::MetaMethod::NewIndex, - |_, data, (key, value): (String, f64)| async move { + |_, mut data, (key, value): (String, f64)| async move { sleep_ms(10).await; match key.as_str() { "ms" => data.0 = value as u64, @@ -477,7 +477,7 @@ async fn test_async_thread_error() -> Result<()> { struct MyUserData; impl UserData for MyUserData { - fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_meta_method("__tostring", |_, _this, ()| Ok("myuserdata error")) } } diff --git a/tests/userdata.rs b/tests/userdata.rs index f925e20f..925c5bd8 100644 --- a/tests/userdata.rs +++ b/tests/userdata.rs @@ -39,7 +39,7 @@ fn test_methods() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { - fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_method("get_value", |_, data, ()| Ok(data.0)); methods.add_method_mut("set_value", |_, data, args| { data.0 = args; @@ -89,7 +89,7 @@ fn test_method_variadic() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { - fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_method("get", |_, data, ()| Ok(data.0)); methods.add_method_mut("add", |_, data, vals: Variadic| { data.0 += vals.into_iter().sum::(); @@ -114,7 +114,7 @@ fn test_metamethods() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { - fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_method("get", |_, data, ()| Ok(data.0)); methods.add_meta_function( MetaMethod::Add, @@ -213,7 +213,7 @@ fn test_metamethod_close() -> Result<()> { struct MyUserData(Arc); impl UserData for MyUserData { - fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_method("get", |_, data, ()| Ok(data.0.load(Ordering::Relaxed))); methods.add_meta_method(MetaMethod::Close, |_, data, _err: Value| { data.0.store(0, Ordering::Relaxed); @@ -259,7 +259,7 @@ fn test_gc_userdata() -> Result<()> { } impl UserData for MyUserdata { - fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_method("access", |_, this, ()| { assert!(this.id == 123); Ok(()) @@ -298,7 +298,7 @@ fn test_userdata_take() -> Result<()> { struct MyUserdata(Arc); impl UserData for MyUserdata { - fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_method("num", |_, this, ()| Ok(*this.0)) } } @@ -433,7 +433,7 @@ fn test_functions() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { - fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_function("get_value", |_, ud: AnyUserData| Ok(ud.borrow::()?.0)); methods.add_function_mut("set_value", |_, (ud, value): (AnyUserData, i64)| { ud.borrow_mut::()?.0 = value; @@ -485,7 +485,7 @@ fn test_fields() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { - fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) { + fn add_fields>(fields: &mut F) { fields.add_field("static", "constant"); fields.add_field_method_get("val", |_, data| Ok(data.0)); fields.add_field_method_set("val", |_, data, val| { @@ -531,12 +531,12 @@ fn test_fields() -> Result<()> { struct MyUserData2(i64); impl UserData for MyUserData2 { - fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) { + fn add_fields>(fields: &mut F) { fields.add_field("z", 0); fields.add_field_method_get("x", |_, data| Ok(data.0)); } - fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_meta_method(MetaMethod::Index, |_, _, name: StdString| match &*name { "y" => Ok(Some(-1)), _ => Ok(None), @@ -563,7 +563,7 @@ fn test_metatable() -> Result<()> { struct MyUserData; impl UserData for MyUserData { - fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_function("my_type_name", |_, data: AnyUserData| { let metatable = data.get_metatable()?; metatable.get::(MetaMethod::Type) @@ -608,7 +608,7 @@ fn test_metatable() -> Result<()> { struct MyUserData2; impl UserData for MyUserData2 { - fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) { + fn add_fields>(fields: &mut F) { fields.add_meta_field_with("__index", |_| Ok(1)); } } @@ -623,7 +623,7 @@ fn test_metatable() -> Result<()> { struct MyUserData3; impl UserData for MyUserData3 { - fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) { + fn add_fields>(fields: &mut F) { fields.add_meta_field_with(MetaMethod::Type, |_| Ok("CustomName")); } } @@ -640,12 +640,12 @@ fn test_userdata_proxy() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { - fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) { + fn add_fields>(fields: &mut F) { fields.add_field("static_field", 123); fields.add_field_method_get("n", |_, this| Ok(this.0)); } - fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_function("new", |_, n| Ok(Self(n))); methods.add_method("plus", |_, this, n: i64| Ok(this.0 + n)); @@ -733,7 +733,7 @@ fn test_userdata_ext() -> Result<()> { struct MyUserData(u32); impl UserData for MyUserData { - fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) { + fn add_fields>(fields: &mut F) { fields.add_field_method_get("n", |_, this| Ok(this.0)); fields.add_field_method_set("n", |_, this, val| { this.0 = val; @@ -741,7 +741,7 @@ fn test_userdata_ext() -> Result<()> { }); } - fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_meta_method(MetaMethod::Call, |_, _this, ()| Ok("called")); methods.add_method_mut("add", |_, this, x: u32| { this.0 += x; @@ -774,7 +774,7 @@ fn test_userdata_method_errors() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { - fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { + fn add_methods>(methods: &mut M) { methods.add_method("get_value", |_, data, ()| Ok(data.0)); } }