diff options
author | Alex Orlenko <zxteam@protonmail.com> | 2024-06-02 00:51:24 +0100 |
---|---|---|
committer | Alex Orlenko <zxteam@protonmail.com> | 2024-06-24 22:46:59 +0100 |
commit | dc12da49d6216fe280b1cf511172ffad508ac44d (patch) | |
tree | 0b53b66965f42b5c8e4cae8d7abb87844009408a | |
parent | fc9475b4959ce23e3bb420b42a95543e4f55bac2 (diff) | |
download | mlua-dc12da49d6216fe280b1cf511172ffad508ac44d.zip |
Refactor: WIP
35 files changed, 2507 insertions, 2926 deletions
@@ -1,6 +1,6 @@ [package] name = "mlua" -version = "0.9.9" # remember to update mlua_derive +version = "0.10.0" # remember to update mlua_derive authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@kyju.org>"] rust-version = "1.71" edition = "2021" @@ -53,7 +53,7 @@ futures-util = { version = "0.3", optional = true, default-features = false, fea serde = { version = "1.0", optional = true } erased-serde = { version = "0.4", optional = true } serde-value = { version = "0.7", optional = true } -parking_lot = { version = "0.12" } +parking_lot = { version = "0.12", features = ["arc_lock"] } ffi = { package = "mlua-sys", version = "0.6.1", path = "mlua-sys" } diff --git a/benches/benchmark.rs b/benches/benchmark.rs index f8352e0..b0a0fbb 100644 --- a/benches/benchmark.rs +++ b/benches/benchmark.rs @@ -305,7 +305,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<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: LuaUserDataMethods<'a, Self>>(methods: &mut M) { methods.add_meta_method(LuaMetaMethod::Index, move |_, _, key: LuaString| Ok(key)); } } @@ -331,7 +331,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<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: LuaUserDataMethods<'a, Self>>(methods: &mut M) { methods.add_method("add", |_, this, i: i64| Ok(this.0 + i)); } } @@ -361,7 +361,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<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: LuaUserDataMethods<'a, Self>>(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/guided_tour.rs b/examples/guided_tour.rs index 26b50ad..60ba159 100644 --- a/examples/guided_tour.rs +++ b/examples/guided_tour.rs @@ -154,8 +154,8 @@ fn main() -> Result<()> { struct Vec2(f32, f32); // We can implement `FromLua` trait for our `Vec2` to return a copy - impl<'lua> FromLua<'lua> for Vec2 { - fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> { + impl FromLua for Vec2 { + fn from_lua(value: Value, _: &Lua) -> Result<Self> { match value { Value::UserData(ud) => Ok(*ud.borrow::<Self>()?), _ => unreachable!(), @@ -192,6 +192,8 @@ fn main() -> Result<()> { // requirement. You can call `Lua::scope` to create userdata and callbacks types that only live // for as long as the call to scope, but do not have to be `'static` (and `Send`). + // TODO: Re-enable this + /* { let mut rust_val = 0; @@ -213,6 +215,7 @@ fn main() -> Result<()> { assert_eq!(rust_val, 42); } + */ // We were able to run our 'sketchy' function inside the scope just fine. However, if we // try to run our 'sketchy' function outside of the scope, the function we created will have diff --git a/mlua_derive/src/from_lua.rs b/mlua_derive/src/from_lua.rs index 3d4e4ed..8d0b683 100644 --- a/mlua_derive/src/from_lua.rs +++ b/mlua_derive/src/from_lua.rs @@ -15,9 +15,9 @@ pub fn from_lua(input: TokenStream) -> TokenStream { }; quote! { - impl #impl_generics ::mlua::FromLua<'_> for #ident #ty_generics #where_clause { + impl #impl_generics ::mlua::FromLua for #ident #ty_generics #where_clause { #[inline] - fn from_lua(value: ::mlua::Value<'_>, _: &'_ ::mlua::Lua) -> ::mlua::Result<Self> { + fn from_lua(value: ::mlua::Value, _: &::mlua::Lua) -> ::mlua::Result<Self> { match value { ::mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()), _ => Err(::mlua::Error::FromLuaConversionError { diff --git a/mlua_derive/src/lib.rs b/mlua_derive/src/lib.rs index 74605cb..07209be 100644 --- a/mlua_derive/src/lib.rs +++ b/mlua_derive/src/lib.rs @@ -99,15 +99,14 @@ pub fn chunk(input: TokenStream) -> TokenStream { use ::std::borrow::Cow; use ::std::cell::Cell; use ::std::io::Result as IoResult; - use ::std::marker::PhantomData; - struct InnerChunk<'lua, F: FnOnce(&'lua Lua) -> Result<Table<'lua>>>(Cell<Option<F>>, PhantomData<&'lua ()>); + struct InnerChunk<F: FnOnce(&Lua) -> Result<Table>>(Cell<Option<F>>); - impl<'lua, F> AsChunk<'lua, 'static> for InnerChunk<'lua, F> + impl<F> AsChunk<'static> for InnerChunk<F> where - F: FnOnce(&'lua Lua) -> Result<Table<'lua>>, + F: FnOnce(&Lua) -> Result<Table>, { - fn environment(&self, lua: &'lua Lua) -> Result<Option<Table<'lua>>> { + fn environment(&self, lua: &Lua) -> Result<Option<Table>> { if #caps_len > 0 { if let Some(make_env) = self.0.take() { return make_env(lua).map(Some); @@ -125,9 +124,7 @@ pub fn chunk(input: TokenStream) -> TokenStream { } } - fn annotate<'a, F: FnOnce(&'a Lua) -> Result<Table<'a>>>(f: F) -> F { f } - - let make_env = annotate(move |lua: &Lua| -> Result<Table> { + let make_env = move |lua: &Lua| -> Result<Table> { let globals = lua.globals(); let env = lua.create_table()?; let meta = lua.create_table()?; @@ -139,9 +136,9 @@ pub fn chunk(input: TokenStream) -> TokenStream { env.set_metatable(Some(meta)); Ok(env) - }); + }; - InnerChunk(Cell::new(Some(make_env)), PhantomData) + InnerChunk(Cell::new(Some(make_env))) }}; wrapped_code.into() diff --git a/src/chunk.rs b/src/chunk.rs index 9de6f47..a0a48e1 100644 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -7,7 +7,7 @@ use std::string::String as StdString; use crate::error::{Error, ErrorContext, Result}; use crate::function::Function; -use crate::lua::Lua; +use crate::lua::{Lua, WeakLua}; use crate::table::Table; use crate::value::{FromLuaMulti, IntoLua, IntoLuaMulti}; @@ -15,7 +15,7 @@ use crate::value::{FromLuaMulti, IntoLua, IntoLuaMulti}; /// /// [loadable by Lua]: https://www.lua.org/manual/5.4/manual.html#3.3.2 /// [`Chunk`]: crate::Chunk -pub trait AsChunk<'lua, 'a> { +pub trait AsChunk<'a> { /// Returns optional chunk name fn name(&self) -> Option<StdString> { None @@ -24,7 +24,7 @@ pub trait AsChunk<'lua, 'a> { /// Returns optional chunk [environment] /// /// [environment]: https://www.lua.org/manual/5.4/manual.html#2.2 - fn environment(&self, lua: &'lua Lua) -> Result<Option<Table<'lua>>> { + fn environment(&self, lua: &Lua) -> Result<Option<Table>> { let _lua = lua; // suppress warning Ok(None) } @@ -38,43 +38,43 @@ pub trait AsChunk<'lua, 'a> { fn source(self) -> IoResult<Cow<'a, [u8]>>; } -impl<'a> AsChunk<'_, 'a> for &'a str { +impl<'a> AsChunk<'a> for &'a str { fn source(self) -> IoResult<Cow<'a, [u8]>> { Ok(Cow::Borrowed(self.as_ref())) } } -impl AsChunk<'_, 'static> for StdString { +impl AsChunk<'static> for StdString { fn source(self) -> IoResult<Cow<'static, [u8]>> { Ok(Cow::Owned(self.into_bytes())) } } -impl<'a> AsChunk<'_, 'a> for &'a StdString { +impl<'a> AsChunk<'a> for &'a StdString { fn source(self) -> IoResult<Cow<'a, [u8]>> { Ok(Cow::Borrowed(self.as_bytes())) } } -impl<'a> AsChunk<'_, 'a> for &'a [u8] { +impl<'a> AsChunk<'a> for &'a [u8] { fn source(self) -> IoResult<Cow<'a, [u8]>> { Ok(Cow::Borrowed(self)) } } -impl AsChunk<'_, 'static> for Vec<u8> { +impl AsChunk<'static> for Vec<u8> { fn source(self) -> IoResult<Cow<'static, [u8]>> { Ok(Cow::Owned(self)) } } -impl<'a> AsChunk<'_, 'a> for &'a Vec<u8> { +impl<'a> AsChunk<'a> for &'a Vec<u8> { fn source(self) -> IoResult<Cow<'a, [u8]>> { Ok(Cow::Borrowed(self.as_ref())) } } -impl AsChunk<'_, 'static> for &Path { +impl AsChunk<'static> for &Path { fn name(&self) -> Option<StdString> { Some(format!("@{}", self.display())) } @@ -84,7 +84,7 @@ impl AsChunk<'_, 'static> for &Path { } } -impl AsChunk<'_, 'static> for PathBuf { +impl AsChunk<'static> for PathBuf { fn name(&self) -> Option<StdString> { Some(format!("@{}", self.display())) } @@ -98,10 +98,10 @@ impl AsChunk<'_, 'static> for PathBuf { /// /// [`Lua::load`]: crate::Lua::load #[must_use = "`Chunk`s do nothing unless one of `exec`, `eval`, `call`, or `into_function` are called on them"] -pub struct Chunk<'lua, 'a> { - pub(crate) lua: &'lua Lua, +pub struct Chunk<'a> { + pub(crate) lua: WeakLua, pub(crate) name: StdString, - pub(crate) env: Result<Option<Table<'lua>>>, + pub(crate) env: Result<Option<Table>>, pub(crate) mode: Option<ChunkMode>, pub(crate) source: IoResult<Cow<'a, [u8]>>, #[cfg(feature = "luau")] @@ -290,7 +290,7 @@ impl Compiler { } } -impl<'lua, 'a> Chunk<'lua, 'a> { +impl<'a> Chunk<'a> { /// Sets the name of this chunk, which results in more informative error traces. pub fn set_name(mut self, name: impl Into<String>) -> Self { self.name = name.into(); @@ -309,9 +309,11 @@ impl<'lua, 'a> Chunk<'lua, 'a> { /// necessary to populate the environment in order for scripts using custom environments to be /// useful. pub fn set_environment<V: IntoLua>(mut self, env: V) -> Self { + let lua = self.lua.lock(); + let lua = lua.lua(); self.env = env - .into_lua(self.lua) - .and_then(|val| self.lua.unpack(val)) + .into_lua(lua) + .and_then(|val| lua.unpack(val)) .context("bad environment value"); self } @@ -363,7 +365,7 @@ impl<'lua, 'a> Chunk<'lua, 'a> { /// If the chunk can be parsed as an expression, this loads and executes the chunk and returns /// the value that it evaluates to. Otherwise, the chunk is interpreted as a block as normal, /// and this is equivalent to calling `exec`. - pub fn eval<R: FromLuaMulti<'lua>>(self) -> Result<R> { + pub fn eval<R: FromLuaMulti>(self) -> Result<R> { // Bytecode is always interpreted as a statement. // For source code, first try interpreting the lua as an expression by adding // "return", then as a statement. This is the same thing the @@ -388,7 +390,7 @@ impl<'lua, 'a> Chunk<'lua, 'a> { #[cfg_attr(docsrs, doc(cfg(feature = "async")))] pub async fn eval_async<R>(self) -> Result<R> where - R: FromLuaMulti<'lua> + 'lua, + R: FromLuaMulti, { if self.detect_mode() == ChunkMode::Binary { self.call_async(()).await @@ -402,7 +404,7 @@ impl<'lua, 'a> Chunk<'lua, 'a> { /// Load the chunk function and call it with the given arguments. /// /// This is equivalent to `into_function` and calling the resulting function. - pub fn call<A: IntoLuaMulti, R: FromLuaMulti<'lua>>(self, args: A) -> Result<R> { + pub fn call<A: IntoLuaMulti, R: FromLuaMulti>(self, args: A) -> Result<R> { self.into_function()?.call(args) } @@ -418,7 +420,7 @@ impl<'lua, 'a> Chunk<'lua, 'a> { pub async fn call_async<A, R>(self, args: A) -> Result<R> where A: IntoLuaMulti, - R: FromLuaMulti<'lua> + 'lua, + R: FromLuaMulti, { self.into_function()?.call_async(args).await } @@ -427,7 +429,7 @@ impl<'lua, 'a> Chunk<'lua, 'a> { /// /// This simply compiles the chunk without actually executing it. #[cfg_attr(not(feature = "luau"), allow(unused_mut))] - pub fn into_function(mut self) -> Result<Function<'lua>> { + pub fn into_function(mut self) -> Result<Function> { #[cfg(feature = "luau")] if self.compiler.is_some() { // We don't need to compile source if no compiler set @@ -436,6 +438,7 @@ impl<'lua, 'a> Chunk<'lua, 'a> { let name = Self::convert_name(self.name)?; self.lua + .lock() .load_chunk(Some(&name), self.env?, self.mode, self.source?.as_ref()) } @@ -455,7 +458,11 @@ impl<'lua, 'a> Chunk<'lua, 'a> { self.mode = Some(ChunkMode::Binary); } #[cfg(not(feature = "luau"))] - if let Ok(func) = self.lua.load_chunk(None, None, None, source.as_ref()) { + if let Ok(func) = self + .lua + .lock() + .load_chunk(None, None, None, source.as_ref()) + { let data = func.dump(false); self.source = Ok(Cow::Owned(data)); self.mode = Some(ChunkMode::Binary); @@ -474,7 +481,8 @@ impl<'lua, 'a> Chunk<'lua, 'a> { let mut text_source = None; if let Ok(ref source) = self.source { if self.detect_mode() == ChunkMode::Text { - if let Some(cache) = self.lua.app_data_ref::<ChunksCache>() { + let lua = self.lua.lock(); + if let Some(cache) = lua.app_data_ref::<ChunksCache>() { if let Some(data) = cache.0.get(source.as_ref()) { self.source = Ok(Cow::Owned(data.clone())); self.mode = Some(ChunkMode::Binary); @@ -490,13 +498,14 @@ impl<'lua, 'a> Chunk<'lua, 'a> { self.compile(); if let Ok(ref binary_source) = self.source { if self.detect_mode() == ChunkMode::Binary { - if let Some(mut cache) = self.lua.app_data_mut::<ChunksCache>() { + let lua = self.lua.lock(); + if let Some(mut cache) = lua.app_data_mut::<ChunksCache>() { cache.0.insert(text_source, binary_source.as_ref().to_vec()); } else { let mut cache = ChunksCache(HashMap::new()); cache.0.insert(text_source, binary_source.as_ref().to_vec()); - let _ = self.lua.try_set_app_data(cache); - } + let _ = lua.try_set_app_data(cache); + }; } } } @@ -504,7 +513,7 @@ impl<'lua, 'a> Chunk<'lua, 'a> { self } - fn to_expression(&self) -> Result<Function<'lua>> { + fn to_expression(&self) -> Result<Function> { // We assume that mode is Text let source = self.source.as_ref(); let source = source.map_err(Error::runtime)?; @@ -519,6 +528,7 @@ impl<'lua, 'a> Chunk<'lua, 'a> { let name = Self::convert_name(self.name.clone())?; self.lua + .lock() .load_chunk(Some(&name), self.env.clone()?, None, &source) } diff --git a/src/conversion.rs b/src/conversion.rs index f521097..1194c63 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -12,69 +12,63 @@ use num_traits::cast; use crate::error::{Error, Result}; use crate::function::Function; -use crate::lua::Lua; +use crate::lua::{Lua, LuaInner}; use crate::string::String; use crate::table::Table; use crate::thread::Thread; use crate::types::{LightUserData, MaybeSend, RegistryKey}; -use crate::userdata::{AnyUserData, UserData, UserDataRef, UserDataRefMut}; +use crate::userdata::{AnyUserData, UserData}; use crate::value::{FromLua, IntoLua, Nil, Value}; -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -use crate::{ - function::OwnedFunction, string::OwnedString, table::OwnedTable, thread::OwnedThread, - userdata::OwnedAnyUserData, -}; - -impl IntoLua for Value<'_> { +impl IntoLua for Value { #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { unsafe { Ok(transmute(self)) } } } -impl IntoLua for &Value<'_> { +impl IntoLua for &Value { #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { unsafe { Ok(transmute(self.clone())) } } #[inline] - unsafe fn push_into_stack(self, lua: &Lua) -> Result<()> { + unsafe fn push_into_stack(self, lua: &LuaInner) -> Result<()> { lua.push_value(self) } } -impl<'lua> FromLua<'lua> for Value<'lua> { +impl FromLua for Value { #[inline] - fn from_lua(lua_value: Value<'lua>, _: &'lua Lua) -> Result<Self> { + fn from_lua(lua_value: Value, _: &Lua) -> Result<Self> { Ok(lua_value) } } -impl IntoLua for String<'_> { +impl IntoLua for String { #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { unsafe { Ok(Value::String(transmute(self))) } } } -impl IntoLua for &String<'_> { +impl IntoLua for &String { #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { unsafe { Ok(Value::String(transmute(self.clone()))) } } #[inline] - unsafe fn push_into_stack(self, lua: &Lua) -> Result<()> { + unsafe fn push_into_stack(self, lua: &LuaInner) -> Result<()> { lua.push_ref(&self.0); Ok(()) } } -impl<'lua> FromLua<'lua> for String<'lua> { +impl FromLua for String { #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<String<'lua>> { + fn from_lua(value: Value, lua: &Lua) -> Result<String> { let ty = value.type_name(); lua.coerce_string(value)? .ok_or_else(|| Error::FromLuaConversionError { @@ -85,62 +79,29 @@ impl<'lua> FromLua<'lua> for String<'lua> { } } -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] -impl IntoLua for OwnedString { - #[inline] - fn into_lua(self, lua: &'_ Lua) -> Result<Value<'_>> { - Ok(Value::String(String(lua.adopt_owned_ref(self.0)))) - } -} - -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] -impl IntoLua for &OwnedString { - #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { - OwnedString::into_lua(self.clone(), lua) - } - +impl IntoLua for Table { #[inline] - unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> { - lua.push_owned_ref(&self.0); - Ok(()) - } -} - -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] -impl<'lua> FromLua<'lua> for OwnedString { - #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<OwnedString> { - String::from_lua(value, lua).map(|s| s.into_owned()) - } -} - -impl IntoLua for Table<'_> { - #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { unsafe { Ok(Value::Table(transmute(self))) } } } -impl IntoLua for &Table<'_> { +impl IntoLua for &Table { #[inline] - fn into_lua(self, _: &'_ Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { unsafe { Ok(Value::Table(transmute(self.clone()))) } } #[inline] - unsafe fn push_into_stack(self, lua: &Lua) -> Result<()> { + unsafe fn push_into_stack(self, lua: &LuaInner) -> Result<()> { lua.push_ref(&self.0); Ok(()) } } -impl<'lua> FromLua<'lua> for Table<'lua> { +impl FromLua for Table { #[inline] - fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Table<'lua>> { + fn from_lua(value: Value, _: &Lua) -> Result<Table> { match value { Value::Table(table) => Ok(table), _ => Err(Error::FromLuaConversionError { @@ -152,62 +113,29 @@ impl<'lua> FromLua<'lua> for Table<'lua> { } } -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] -impl IntoLua for OwnedTable { +impl IntoLua for Function { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { - Ok(Value::Table(Table(lua.adopt_owned_ref(self.0)))) - } -} - -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] -impl IntoLua for &OwnedTable { - #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { - OwnedTable::into_lua(self.clone(), lua) - } - - #[inline] - unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> { - lua.push_owned_ref(&self.0); - Ok(()) - } -} - -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] -impl<'lua> FromLua<'lua> for OwnedTable { - #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<OwnedTable> { - Table::from_lua(value, lua).map(|s| s.into_owned()) - } -} - -impl IntoLua for Function<'_> { - #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { unsafe { Ok(Value::Function(transmute(self))) } } } -impl IntoLua for &Function<'_> { +impl IntoLua for &Function { #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { unsafe { Ok(Value::Function(transmute(self.clone()))) } } #[inline] - unsafe fn push_into_stack(self, lua: &Lua) -> Result<()> { + unsafe fn push_into_stack(self, lua: &LuaInner) -> Result<()> { lua.push_ref(&self.0); Ok(()) } } -impl<'lua> FromLua<'lua> for Function<'lua> { +impl FromLua for Function { #[inline] - fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Function<'lua>> { + fn from_lua(value: Value, _: &Lua) -> Result<Function> { match value { Value::Function(table) => Ok(table), _ => Err(Error::FromLuaConversionError { @@ -219,62 +147,29 @@ impl<'lua> FromLua<'lua> for Function<'lua> { } } -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] -impl IntoLua for OwnedFunction { - #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { - Ok(Value::Function(Function(lua.adopt_owned_ref(self.0)))) - } -} - -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] -impl IntoLua for &OwnedFunction { - #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { - OwnedFunction::into_lua(self.clone(), lua) - } - - #[inline] - unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> { - lua.push_owned_ref(&self.0); - Ok(()) - } -} - -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] -impl<'lua> FromLua<'lua> for OwnedFunction { +impl IntoLua for Thread { #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<OwnedFunction> { - Function::from_lua(value, lua).map(|s| s.into_owned()) - } -} - -impl IntoLua for Thread<'_> { - #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { unsafe { Ok(Value::Thread(transmute(self))) } } } -impl IntoLua for &Thread<'_> { +impl IntoLua for &Thread { #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { unsafe { Ok(Value::Thread(transmute(self.clone()))) } } #[inline] - unsafe fn push_into_stack(self, lua: &Lua) -> Result<()> { + unsafe fn push_into_stack(self, lua: &LuaInner) -> Result<()> { lua.push_ref(&self.0); Ok(()) } } -impl<'lua> FromLua<'lua> for Thread<'lua> { +impl FromLua for Thread { #[inline] - fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Thread<'lua>> { + fn from_lua(value: Value, _: &Lua) -> Result<Thread> { match value { Value::Thread(t) => Ok(t), _ => Err(Error::FromLuaConversionError { @@ -286,62 +181,29 @@ impl<'lua> FromLua<'lua> for Thread<'lua> { } } -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] -impl IntoLua for OwnedThread { - #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { - Ok(Value::Thread(Thread(lua.adopt_owned_ref(self.0), self.1))) - } -} - -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] -impl IntoLua for &OwnedThread { - #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { - OwnedThread::into_lua(self.clone(), lua) - } - +impl IntoLua for AnyUserData { #[inline] - unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> { - lua.push_owned_ref(&self.0); - Ok(()) - } -} - -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] -impl<'lua> FromLua<'lua> for OwnedThread { - #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<OwnedThread> { - Thread::from_lua(value, lua).map(|s| s.into_owned()) - } -} - -impl IntoLua for AnyUserData<'_> { - #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { unsafe { Ok(Value::UserData(transmute(self))) } } } -impl IntoLua for &AnyUserData<'_> { +impl IntoLua for &AnyUserData { #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { unsafe { Ok(Value::UserData(transmute(self.clone()))) } } #[inline] - unsafe fn push_into_stack(self, lua: &Lua) -> Result<()> { + unsafe fn push_into_stack(self, lua: &LuaInner) -> Result<()> { lua.push_ref(&self.0); Ok(()) } } -impl<'lua> FromLua<'lua> for AnyUserData<'lua> { +impl FromLua for AnyUserData { #[inline] - fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<AnyUserData<'lua>> { + fn from_lua(value: Value, _: &Lua) -> Result<AnyUserData> { match value { Value::UserData(ud) => Ok(ud), _ => Err(Error::FromLuaConversionError { @@ -353,73 +215,23 @@ impl<'lua> FromLua<'lua> for AnyUserData<'lua> { } } -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] -impl IntoLua for OwnedAnyUserData { - #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { - Ok(Value::UserData(AnyUserData( - lua.adopt_owned_ref(self.0), - self.1, - ))) - } -} - -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] -impl IntoLua for &OwnedAnyUserData { - #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { - OwnedAnyUserData::into_lua(self.clone(), lua) - } - - #[inline] - unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> { - lua.push_owned_ref(&self.0); - Ok(()) - } -} - -#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] -impl<'lua> FromLua<'lua> for OwnedAnyUserData { - #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<OwnedAnyUserData> { - AnyUserData::from_lua(value, lua).map(|s| s.into_owned()) - } -} - impl<T: UserData + MaybeSend + 'static> IntoLua for T { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::UserData(lua.create_userdata(self)?)) } } -impl<'lua, T: 'static> FromLua<'lua> for UserDataRef<'lua, T> { - #[inline] - fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> { - Self::from_value(value) - } -} - -impl<'lua, T: 'static> FromLua<'lua> for UserDataRefMut<'lua, T> { - #[inline] - fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> { - Self::from_value(value) - } -} - impl IntoLua for Error { #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Error(Box::new(self))) } } -impl<'lua> FromLua<'lua> for Error { +impl FromLua for Error { #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Error> { + fn from_lua(value: Value, lua: &Lua) -> Result<Error> { match value { Value::Error(err) => Ok(*err), val => Ok(Error::runtime( @@ -433,23 +245,23 @@ impl<'lua> FromLua<'lua> for Error { impl IntoLua for RegistryKey { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { lua.registry_value(&self) } #[inline] - unsafe fn push_into_stack(self, lua: &Lua) -> Result<()> { + unsafe fn push_into_stack(self, lua: &LuaInner) -> Result<()> { <&RegistryKey>::push_into_stack(&self, lua) } } impl IntoLua for &RegistryKey { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { lua.registry_value(self) } - unsafe fn push_into_stack(self, lua: &Lua) -> Result<()> { + unsafe fn push_into_stack(self, lua: &LuaInner) -> Result<()> { if !lua.owns_registry_value(self) { return Err(Error::MismatchedRegistryKey); } @@ -464,29 +276,29 @@ impl IntoLua for &RegistryKey { } } -impl<'lua> FromLua<'lua> for RegistryKey { +impl FromLua for RegistryKey { #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<RegistryKey> { + fn from_lua(value: Value, lua: &Lua) -> Result<RegistryKey> { lua.create_registry_value(value) } } impl IntoLua for bool { #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Boolean(self)) } #[inline] - unsafe fn push_into_stack(self, lua: &Lua) -> Result<()> { + unsafe fn push_into_stack(self, lua: &LuaInner) -> Result<()> { ffi::lua_pushboolean(lua.state(), self as c_int); Ok(()) } } -impl<'lua> FromLua<'lua> for bool { +impl FromLua for bool { #[inline] - fn from_lua(v: Value<'lua>, _: &'lua Lua) -> Result<Self> { + fn from_lua(v: Value, _: &Lua) -> Result<Self> { match v { Value::Nil => Ok(false), Value::Boolean(b) => Ok(b), @@ -495,21 +307,21 @@ impl<'lua> FromLua<'lua> for bool { } #[inline] - unsafe fn from_stack(idx: c_int, lua: &'lua Lua) -> Result<Self> { + unsafe fn from_stack(idx: c_int, lua: &LuaInner) -> Result<Self> { Ok(ffi::lua_toboolean(lua.state(), idx) != 0) } } impl IntoLua for LightUserData { #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::LightUserData(self)) } } -impl<'lua> FromLua<'lua> for LightUserData { +impl FromLua for LightUserData { #[inline] - fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> { + fn from_lua(value: Value, _: &Lua) -> Result<Self> { match value { Value::LightUserData(ud) => Ok(ud), _ => Err(Error::FromLuaConversionError { @@ -524,15 +336,15 @@ impl<'lua> FromLua<'lua> for LightUserData { #[cfg(feature = "luau")] impl IntoLua for crate::types::Vector { #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { Ok(Value::Vector(self)) } } #[cfg(feature = "luau")] -impl<'lua> FromLua<'lua> for crate::types::Vector { +impl FromLua for crate::types::Vector { #[inline] - fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> { + fn from_lua(value: Value, _: &Lua) -> Result<Self> { match value { Value::Vector(v) => Ok(v), _ => Err(Error::FromLuaConversionError { @@ -546,19 +358,19 @@ impl<'lua> FromLua<'lua> for crate::types::Vector { impl IntoLua for StdString { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::String(lua.create_string(&self)?)) } #[inline] - unsafe fn push_into_stack(self, lua: &Lua) -> Result<()> { + unsafe fn push_into_stack(self, lua: &LuaInner) -> Result<()> { push_bytes_into_stack(self, lua) } } -impl<'lua> FromLua<'lua> for StdString { +impl FromLua for StdString { #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> { + fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let ty = value.type_name(); Ok(lua .coerce_string(value)? @@ -572,7 +384,7 @@ impl<'lua> FromLua<'lua> for StdString { } #[inline] - unsafe fn from_stack(idx: c_int, lua: &'lua Lua) -> Result<Self> { + unsafe fn from_stack(idx: c_int, lua: &LuaInner) -> Result<Self> { let state = lua.state(); if ffi::lua_type(state, idx) == ffi::LUA_TSTRING { let mut size = 0; @@ -587,39 +399,39 @@ impl<'lua> FromLua<'lua> for StdString { }); } // Fallback to default - Self::from_lua(lua.stack_value(idx), lua) + Self::from_lua(lua.stack_value(idx), lua.lua()) } } impl IntoLua for &str { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::String(lua.create_string(self)?)) } #[inline] - unsafe fn push_into_stack(self, lua: &Lua) -> Result<()> { + unsafe fn push_into_stack(self, lua: &LuaInner) -> Result<()> { push_bytes_into_stack(self, lua) } } impl IntoLua for Cow<'_, str> { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::String(lua.create_string(self.as_bytes())?)) } } impl IntoLua for Box<str> { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::String(lua.create_string(&*self)?)) } } -impl<'lua> FromLua<'lua> for Box<str> { +impl FromLua for Box<str> { #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> { + fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let ty = value.type_name(); Ok(lua .coerce_string(value)? @@ -636,14 +448,14 @@ impl<'lua> FromLua<'lua> for Box<str> { impl IntoLua for CString { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::String(lua.create_string(self.as_bytes())?)) } } -impl<'lua> FromLua<'lua> for CString { +impl FromLua for CString { #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> { + fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let ty = value.type_name(); let string = lua .coerce_string(value)? @@ -666,34 +478,35 @@ impl<'lua> FromLua<'lua> for CString { impl IntoLua for &CStr { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::String(lua.create_string(self.to_bytes())?)) } } impl IntoLua for Cow<'_, CStr> { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::String(lua.create_string(self.to_bytes())?)) } } impl IntoLua for BString { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::String(lua.create_string(&self)?)) } } -impl<'lua> FromLua<'lua> for BString { - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> { +impl FromLua for BString { + fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let ty = value.type_name(); match value { Value::String(s) => Ok(s.as_bytes().into()), #[cfg(feature = "luau")] Value::UserData(ud) if ud.1 == crate::types::SubtypeId::Buffer => unsafe { + let lua = ud.0.lua.lock(); let mut size = 0usize; - let buf = ffi::lua_tobuffer(ud.0.lua.ref_thread(), ud.0.index, &mut size); + let buf = ffi::lua_tobuffer(lua.ref_thread(), ud.0.index, &mut size); mlua_assert!(!buf.is_null(), "invalid Luau buffer"); Ok(slice::from_raw_parts(buf as *const u8, size).into()) }, @@ -709,7 +522,7 @@ impl<'lua> FromLua<'lua> for BString { } } - unsafe fn from_stack(idx: c_int, lua: &'lua Lua) -> Result<Self> { + unsafe fn from_stack(idx: c_int, lua: &LuaInner) -> Result<Self> { let state = lua.state(); match ffi::lua_type(state, idx) { ffi::LUA_TSTRING => { @@ -726,7 +539,7 @@ impl<'lua> FromLua<'lua> for BString { } _ => { // Fallback to default - Self::from_lua(lua.stack_value(idx), lua) + Self::from_lua(lua.stack_value(idx), lua.lua()) } } } @@ -734,13 +547,13 @@ impl<'lua> FromLua<'lua> for BString { impl IntoLua for &BStr { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::String(lua.create_string(self)?)) } } #[inline] -unsafe fn push_bytes_into_stack<'lua, T>(this: T, lua: &'lua Lua) -> Result<()> +unsafe fn push_bytes_into_stack<T>(this: T, lua: &LuaInner) -> Result<()> where T: IntoLua + AsRef<[u8]>, { @@ -751,14 +564,14 @@ where return Ok(()); } // Fallback to default - lua.push_value(&T::into_lua(this, lua)?) + lua.push_value(&T::into_lua(this, lua.lua())?) } macro_rules! lua_convert_int { ($x:ty) => { impl IntoLua for $x { #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { cast(self) .map(Value::Integer) .or_else(|| cast(self).map(Value::Number)) @@ -771,7 +584,7 @@ macro_rules! lua_convert_int { } #[inline] - unsafe fn push_into_stack(self, lua: &Lua) -> Result<()> { + unsafe fn push_into_stack(self, lua: &LuaInner) -> Result<()> { match cast(self) { Some(i) => ffi::lua_pushinteger(lua.state(), i), None => ffi::lua_pushnumber(lua.state(), self as ffi::lua_Number), @@ -780,9 +593,9 @@ macro_rules! lua_convert_int { } } - impl<'lua> FromLua<'lua> for $x { + impl FromLua for $x { #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> { + fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let ty = value.type_name(); (match value { Value::Integer(i) => cast(i), @@ -830,7 +643,7 @@ macro_rules! lua_convert_float { ($x:ty) => { impl IntoLua for $x { #[inline] - fn into_lua(self, _: &Lua) -> Result<Value<'_>> { + fn into_lua(self, _: &Lua) -> Result<Value> { cast(self) .ok_or_else(|| Error::ToLuaConversionError { from: stringify!($x), @@ -841,9 +654,9 @@ macro_rules! lua_convert_float { } } - impl<'lua> FromLua<'lua> for $x { + impl FromLua for $x { #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> { + fn from_lua(value: Value, lua: &Lua) -> Result<Self> { let ty = value.type_name(); lua.coerce_number(value)? .ok_or_else(|| Error::FromLuaConversionError { @@ -871,7 +684,7 @@ where T: IntoLua + Clone, { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table( lua.create_sequence_from(self.iter().cloned())?, )) @@ -883,17 +696,17 @@ where T: IntoLua, { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table(lua.create_sequence_from(self)?)) } } -impl<'lua, T, const N: usize> FromLua<'lua> for [T; N] +impl<T, const N: usize> FromLua for [T; N] where - T: FromLua<'lua>, + T: FromLua, { #[inline] - fn from_lua(value: Value<'lua>, _lua: &'lua Lua) -> Result<Self> { + fn from_lua(value: Value, _lua: &Lua) -> Result<Self> { match value { #[cfg(feature = "luau")] #[rustfmt::skip] @@ -927,28 +740,28 @@ where impl<T: IntoLua> IntoLua for Box<[T]> { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table(lua.create_sequence_from(self.into_vec())?)) } } -impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Box<[T]> { +impl<T: FromLua> FromLua for Box<[T]> { #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> { + fn from_lua(value: Value, lua: &Lua) -> Result<Self> { Ok(Vec::<T>::from_lua(value, lua)?.into_boxed_slice()) } } impl<T: IntoLua> IntoLua for Vec<T> { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table(lua.create_sequence_from(self)?)) } } -impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Vec<T> { +impl<T: FromLua> FromLua for Vec<T> { #[inline] - fn from_lua(value: Value<'lua>, _lua: &'lua Lua) -> Result<Self> { + fn from_lua(value: Value, _lua: &Lua) -> Result<Self> { match value { Value::Table(table) => table.sequence_values().collect(), _ => Err(Error::FromLuaConversionError { @@ -962,16 +775,14 @@ impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Vec<T> { impl<K: Eq + Hash + IntoLua, V: IntoLua, S: BuildHasher> IntoLua for HashMap<K, V, S> { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table(lua.create_table_from(self)?)) } } -impl<'lua, K: Eq + Hash + FromLua<'lua>, V: FromLua<'lua>, S: BuildHasher + Default> FromLua<'lua> - for HashMap<K, V, S> -{ +impl<K: Eq + Hash + FromLua, V: FromLua, S: BuildHasher + Default> FromLua for HashMap<K, V, S> { #[inline] - fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> { + fn from_lua(value: Value, _: &Lua) -> Result<Self> { if let Value::Table(table) = value { table.pairs().collect() } else { @@ -986,14 +797,14 @@ impl<'lua, K: Eq + Hash + FromLua<'lua>, V: FromLua<'lua>, S: BuildHasher + Defa impl<K: Ord + IntoLua, V: IntoLua> IntoLua for BTreeMap<K, V> { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table(lua.create_table_from(self)?)) } } -impl<'lua, K: Ord + FromLua<'lua>, V: FromLua<'lua>> FromLua<'lua> for BTreeMap<K, V> { +impl<K: Ord + FromLua, V: FromLua> FromLua for BTreeMap<K, V> { #[inline] - fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> { + fn from_lua(value: Value, _: &Lua) -> Result<Self> { if let Value::Table(table) = value { table.pairs().collect() } else { @@ -1008,20 +819,20 @@ impl<'lua, K: Ord + FromLua<'lua>, V: FromLua<'lua>> FromLua<'lua> for BTreeMap< impl<T: Eq + Hash + IntoLua, S: BuildHasher> IntoLua for HashSet<T, S> { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table(lua.create_table_from( self.into_iter().map(|val| (val, true)), )?)) } } -impl<'lua, T: Eq + Hash + FromLua<'lua>, S: BuildHasher + Default> FromLua<'lua> for HashSet<T, S> { +impl<T: Eq + Hash + FromLua, S: BuildHasher + Default> FromLua for HashSet<T, S> { #[inline] - fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> { + fn from_lua(value: Value, _: &Lua) -> Result<Self> { match value { Value::Table(table) if table.raw_len() > 0 => table.sequence_values().collect(), Value::Table(table) => table - .pairs::<T, Value<'lua>>() + .pairs::<T, Value>() .map(|res| res.map(|(k, _)| k)) .collect(), _ => Err(Error::FromLuaConversionError { @@ -1035,20 +846,20 @@ impl<'lua, T: Eq + Hash + FromLua<'lua>, S: BuildHasher + Default> FromLua<'lua> impl<T: Ord + IntoLua> IntoLua for BTreeSet<T> { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { Ok(Value::Table(lua.create_table_from( self.into_iter().map(|val| (val, true)), )?)) } } -impl<'lua, T: Ord + FromLua<'lua>> FromLua<'lua> for BTreeSet<T> { +impl<T: Ord + FromLua> FromLua for BTreeSet<T> { #[inline] - fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> { + fn from_lua(value: Value, _: &Lua) -> Result<Self> { match value { Value::Table(table) if table.raw_len() > 0 => table.sequence_values().collect(), Value::Table(table) => table - .pairs::<T, Value<'lua>>() + .pairs::<T, Value>() .map(|res| res.map(|(k, _)| k)) .collect(), _ => Err(Error::FromLuaConversionError { @@ -1062,7 +873,7 @@ impl<'lua, T: Ord + FromLua<'lua>> FromLua<'lua> for BTreeSet<T> { impl<T: IntoLua> IntoLua for Option<T> { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { match self { Some(val) => val.into_lua(lua), None => Ok(Nil), @@ -1070,7 +881,7 @@ impl<T: IntoLua> IntoLua for Option<T> { } #[inline] - unsafe fn push_into_stack(self, lua: &Lua) -> Result<()> { + unsafe fn push_into_stack(self, lua: &LuaInner) -> Result<()> { match self { Some(val) => val.push_into_stack(lua)?, None => ffi::lua_pushnil(lua.state()), @@ -1079,9 +890,9 @@ impl<T: IntoLua> IntoLua for Option<T> { } } -impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Option<T> { +impl<T: FromLua> FromLua for Option<T> { #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> { + fn from_lua(value: Value, lua: &Lua) -> Result<Self> { match value { Nil => Ok(None), value => Ok(Some(T::from_lua(value, lua)?)), @@ -1089,7 +900,7 @@ impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Option<T> { } #[inline] - unsafe fn from_stack(idx: c_int, lua: &'lua Lua) -> Result<Self> { + unsafe fn from_stack(idx: c_int, lua: &LuaInner) -> Result<Self> { if ffi::lua_isnil(lua.state(), idx) != 0 { Ok(None) } else { diff --git a/src/function.rs b/src/function.rs index 81a7cda..a27069e 100644 --- a/src/function.rs +++ b/src/function.rs @@ -22,28 +22,7 @@ use { /// Handle to an internal Lua function. #[derive(Clone, Debug)] -pub struct Function<'lua>(pub(crate) ValueRef<'lua>); - -/// Owned handle to an internal Lua function. -/// -/// The owned handle holds a *strong* reference to the current Lua instance. -/// Be warned, if you place it into a Lua type (eg. [`UserData`] or a Rust callback), it is *very easy* -/// to accidentally cause reference cycles that would prevent destroying Lua instance. -/// -/// [`UserData`]: crate::UserData -#[cfg(feature = "unstable")] -#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] -#[derive(Clone, Debug)] -pub struct OwnedFunction(pub(crate) crate::types::OwnedValueRef); - -#[cfg(feature = "unstable")] -impl OwnedFunction { - /// Get borrowed handle to the underlying Lua function. - #[cfg_attr(feature = "send", allow(unused))] - pub const fn to_ref(&self) -> Function { - Function(self.0.to_ref()) - } -} +pub struct Function(pub(crate) ValueRef); /// Contains information about a function. /// @@ -81,7 +60,7 @@ pub struct CoverageInfo { pub hits: Vec<i32>, } -impl<'lua> Function<'lua> { +impl Function { /// Calls the function, passing `args` as function arguments. /// /// The function's return values are converted to the generic type `R`. @@ -122,8 +101,8 @@ impl<'lua> Function<'lua> { /// # Ok(()) /// # } /// ``` - pub fn call<A: IntoLuaMulti, R: FromLuaMulti<'lua>>(&self, args: A) -> Result<R> { - let lua = self.0.lua; + pub fn call<A: IntoLuaMulti, R: FromLuaMulti>(&self, args: A) -> Result<R> { + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -134,7 +113,7 @@ impl<'lua> Function<'lua> { let stack_start = ffi::lua_gettop(state); // Push function and the arguments lua.push_ref(&self.0); - let nargs = args.push_into_stack_multi(lua)?; + let nargs = args.push_into_stack_multi(&lua)?; // Call the function let ret = ffi::lua_pcall(state, nargs, ffi::LUA_MULTRET, stack_start); if ret != ffi::LUA_OK { @@ -142,7 +121,7 @@ impl<'lua> Function<'lua> { } // Get the results let nresults = ffi::lua_gettop(state) - stack_start; - R::from_stack_multi(nresults, lua) + R::from_stack_multi(nresults, &lua) } } @@ -176,12 +155,12 @@ impl<'lua> Function<'lua> { /// [`AsyncThread`]: crate::AsyncThread #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - pub fn call_async<A, R>(&self, args: A) -> impl Future<Output = Result<R>> + 'lua + pub fn call_async<A, R>(&self, args: A) -> impl Future<Output = Result<R>> where A: IntoLuaMulti, - R: FromLuaMulti<'lua> + 'lua, + R: FromLuaMulti, { - let lua = self.0.lua; + let lua = self.0.lua.lock(); let thread_res = lua.create_recycled_thread(self).map(|th| { let mut th = th.into_async(args); th.set_recyclable(true); @@ -217,7 +196,7 @@ impl<'lua> Function<'lua> { /// # Ok(()) /// # } /// ``` - pub fn bind<A: IntoLuaMulti>(&self, args: A) -> Result<Function<'lua>> { + pub fn bind<A: IntoLuaMulti>(&self, args: A) -> Result<Function> { unsafe extern "C-unwind" fn args_wrapper_impl(state: *mut ffi::lua_State) -> c_int { let nargs = ffi::lua_gettop(state); let nbinds = ffi::lua_tointeger(state, ffi::lua_upvalueindex(1)) as c_int; @@ -233,10 +212,10 @@ impl<'lua> Function<'lua> { nargs + nbinds } - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); - let args = args.into_lua_multi(lua)?; + let args = args.into_lua_multi(lua.lua())?; let nargs = args.len() as c_int; if nargs == 0 { @@ -262,6 +241,7 @@ impl<'lua> Function<'lua> { Function(lua.pop_ref()) }; + let lua = lua.lua(); lua.load( r#" local func, args_wrapper = ... @@ -281,7 +261,7 @@ impl<'lua> Function<'lua> { /// /// This function always returns `None` for Rust/C functions. pub fn environment(&self) -> Option<Table> { - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -318,7 +298,7 @@ impl<'lua> Function<'lua> { /// /// This function does nothing for Rust/C functions. pub fn set_environment(&self, env: Table) -> Result<bool> { - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -342,6 +322,7 @@ impl<'lua> Function<'lua> { ffi::lua_pop(state, 1); // Create an anonymous function with the new environment let f_with_env = lua + .lua() .load("return _ENV") .set_environment(env) .try_cache() @@ -364,7 +345,7 @@ impl<'lua> Function<'lua> { /// /// [`lua_getinfo`]: https://www.lua.org/manual/5.4/manual.html#lua_getinfo pub fn info(&self) -> FunctionInfo { - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -425,7 +406,7 @@ impl<'lua> Function<'lua> { 0 } - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); let mut data: Vec<u8> = Vec::new(); unsafe { @@ -482,7 +463,7 @@ impl<'lua> Function<'lua> { }); } - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -514,80 +495,42 @@ impl<'lua> Function<'lua> { #[cfg(feature = "luau")] #[cfg_attr(docsrs, doc(cfg(feature = "luau")))] pub fn deep_clone(&self) -> Self { - let ref_thread = self.0.lua.ref_thread(); + let lua = self.0.lua.lock(); + let ref_thread = lua.ref_thread(); unsafe { if ffi::lua_iscfunction(ref_thread, self.0.index) != 0 { return self.clone(); } ffi::lua_clonefunction(ref_thread, self.0.index); - Function(self.0.lua.pop_ref_thread()) + Function(lua.pop_ref_thread()) } } - - /// Convert this handle to owned version. - #[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] - #[inline] - pub fn into_owned(self) -> OwnedFunction { - OwnedFunction(self.0.into_owned()) - } } -impl<'lua> PartialEq for Function<'lua> { +impl PartialEq for Function { fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } -// Additional shortcuts -#[cfg(feature = "unstable")] -impl OwnedFunction { - /// Calls the function, passing `args` as function arguments. - /// - /// This is a shortcut for [`Function::call()`]. - #[inline] - pub fn call<'lua, A, R>(&'lua self, args: A) -> Result<R> - where - A: IntoLuaMulti, - R: FromLuaMulti<'lua>, - { - self.to_ref().call(args) - } - - /// Returns a future that, when polled, calls `self`, passing `args` as function arguments, - /// and drives the execution. - /// - /// This is a shortcut for [`Function::call_async()`]. - #[cfg(feature = "async")] - #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - #[inline] - pub async fn call_async<'lua, A, R>(&'lua self, args: A) -> Result<R> - where - A: IntoLuaMulti, - R: FromLuaMulti<'lua> + 'lua, - { - self.to_ref().call_async(args).await - } -} - -pub(crate) struct WrappedFunction<'lua>(pub(crate) Callback<'lua, 'static>); +pub(crate) struct WrappedFunction(pub(crate) Callback<'static>); #[cfg(feature = "async")] -pub(crate) struct WrappedAsyncFunction<'lua>(pub(crate) AsyncCallback<'lua, 'static>); +pub(crate) struct WrappedAsyncFunction(pub(crate) AsyncCallback<'static>); -impl<'lua> Function<'lua> { +impl Function { /// Wraps a Rust function or closure, returning an opaque type that implements [`IntoLua`] trait. #[inline] pub fn wrap<A, R, F>(func: F) -> impl IntoLua where - A: FromLuaMulti<'lua>, + A: FromLuaMulti, R: IntoLuaMulti, - F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static, + F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static, { WrappedFunction(Box::new(move |lua, nargs| unsafe { let args = A::from_stack_args(nargs, 1, None, lua)?; - func(lua, args)?.push_into_stack_multi(lua) + func(lua.lua(), args)?.push_into_stack_multi(lua) })) } @@ -595,9 +538,9 @@ impl<'lua> Function<'lua> { #[inline] pub fn wrap_mut<A, R, F>(func: F) -> impl IntoLua where - A: FromLuaMulti<'lua>, + A: FromLuaMulti, R: IntoLuaMulti, - F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static, + F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static, { let func = RefCell::new(func); WrappedFunction(Box::new(move |lua, nargs| unsafe { @@ -605,7 +548,7 @@ impl<'lua> Function<'lua> { .try_borrow_mut() .map_err(|_| Error::RecursiveMutCallback)?; let args = A::from_stack_args(nargs, 1, None, lua)?; - func(lua, args)?.push_into_stack_multi(lua) + func(lua.lua(), args)?.push_into_stack_multi(lua) })) } @@ -614,45 +557,44 @@ impl<'lua> Function<'lua> { #[cfg_attr(docsrs, doc(cfg(feature = "async")))] pub fn wrap_async<A, R, F, FR>(func: F) -> impl IntoLua where - A: FromLuaMulti<'lua>, + A: FromLuaMulti, R: IntoLuaMulti, - F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static, + F: Fn(&Lua, A) -> FR + MaybeSend + 'static, FR: Future<Output = Result<R>> + 'static, { - WrappedAsyncFunction(Box::new(move |lua, args| unsafe { + WrappedAsyncFunction(Box::new(move |rawlua, args| unsafe { + let lua = rawlua.lua(); let args = match A::from_lua_args(args, 1, None, lua) { Ok(args) => args, Err(e) => return Box::pin(future::err(e)), }; let fut = func(lua, args); - Box::pin(async move { fut.await?.push_into_stack_multi(lua) }) + let weak = rawlua.weak().clone(); + Box::pin(async move { fut.await?.push_into_stack_multi(&weak.lock()) }) })) } } -impl IntoLua for WrappedFunction<'_> { +impl IntoLua for WrappedFunction { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { - lua.create_callback(unsafe { mem::transmute(self.0) }) - .map(Value::Function) + fn into_lua(self, lua: &Lua) -> Result<Value> { + lua.lock().create_callback(self.0).map(Value::Function) } } #[cfg(feature = "async")] -impl IntoLua for WrappedAsyncFunction<'_> { +impl IntoLua for WrappedAsyncFunction { #[inline] - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { - lua.create_async_callback(unsafe { mem::transmute(self.0) }) + fn into_lua(self, lua: &Lua) -> Result<Value> { + lua.lock() + .create_async_callback(self.0) .map(Value::Function) } } -#[cfg(test)] -mod assertions { - use super::*; +// #[cfg(test)] +// mod assertions { +// use super::*; - static_assertions::assert_not_impl_any!(Function: Send); - - #[cfg(all(feature = "unstable", not(feature = "send")))] - static_assertions::assert_not_impl_any!(OwnedFunction: Send); -} +// static_assertions::assert_not_impl_any!(Function: Send); +// } diff --git a/src/hook.rs b/src/hook.rs index 950bc79..72f8b88 100644 --- a/src/hook.rs +++ b/src/hook.rs @@ -1,12 +1,14 @@ use std::borrow::Cow; use std::cell::UnsafeCell; +use std::mem::ManuallyDrop; #[cfg(not(feature = "luau"))] use std::ops::{BitOr, BitOrAssign}; use std::os::raw::c_int; use ffi::lua_Debug; +use parking_lot::ReentrantMutexGuard; -use crate::lua::Lua; +use crate::lua::{Lua, LuaInner}; use crate::util::{linenumber_to_usize, ptr_to_lossy_str, ptr_to_str}; /// Contains information about currently executing Lua code. @@ -19,24 +21,37 @@ use crate::util::{linenumber_to_usize, ptr_to_lossy_str, ptr_to_str}; /// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#lua_Debug /// [`Lua::set_hook`]: crate::Lua::set_hook pub struct Debug<'lua> { - lua: &'lua Lua, + lua: ManuallyDrop<ReentrantMutexGuard<'lua, LuaInner>>, ar: ActivationRecord, #[cfg(feature = "luau")] level: c_int, } +impl<'lua> Drop for Debug<'lua> { + fn drop(&mut self) { + if let ActivationRecord::Owned(_) = self.ar { + unsafe { ManuallyDrop::drop(&mut self.lua) } + } + } +} + impl<'lua> Debug<'lua> { + // We assume the lock is held when this function is called. #[cfg(not(feature = "luau"))] pub(crate) fn new(lua: &'lua Lua, ar: *mut lua_Debug) -> Self { Debug { - lua, + lua: unsafe { lua.guard_unchecked() }, ar: ActivationRecord::Borrowed(ar), } } - pub(crate) fn new_owned(lua: &'lua Lua, _level: c_int, ar: lua_Debug) -> Self { + pub(crate) fn new_owned( + guard: ReentrantMutexGuard<'lua, LuaInner>, + _level: c_int, + ar: lua_Debug, + ) -> Self { Debug { - lua, + lua: ManuallyDrop::new(guard), ar: ActivationRecord::Owned(UnsafeCell::new(ar)), #[cfg(feature = "luau")] level: _level, @@ -89,13 +89,14 @@ mod lua; mod luau; mod memory; mod multi; -mod scope; +// mod scope; mod stdlib; mod string; mod table; mod thread; mod types; mod userdata; +mod userdata_cell; mod userdata_ext; mod userdata_impl; mod util; @@ -111,7 +112,7 @@ pub use crate::function::{Function, FunctionInfo}; pub use crate::hook::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack}; pub use crate::lua::{GCMode, Lua, LuaOptions}; pub use crate::multi::Variadic; -pub use crate::scope::Scope; +// pub use crate::scope::Scope; pub use crate::stdlib::StdLib; pub use crate::string::String; pub use crate::table::{Table, TableExt, TablePairs, TableSequence}; @@ -119,8 +120,8 @@ pub use crate::thread::{Thread, ThreadStatus}; pub use crate::types::{AppDataRef, AppDataRefMut, Integer, LightUserData, Number, RegistryKey}; pub use crate::userdata::{ AnyUserData, MetaMethod, UserData, UserDataFields, UserDataMetatable, UserDataMethods, - UserDataRef, UserDataRefMut, }; +pub use crate::userdata_cell::{UserDataRef, UserDataRefMut}; pub use crate::userdata_ext::AnyUserDataExt; pub use crate::userdata_impl::UserDataRegistry; pub use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, MultiValue, Nil, Value}; @@ -154,13 +155,6 @@ pub mod serde; #[macro_use] extern crate mlua_derive; -// Unstable features -#[cfg(feature = "unstable")] -pub use crate::{ - function::OwnedFunction, string::OwnedString, table::OwnedTable, thread::OwnedThread, - userdata::OwnedAnyUserData, -}; - /// Create a type that implements [`AsChunk`] and can capture Rust variables. /// /// This macro allows to write Lua code directly in Rust code. @@ -279,6 +273,6 @@ pub(crate) mod private { impl Sealed for Error {} impl<T> Sealed for std::result::Result<T, Error> {} impl Sealed for Lua {} - impl Sealed for Table<'_> {} - impl Sealed for AnyUserData<'_> {} + impl Sealed for Table {} + impl Sealed for AnyUserData {} } @@ -1,17 +1,18 @@ use std::any::TypeId; use std::cell::{Cell, RefCell, UnsafeCell}; -use std::collections::VecDeque; +// use std::collections::VecDeque; use std::ffi::{CStr, CString}; use std::fmt; use std::marker::PhantomData; -use std::mem::{self, MaybeUninit}; +use std::mem::{self, ManuallyDrop, MaybeUninit}; use std::ops::Deref; use std::os::raw::{c_char, c_int, c_void}; use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe, Location}; use std::ptr; use std::result::Result as StdResult; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Weak}; +use parking_lot::{Mutex, ReentrantMutex, ReentrantMutexGuard}; use rustc_hash::FxHashMap; use crate::chunk::{AsChunk, Chunk, ChunkMode}; @@ -19,16 +20,18 @@ use crate::error::{Error, Result}; use crate::function::Function; use crate::hook::Debug; use crate::memory::{MemoryState, ALLOCATOR}; -use crate::scope::Scope; +// use crate::scope::Scope; use crate::stdlib::StdLib; use crate::string::String; use crate::table::Table; use crate::thread::Thread; use crate::types::{ - AppData, AppDataRef, AppDataRefMut, Callback, CallbackUpvalue, DestructedUserdata, Integer, - LightUserData, MaybeSend, Number, RegistryKey, SubtypeId, ValueRef, + AppData, AppDataRef, AppDataRefMut, ArcReentrantMutexGuard, Callback, CallbackUpvalue, + DestructedUserdata, Integer, LightUserData, MaybeSend, Number, RegistryKey, SubtypeId, + ValueRef, }; -use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataCell}; +use crate::userdata::{AnyUserData, MetaMethod, UserData}; +use crate::userdata_cell::{UserDataRef, UserDataVariant}; use crate::userdata_impl::{UserDataProxy, UserDataRegistry}; use crate::util::{ self, assert_stack, check_stack, error_traceback, get_destructed_userdata_metatable, @@ -66,8 +69,15 @@ use { use serde::Serialize; /// Top level Lua struct which represents an instance of Lua VM. +#[derive(Clone)] #[repr(transparent)] -pub struct Lua(Arc<LuaInner>); +pub struct Lua(Arc<ReentrantMutex<LuaInner>>); + +#[derive(Clone)] +#[repr(transparent)] +pub(crate) struct WeakLua(Weak<ReentrantMutex<LuaInner>>); + +pub(crate) struct LuaGuard(ArcReentrantMutexGuard<LuaInner>); /// An inner Lua struct which holds a raw Lua state. pub struct LuaInner { @@ -80,7 +90,8 @@ pub struct LuaInner { // Data associated with the Lua. pub(crate) struct ExtraData { // Same layout as `Lua` - inner: MaybeUninit<Arc<LuaInner>>, + inner: MaybeUninit<Arc<ReentrantMutex<LuaInner>>>, + weak: MaybeUninit<Weak<ReentrantMutex<LuaInner>>>, registered_userdata: FxHashMap<TypeId, c_int>, registered_userdata_mt: FxHashMap<*const c_void, Option<TypeId>>, @@ -106,7 +117,7 @@ pub(crate) struct ExtraData { // Pool of `WrappedFailure` enums in the ref thread (as userdata) wrapped_failure_pool: Vec<c_int>, // Pool of `MultiValue` containers - multivalue_pool: Vec<VecDeque<Value<'static>>>, + // multivalue_pool: Vec<VecDeque<Value>>, // Pool of `Thread`s (coroutines) for async execution #[cfg(feature = "async")] thread_pool: Vec<c_int>, @@ -225,7 +236,7 @@ pub(crate) static ASYNC_POLL_PENDING: u8 = 0; pub(crate) static EXTRA_REGISTRY_KEY: u8 = 0; const WRAPPED_FAILURE_POOL_SIZE: usize = 64; -const MULTIVALUE_POOL_SIZE: usize = 64; +// const MULTIVALUE_POOL_SIZE: usize = 64; const REF_STACK_RESERVE: c_int = 1; /// Requires `feature = "send"` @@ -262,23 +273,14 @@ impl Drop for ExtraData { unsafe { self.inner.assume_init_drop(); } - - *mlua_expect!(self.registry_unref_list.lock(), "unref list poisoned") = None; + unsafe { self.weak.assume_init_drop() }; + *self.registry_unref_list.lock() = None; } } impl fmt::Debug for Lua { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Lua({:p})", self.state()) - } -} - -impl Deref for Lua { - type Target = LuaInner; - - #[inline] - fn deref(&self) -> &Self::Target { - &self.0 + write!(f, "Lua({:p})", self.lock().state()) } } @@ -344,7 +346,10 @@ impl Lua { if libs.contains(StdLib::PACKAGE) { mlua_expect!(lua.disable_c_modules(), "Error during disabling C modules"); } - unsafe { (*lua.extra.get()).safe = true }; + unsafe { + let rawlua = lua.lock(); + (*rawlua.extra.get()).safe = true; + } Ok(lua) } @@ -400,7 +405,7 @@ impl Lua { } let lua = Lua::init_from_ptr(state); - let extra = lua.extra.get(); + let extra = lua.lock().extra.get(); mlua_expect!( load_from_std_lib(state, libs), @@ -510,6 +515,7 @@ impl Lua { // Create ExtraData let extra = Arc::new(UnsafeCell::new(ExtraData { inner: MaybeUninit::uninit(), + weak: MaybeUninit::uninit(), registered_userdata: FxHashMap::default(), registered_userdata_mt: FxHashMap::default(), last_checked_userdata_mt: (ptr::null(), None), @@ -525,7 +531,7 @@ impl Lua { ref_stack_top: ffi::lua_gettop(ref_thread), ref_free: Vec::new(), wrapped_failure_pool: Vec::with_capacity(WRAPPED_FAILURE_POOL_SIZE), - multivalue_pool: Vec::with_capacity(MULTIVALUE_POOL_SIZE), + // multivalue_pool: Vec::with_capacity(MULTIVALUE_POOL_SIZE), #[cfg(feature = "async")] thread_pool: Vec::new(), wrapped_failure_mt_ptr, @@ -568,15 +574,16 @@ impl Lua { ); assert_stack(main_state, ffi::LUA_MINSTACK); - let inner = Arc::new(LuaInner { + let inner = Arc::new(ReentrantMutex::new(LuaInner { state: Cell::new(state), main_state, extra: Arc::clone(&extra), - }); + })); (*extra.get()).inner.write(Arc::clone(&inner)); #[cfg(not(feature = "module"))] Arc::decrement_strong_count(Arc::as_ptr(&inner)); + (*extra.get()).weak.write(Arc::downgrade(&inner)); Lua(inner) } @@ -587,7 +594,8 @@ impl Lua { /// /// [`StdLib`]: crate::StdLib pub fn load_from_std_lib(&self, libs: StdLib) -> Result<()> { - let is_safe = unsafe { (*self.extra.get()).safe }; + let lua = self.lock(); + let is_safe = unsafe { (*lua.extra.get()).safe }; #[cfg(not(feature = "luau"))] if is_safe && libs.contains(StdLib::DEBUG) { @@ -602,14 +610,14 @@ impl Lua { )); } - let res = unsafe { load_from_std_lib(self.main_state, libs) }; + let res = unsafe { load_from_std_lib(lua.main_state, libs) }; // If `package` library loaded into a safe lua state then disable C modules - let curr_libs = unsafe { (*self.extra.get()).libs }; + let curr_libs = unsafe { (*lua.extra.get()).libs }; if is_safe && (curr_libs ^ (curr_libs | libs)).contains(StdLib::PACKAGE) { mlua_expect!(self.disable_c_modules(), "Error during disabling C modules"); } - unsafe { (*self.extra.get()).libs |= libs }; + unsafe { (*lua.extra.get()).libs |= libs }; res } @@ -629,18 +637,19 @@ impl Lua { /// Behavior is similar to Lua's [`require`] function. /// /// [`require`]: https://www.lua.org/manual/5.4/manual.html#pdf-require - pub fn load_from_function<'lua, T>(&'lua self, modname: &str, func: Function<'lua>) -> Result<T> + pub fn load_from_function<T>(&self, modname: &str, func: Function) -> Result<T> where - T: FromLua<'lua>, + T: FromLua, { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); let loaded = unsafe { let _sg = StackGuard::new(state); check_stack(state, 2)?; protect_lua!(state, 0, 1, fn(state) { ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, cstr!("_LOADED")); })?; - Table(self.pop_ref()) + Table(lua.pop_ref()) }; let modname = self.create_string(modname)?; @@ -666,14 +675,15 @@ impl Lua { /// /// [`package.loaded`]: https://www.lua.org/manual/5.4/manual.html#pdf-package.loaded pub fn unload(&self, modname: &str) -> Result<()> { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); let loaded = unsafe { let _sg = StackGuard::new(state); check_stack(state, 2)?; protect_lua!(state, 0, 1, fn(state) { ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, cstr!("_LOADED")); })?; - Table(self.pop_ref()) + Table(lua.pop_ref()) }; let modname = self.create_string(modname)?; @@ -709,22 +719,23 @@ impl Lua { // The returned value then pushed onto the stack. #[doc(hidden)] #[cfg(not(tarpaulin_include))] - pub unsafe fn entrypoint<'lua, A, R, F>(self, state: *mut ffi::lua_State, func: F) -> c_int + pub unsafe fn entrypoint<A, R, F>(self, state: *mut ffi::lua_State, func: F) -> c_int where - A: FromLuaMulti<'lua>, + A: FromLuaMulti, R: IntoLua, - F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static, + F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static, { - let extra = self.extra.get(); + let extra = self.lock().extra.get(); // `self` is no longer needed and must be dropped at this point to avoid possible memory leak // in case of possible longjmp (lua_error) below drop(self); callback_error_ext(state, extra, move |nargs| { - let lua: &Lua = mem::transmute((*extra).inner.assume_init_ref()); - let _guard = StateGuard::new(&lua.0, state); - let args = A::from_stack_args(nargs, 1, None, lua)?; - func(lua, args)?.push_into_stack(lua)?; + let lua = (*extra).lua(); + let rawlua = lua.lock(); + let _guard = StateGuard::new(&rawlua, state); + let args = A::from_stack_args(nargs, 1, None, &rawlua)?; + func(lua, args)?.push_into_stack(&rawlua)?; Ok(1) }) } @@ -732,10 +743,10 @@ impl Lua { // A simple module entrypoint without arguments #[doc(hidden)] #[cfg(not(tarpaulin_include))] - pub unsafe fn entrypoint1<'lua, R, F>(self, state: *mut ffi::lua_State, func: F) -> c_int + pub unsafe fn entrypoint1<R, F>(self, state: *mut ffi::lua_State, func: F) -> c_int where R: IntoLua, - F: Fn(&'lua Lua) -> Result<R> + MaybeSend + 'static, + F: Fn(&Lua) -> Result<R> + MaybeSend + 'static, { self.entrypoint(state, move |lua, _: ()| func(lua)) } @@ -778,9 +789,10 @@ impl Lua { #[cfg(any(feature = "luau", docsrs))] #[cfg_attr(docsrs, doc(cfg(feature = "luau")))] pub fn sandbox(&self, enabled: bool) -> Result<()> { + let lua = self.lock(); unsafe { - if (*self.extra.get()).sandboxed != enabled { - let state = self.main_state; + if (*lua.extra.get()).sandboxed != enabled { + let state = lua.main_state; check_stack(state, 3)?; protect_lua!(state, 0, 0, |state| { if enabled { @@ -788,12 +800,12 @@ impl Lua { ffi::luaL_sandboxthread(state); } else { // Restore original `LUA_GLOBALSINDEX` - ffi::lua_xpush(self.ref_thread(), state, ffi::LUA_GLOBALSINDEX); + ffi::lua_xpush(lua.ref_thread(), state, ffi::LUA_GLOBALSINDEX); ffi::lua_replace(state, ffi::LUA_GLOBALSINDEX); ffi::luaL_sandbox(state, 0); } })?; - (*self.extra.get()).sandboxed = enabled; + (*lua.extra.get()).sandboxed = enabled; } Ok(()) } @@ -843,42 +855,8 @@ impl Lua { where F: Fn(&Lua, Debug) -> Result<()> + MaybeSend + 'static, { - unsafe { self.set_thread_hook(self.state(), triggers, callback) }; - } - - /// Sets a 'hook' function for a thread (coroutine). - #[cfg(not(feature = "luau"))] - pub(crate) unsafe fn set_thread_hook<F>( - &self, - state: *mut ffi::lua_State, - triggers: HookTriggers, - callback: F, - ) where - F: Fn(&Lua, Debug) -> Result<()> + MaybeSend + 'static, - { - unsafe extern "C-unwind" fn hook_proc(state: *mut ffi::lua_State, ar: *mut ffi::lua_Debug) { - let extra = extra_data(state); - if (*extra).hook_thread != state { - // Hook was destined for a different thread, ignore - ffi::lua_sethook(state, None, 0, 0); - return; - } - callback_error_ext(state, extra, move |_| { - let hook_cb = (*extra).hook_callback.clone(); - let hook_cb = mlua_expect!(hook_cb, "no hook callback set in hook_proc"); - if Arc::strong_count(&hook_cb) > 2 { - return Ok(()); // Don't allow recursion - } - let lua: &Lua = mem::transmute((*extra).inner.assume_init_ref()); - let _guard = StateGuard::new(&lua.0, state); - let debug = Debug::new(lua, ar); - hook_cb(lua, debug) - }) - } - - (*self.extra.get()).hook_callback = Some(Arc::new(callback)); - (*self.extra.get()).hook_thread = state; // Mark for what thread the hook is set - ffi::lua_sethook(state, Some(hook_proc), triggers.mask(), triggers.count()); + let lua = self.lock(); + unsafe { lua.set_thread_hook(lua.state(), triggers, callback) }; } /// Removes any hook previously set by [`Lua::set_hook()`] or [`Thread::set_hook()`]. @@ -887,18 +865,19 @@ impl Lua { #[cfg(not(feature = "luau"))] #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))] pub fn remove_hook(&self) { + let lua = self.lock(); unsafe { - let state = self.state(); + let state = lua.state(); ffi::lua_sethook(state, None, 0, 0); - match get_main_state(self.main_state) { + match get_main_state(lua.main_state) { Some(main_state) if !ptr::eq(state, main_state) => { // If main_state is different from state, remove hook from it too ffi::lua_sethook(main_state, None, 0, 0); } _ => {} }; - (*self.extra.get()).hook_callback = None; - (*self.extra.get()).hook_thread = ptr::null_mut(); + (*lua.extra.get()).hook_callback = None; + (*lua.extra.get()).hook_thread = ptr::null_mut(); } } @@ -963,8 +942,9 @@ impl Lua { if Arc::strong_count(&interrupt_cb) > 2 { return Ok(VmState::Continue); // Don't allow recursion } - let lua: &Lua = mem::transmute((*extra).inner.assume_init_ref()); - let _guard = StateGuard::new(&lua.0, state); + let lua = (*extra).lua(); + let rawlua = lua.lock(); + let _guard = StateGuard::new(&rawlua, state); interrupt_cb(lua) }); match result { @@ -975,9 +955,10 @@ impl Lua { } } + let lua = self.lock(); unsafe { - (*self.extra.get()).interrupt_callback = Some(Arc::new(callback)); - (*ffi::lua_callbacks(self.main_state)).interrupt = Some(interrupt_proc); + (*lua.extra.get()).interrupt_callback = Some(Arc::new(callback)); + (*ffi::lua_callbacks(lua.main_state)).interrupt = Some(interrupt_proc); } } @@ -987,9 +968,10 @@ impl Lua { #[cfg(any(feature = "luau", docsrs))] #[cfg_attr(docsrs, doc(cfg(feature = "luau")))] pub fn remove_interrupt(&self) { + let lua = self.lock(); unsafe { - (*self.extra.get()).interrupt_callback = None; - (*ffi::lua_callbacks(self.main_state)).interrupt = None; + (*lua.extra.get()).interrupt_callback = None; + (*ffi::lua_callbacks(lua.main_state)).interrupt = None; } } @@ -1004,8 +986,9 @@ impl Lua { { unsafe extern "C-unwind" fn warn_proc(ud: *mut c_void, msg: *const c_char, tocont: c_int) { let extra = ud as *mut ExtraData; - let lua: &Lua = mem::transmute((*extra).inner.assume_init_ref()); - callback_error_ext(lua.state(), extra, |_| { + let lua = (*extra).lua(); + let rawlua = lua.lock(); + callback_error_ext(rawlua.state(), extra, |_| { let cb = mlua_expect!( (*extra).warn_callback.as_ref(), "no warning callback set in warn_proc" @@ -1015,10 +998,11 @@ impl Lua { }); } - let state = self.main_state; + let lua = self.lock(); + let state = lua.main_state; unsafe { - (*self.extra.get()).warn_callback = Some(Box::new(callback)); - ffi::lua_setwarnf(state, Some(warn_proc), self.extra.get() as *mut c_void); + (*lua.extra.get()).warn_callback = Some(Box::new(callback)); + ffi::lua_setwarnf(state, Some(warn_proc), lua.extra.get() as *mut c_void); } } @@ -1030,9 +1014,10 @@ impl Lua { #[cfg(feature = "lua54")] #[cfg_attr(docsrs, doc(cfg(feature = "lua54")))] pub fn remove_warning_function(&self) { + let lua = self.lock(); unsafe { - (*self.extra.get()).warn_callback = None; - ffi::lua_setwarnf(self.main_state, None, ptr::null_mut()); + (*lua.extra.get()).warn_callback = None; + ffi::lua_setwarnf(lua.main_state, None, ptr::null_mut()); } } @@ -1050,9 +1035,10 @@ impl Lua { bytes[..msg.len()].copy_from_slice(msg.as_bytes()); let real_len = bytes.iter().position(|&c| c == 0).unwrap(); bytes.truncate(real_len); + let lua = self.lock(); unsafe { ffi::lua_warning( - self.state(), + lua.state(), bytes.as_ptr() as *const c_char, incomplete as c_int, ); @@ -1067,30 +1053,32 @@ impl Lua { /// /// [`Debug`]: crate::hook::Debug pub fn inspect_stack(&self, level: usize) -> Option<Debug> { + let lua = self.lock(); unsafe { let mut ar: ffi::lua_Debug = mem::zeroed(); let level = level as c_int; #[cfg(not(feature = "luau"))] - if ffi::lua_getstack(self.state(), level, &mut ar) == 0 { + if ffi::lua_getstack(lua.state(), level, &mut ar) == 0 { return None; } #[cfg(feature = "luau")] - if ffi::lua_getinfo(self.state(), level, cstr!(""), &mut ar) == 0 { + if ffi::lua_getinfo(lua.state(), level, cstr!(""), &mut ar) == 0 { return None; } - Some(Debug::new_owned(self, level, ar)) + Some(Debug::new_owned(lua, level, ar)) } } /// Returns the amount of memory (in bytes) currently used inside this Lua state. pub fn used_memory(&self) -> usize { + let lua = self.lock(); unsafe { - match MemoryState::get(self.main_state) { + match MemoryState::get(lua.main_state) { mem_state if !mem_state.is_null() => (*mem_state).used_memory(), _ => { // Get data from the Lua GC - let used_kbytes = ffi::lua_gc(self.main_state, ffi::LUA_GCCOUNT, 0); - let used_kbytes_rem = ffi::lua_gc(self.main_state, ffi::LUA_GCCOUNTB, 0); + let used_kbytes = ffi::lua_gc(lua.main_state, ffi::LUA_GCCOUNT, 0); + let used_kbytes_rem = ffi::lua_gc(lua.main_state, ffi::LUA_GCCOUNTB, 0); (used_kbytes as usize) * 1024 + (used_kbytes_rem as usize) } } @@ -1105,8 +1093,9 @@ impl Lua { /// /// Does not work in module mode where Lua state is managed externally. pub fn set_memory_limit(&self, limit: usize) -> Result<usize> { + let lua = self.lock(); unsafe { - match MemoryState::get(self.main_state) { + match MemoryState::get(lua.main_state) { mem_state if !mem_state.is_null() => Ok((*mem_state).set_memory_limit(limit)), _ => Err(Error::MemoryLimitNotAvailable), } @@ -1123,17 +1112,20 @@ impl Lua { feature = "luau" ))] pub fn gc_is_running(&self) -> bool { - unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCISRUNNING, 0) != 0 } + let lua = self.lock(); + unsafe { ffi::lua_gc(lua.main_state, ffi::LUA_GCISRUNNING, 0) != 0 } } /// Stop the Lua GC from running pub fn gc_stop(&self) { - unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCSTOP, 0) }; + let lua = self.lock(); + unsafe { ffi::lua_gc(lua.main_state, ffi::LUA_GCSTOP, 0) }; } /// Restarts the Lua GC if it is not running pub fn gc_restart(&self) { - unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCRESTART, 0) }; + let lua = self.lock(); + unsafe { ffi::lua_gc(lua.main_state, ffi::LUA_GCRESTART, 0) }; } /// Perform a full garbage-collection cycle. @@ -1141,9 +1133,10 @@ impl Lua { /// It may be necessary to call this function twice to collect all currently unreachable /// objects. Once to finish the current gc cycle, and once to start and finish the next cycle. pub fn gc_collect(&self) -> Result<()> { + let lua = self.lock(); unsafe { - check_stack(self.main_state, 2)?; - protect_lua!(self.main_state, 0, 0, fn(state) ffi::lua_gc(state, ffi::LUA_GCCOLLECT, 0)) + check_stack(lua.main_state, 2)?; + protect_lua!(lua.main_state, 0, 0, fn(state) ffi::lua_gc(state, ffi::LUA_GCCOLLECT, 0)) } } @@ -1159,9 +1152,10 @@ impl Lua { /// if `kbytes` is 0, then this is the same as calling `gc_step`. Returns true if this step has /// finished a collection cycle. pub fn gc_step_kbytes(&self, kbytes: c_int) -> Result<bool> { + let lua = self.lock(); unsafe { - check_stack(self.main_state, 3)?; - protect_lua!(self.main_state, 0, 0, |state| { + check_stack(lua.main_state, 3)?; + protect_lua!(lua.main_state, 0, 0, |state| { ffi::lua_gc(state, ffi::LUA_GCSTEP, kbytes) != 0 }) } @@ -1176,11 +1170,12 @@ impl Lua { /// /// [documentation]: https://www.lua.org/manual/5.4/manual.html#2.5 pub fn gc_set_pause(&self, pause: c_int) -> c_int { + let lua = self.lock(); unsafe { #[cfg(not(feature = "luau"))] - return ffi::lua_gc(self.main_state, ffi::LUA_GCSETPAUSE, pause); + return ffi::lua_gc(lua.main_state, ffi::LUA_GCSETPAUSE, pause); #[cfg(feature = "luau")] - return ffi::lua_gc(self.main_state, ffi::LUA_GCSETGOAL, pause); + return ffi::lua_gc(lua.main_state, ffi::LUA_GCSETGOAL, pause); } } @@ -1191,7 +1186,8 @@ impl Lua { /// /// [documentation]: https://www.lua.org/manual/5.4/manual.html#2.5 pub fn gc_set_step_multiplier(&self, step_multiplier: c_int) -> c_int { - unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCSETSTEPMUL, step_multiplier) } + let lua = self.lock(); + unsafe { ffi::lua_gc(lua.main_state, ffi::LUA_GCSETSTEPMUL, step_multiplier) } } /// Changes the collector to incremental mode with the given parameters. @@ -1201,7 +1197,8 @@ impl Lua { /// /// [documentation]: https://www.lua.org/manual/5.4/manual.html#2.5.1 pub fn gc_inc(&self, pause: c_int, step_multiplier: c_int, step_size: c_int) -> GCMode { - let state = self.main_state; + let lua = self.lock(); + let state = lua.main_state; #[cfg(any( feature = "lua53", @@ -1254,7 +1251,8 @@ impl Lua { #[cfg(feature = "lua54")] #[cfg_attr(docsrs, doc(cfg(feature = "lua54")))] pub fn gc_gen(&self, minor_multiplier: c_int, major_multiplier: c_int) -> GCMode { - let state = self.main_state; + let lua = self.lock(); + let state = lua.main_state; let prev_mode = unsafe { ffi::lua_gc(state, ffi::LUA_GCGEN, minor_multiplier, major_multiplier) }; match prev_mode { @@ -1275,7 +1273,8 @@ impl Lua { #[cfg(any(feature = "luau", doc))] #[cfg_attr(docsrs, doc(cfg(feature = "luau")))] pub fn set_compiler(&self, compiler: Compiler) { - unsafe { (*self.extra.get()).compiler = Some(compiler) }; + let lua = self.lock(); + unsafe { (*lua.extra.get()).compiler = Some(compiler) }; } /// Toggles JIT compilation mode for new chunks of code. @@ -1311,62 +1310,16 @@ impl Lua { /// /// [`Chunk::exec`]: crate::Chunk::exec #[track_caller] - pub fn load<'lua, 'a>(&'lua self, chunk: impl AsChunk<'lua, 'a>) -> Chunk<'lua, 'a> { + pub fn load<'a>(&self, chunk: impl AsChunk<'a>) -> Chunk<'a> { let caller = Location::caller(); Chunk { - lua: self, + lua: self.weak(), name: chunk.name().unwrap_or_else(|| caller.to_string()), env: chunk.environment(self), mode: chunk.mode(), source: chunk.source(), #[cfg(feature = "luau")] - compiler: unsafe { (*self.extra.get()).compiler.clone() }, - } - } - - pub(crate) fn load_chunk<'lua>( - &'lua self, - name: Option<&CStr>, - env: Option<Table>, - mode: Option<ChunkMode>, - source: &[u8], - ) -> Result<Function<'lua>> { - let state = self.state(); - unsafe { - let _sg = StackGuard::new(state); - check_stack(state, 1)?; - - let mode_str = match mode { - Some(ChunkMode::Binary) => cstr!("b"), - Some(ChunkMode::Text) => cstr!("t"), - None => cstr!("bt"), - }; - - match ffi::luaL_loadbufferx( - state, - source.as_ptr() as *const c_char, - source.len(), - name.map(|n| n.as_ptr()).unwrap_or_else(ptr::null), - mode_str, - ) { - ffi::LUA_OK => { - if let Some(env) = env { - self.push_ref(&env.0); - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - ffi::lua_setupvalue(state, -2, 1); - #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))] - ffi::lua_setfenv(state, -2); - } - - #[cfg(feature = "luau-jit")] - if (*self.extra.get()).enable_jit && ffi::luau_codegen_supported() != 0 { - ffi::luau_codegen_compile(state, -1); - } - - Ok(Function(self.pop_ref())) - } - err => Err(pop_error(state, err)), - } + compiler: unsafe { (*self.lock().extra.get()).compiler.clone() }, } } @@ -1374,17 +1327,18 @@ impl Lua { /// embedded nulls, so in addition to `&str` and `&String`, you can also pass plain `&[u8]` /// here. pub fn create_string(&self, s: impl AsRef<[u8]>) -> Result<String> { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); unsafe { - if self.unlikely_memory_error() { - push_string(self.ref_thread(), s.as_ref(), false)?; - return Ok(String(self.pop_ref_thread())); + if lua.unlikely_memory_error() { + push_string(lua.ref_thread(), s.as_ref(), false)?; + return Ok(String(lua.pop_ref_thread())); } let _sg = StackGuard::new(state); check_stack(state, 3)?; push_string(state, s.as_ref(), true)?; - Ok(String(self.pop_ref())) + Ok(String(lua.pop_ref())) } } @@ -1395,17 +1349,18 @@ impl Lua { /// [buffer]: https://luau-lang.org/library#buffer-library #[cfg(feature = "luau")] pub fn create_buffer(&self, buf: impl AsRef<[u8]>) -> Result<AnyUserData> { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); unsafe { - if self.unlikely_memory_error() { - crate::util::push_buffer(self.ref_thread(), buf.as_ref(), false)?; - return Ok(AnyUserData(self.pop_ref_thread(), SubtypeId::Buffer)); + if lua.unlikely_memory_error() { + crate::util::push_buffer(lua.ref_thread(), buf.as_ref(), false)?; + return Ok(AnyUserData(lua.pop_ref_thread(), SubtypeId::Buffer)); } let _sg = StackGuard::new(state); check_stack(state, 4)?; crate::util::push_buffer(state, buf.as_ref(), true)?; - Ok(AnyUserData(self.pop_ref(), SubtypeId::Buffer)) + Ok(AnyUserData(lua.pop_ref(), SubtypeId::Buffer)) } } @@ -1419,39 +1374,41 @@ impl Lua { /// `nrec` is a hint for how many other elements the table will have. /// Lua may use these hints to preallocate memory for the new table. pub fn create_table_with_capacity(&self, narr: usize, nrec: usize) -> Result<Table> { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); unsafe { - if self.unlikely_memory_error() { - push_table(self.ref_thread(), narr, nrec, false)?; - return Ok(Table(self.pop_ref_thread())); + if lua.unlikely_memory_error() { + push_table(lua.ref_thread(), narr, nrec, false)?; + return Ok(Table(lua.pop_ref_thread())); } let _sg = StackGuard::new(state); check_stack(state, 3)?; push_table(state, narr, nrec, true)?; - Ok(Table(self.pop_ref())) + Ok(Table(lua.pop_ref())) } } /// Creates a table and fills it with values from an iterator. - pub fn create_table_from<'lua, K, V, I>(&'lua self, iter: I) -> Result<Table<'lua>> + pub fn create_table_from<K, V, I>(&self, iter: I) -> Result<Table> where K: IntoLua, V: IntoLua, I: IntoIterator<Item = (K, V)>, { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); unsafe { let _sg = StackGuard::new(state); check_stack(state, 6)?; let iter = iter.into_iter(); let lower_bound = iter.size_hint().0; - let protect = !self.unlikely_memory_error(); + let protect = !lua.unlikely_memory_error(); push_table(state, 0, lower_bound, protect)?; for (k, v) in iter { - self.push(k)?; - self.push(v)?; + lua.push(k)?; + lua.push(v)?; if protect { protect_lua!(state, 3, 1, fn(state) ffi::lua_rawset(state, -3))?; } else { @@ -1459,27 +1416,28 @@ impl Lua { } } - Ok(Table(self.pop_ref())) + Ok(Table(lua.pop_ref())) } } /// Creates a table from an iterator of values, using `1..` as the keys. - pub fn create_sequence_from<'lua, T, I>(&'lua self, iter: I) -> Result<Table<'lua>> + pub fn create_sequence_from<T, I>(&self, iter: I) -> Result<Table> where T: IntoLua, I: IntoIterator<Item = T>, { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); unsafe { let _sg = StackGuard::new(state); check_stack(state, 5)?; let iter = iter.into_iter(); let lower_bound = iter.size_hint().0; - let protect = !self.unlikely_memory_error(); + let protect = !lua.unlikely_memory_error(); push_table(state, lower_bound, 0, protect)?; for (i, v) in iter.enumerate() { - self.push(v)?; + lua.push(v)?; if protect { protect_lua!(state, 2, 1, |state| { ffi::lua_rawseti(state, -2, (i + 1) as Integer); @@ -1489,7 +1447,7 @@ impl Lua { } } - Ok(Table(self.pop_ref())) + Ok(Table(lua.pop_ref())) } } @@ -1538,15 +1496,16 @@ impl Lua { /// /// [`IntoLua`]: crate::IntoLua /// [`IntoLuaMulti`]: crate::IntoLuaMulti - pub fn create_function<'lua, A, R, F>(&'lua self, func: F) -> Result<Function<'lua>> + pub fn create_function<A, R, F>(&self, func: F) -> Result<Function> where - A: FromLuaMulti<'lua>, + A: FromLuaMulti, R: IntoLuaMulti, - F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static, + F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static, { - self.create_callback(Box::new(move |lua, nargs| unsafe { + let lua = self.lock(); + lua.create_callback(Box::new(move |lua, nargs| unsafe { let args = A::from_stack_args(nargs, 1, None, lua)?; - func(lua, args)?.push_into_stack_multi(lua) + func(lua.lua(), args)?.push_into_stack_multi(lua) })) } @@ -1556,11 +1515,11 @@ impl Lua { /// [`create_function`] for more information about the implementation. /// /// [`create_function`]: #method.create_function - pub fn create_function_mut<'lua, A, R, F>(&'lua self, func: F) -> Result<Function<'lua>> + pub fn create_function_mut<A, R, F>(&self, func: F) -> Result<Function> where - A: FromLuaMulti<'lua>, + A: FromLuaMulti, R: IntoLuaMulti, - F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static, + F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static, { let func = RefCell::new(func); self.create_function(move |lua, args| { @@ -1575,10 +1534,11 @@ impl Lua { /// # Safety /// This function is unsafe because provides a way to execute unsafe C function. pub unsafe fn create_c_function(&self, func: ffi::lua_CFunction) -> Result<Function> { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); check_stack(state, 1)?; ffi::lua_pushcfunction(state, func); - Ok(Function(self.pop_ref())) + Ok(Function(lua.pop_ref())) } /// Wraps a Rust async function or closure, creating a callable Lua function handle to it. @@ -1622,104 +1582,32 @@ impl Lua { /// [`AsyncThread`]: crate::AsyncThread #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - pub fn create_async_function<'lua, A, R, F, FR>(&'lua self, func: F) -> Result<Function<'lua>> + pub fn create_async_function<'lua, 'a, F, A, FR, R>(&'lua self, func: F) -> Result<Function> where - A: FromLuaMulti<'lua>, + 'lua: 'a, + F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static, + A: FromLuaMulti, + FR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti, - F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static, - FR: Future<Output = Result<R>> + 'lua, { - self.create_async_callback(Box::new(move |lua, args| unsafe { + let lua = self.lock(); + lua.create_async_callback(Box::new(move |rawlua, args| unsafe { + // let rawlua = mem::transmute::<&LuaInner, &LuaInner>(rawlua); + let lua = rawlua.lua(); let args = match A::from_lua_args(args, 1, None, lua) { Ok(args) => args, Err(e) => return Box::pin(future::err(e)), }; let fut = func(lua, args); - Box::pin(async move { fut.await?.push_into_stack_multi(lua) }) + Box::pin(async move { fut.await?.push_into_stack_multi(rawlua) }) })) } /// Wraps a Lua function into a new thread (or coroutine). /// /// Equivalent to `coroutine.create`. - pub fn create_thread<'lua>(&'lua self, func: Function) -> Result<Thread<'lua>> { - self.create_thread_inner(&func) - } - - /// Wraps a Lua function into a new thread (or coroutine). - /// - /// Takes function by reference. - fn create_thread_inner<'lua>(&'lua self, func: &Function) -> Result<Thread<'lua>> { - let state = self.state(); - unsafe { - let _sg = StackGuard::new(state); - check_stack(state, 3)?; - - let thread_state = if self.unlikely_memory_error() { - ffi::lua_newthread(state) - } else { - protect_lua!(state, 0, 1, |state| ffi::lua_newthread(state))? - }; - self.push_ref(&func.0); - ffi::lua_xmove(state, thread_state, 1); - - Ok(Thread::new(self.pop_ref())) - } - } - - /// Wraps a Lua function into a new or recycled thread (coroutine). - #[cfg(feature = "async")] - pub(crate) fn create_recycled_thread<'lua>( - &'lua self, - func: &Function, - ) -> Result<Thread<'lua>> { - #[cfg(any(feature = "lua54", feature = "luau"))] - unsafe { - let state = self.state(); - let _sg = StackGuard::new(state); - check_stack(state, 1)?; - - if let Some(index) = (*self.extra.get()).thread_pool.pop() { - let thread_state = ffi::lua_tothread(self.ref_thread(), index); - self.push_ref(&func.0); - ffi::lua_xmove(state, thread_state, 1); - - #[cfg(feature = "luau")] - { - // Inherit `LUA_GLOBALSINDEX` from the caller - ffi::lua_xpush(state, thread_state, ffi::LUA_GLOBALSINDEX); - ffi::lua_replace(thread_state, ffi::LUA_GLOBALSINDEX); - } - - return Ok(Thread::new(ValueRef::new(self, index))); - } - }; - self.create_thread_inner(func) - } - - /// Resets thread (coroutine) and returns to the pool for later use. - #[cfg(feature = "async")] - #[cfg(any(feature = "lua54", feature = "luau"))] - pub(crate) unsafe fn recycle_thread(&self, thread: &mut Thread) -> bool { - let extra = &mut *self.extra.get(); - if extra.thread_pool.len() < extra.thread_pool.capacity() { - let thread_state = ffi::lua_tothread(extra.ref_thread, thread.0.index); - #[cfg(all(feature = "lua54", not(feature = "vendored")))] - let status = ffi::lua_resetthread(thread_state); - #[cfg(all(feature = "lua54", feature = "vendored"))] - let status = ffi::lua_closethread(thread_state, self.state()); - #[cfg(feature = "lua54")] - if status != ffi::LUA_OK { - // Error object is on top, drop it - ffi::lua_settop(thread_state, 0); - } - #[cfg(feature = "luau")] - ffi::lua_resetthread(thread_state); - extra.thread_pool.push(thread.0.index); - thread.0.drop = false; - return true; - } - false + pub fn create_thread(&self, func: Function) -> Result<Thread> { + self.lock().create_thread_inner(&func) } /// Creates a Lua userdata object from a custom userdata type. @@ -1730,7 +1618,8 @@ impl Lua { where T: UserData + MaybeSend + 'static, { - unsafe { self.make_userdata(UserDataCell::new(data)) } + let lua = self.lock(); + unsafe { lua.make_userdata(UserDataVariant::new(data)) } } /// Creates a Lua userdata object from a custom serializable userdata type. @@ -1743,7 +1632,8 @@ impl Lua { where T: UserData + Serialize + MaybeSend + 'static, { - unsafe { self.make_userdata(UserDataCell::new_ser(data)) } + let lua = self.lock(); + unsafe { lua.make_userdata(UserDataVariant::new_ser(data)) } } /// Creates a Lua userdata object from a custom Rust type. @@ -1758,7 +1648,8 @@ impl Lua { where T: MaybeSend + 'static, { - unsafe { self.make_any_userdata(UserDataCell::new(data)) } + let lua = self.lock(); + unsafe { lua.make_any_userdata(UserDataVariant::new(data)) } } /// Creates a Lua userdata object from a custom serializable Rust type. @@ -1773,7 +1664,8 @@ impl Lua { where T: Serialize + MaybeSend + 'static, { - unsafe { self.make_any_userdata(UserDataCell::new_ser(data)) } + let lua = self.lock(); + unsafe { lua.make_any_userdata(UserDataVariant::new_ser(data)) } } /// Registers a custom Rust type in Lua to use in userdata objects. @@ -1786,17 +1678,18 @@ impl Lua { let mut registry = UserDataRegistry::new(); f(&mut registry); + let lua = self.lock(); unsafe { // Deregister the type if it already registered let type_id = TypeId::of::<T>(); - if let Some(&table_id) = (*self.extra.get()).registered_userdata.get(&type_id) { - ffi::luaL_unref(self.state(), ffi::LUA_REGISTRYINDEX, table_id); + if let Some(&table_id) = (*lua.extra.get()).registered_userdata.get(&type_id) { + ffi::luaL_unref(lua.state(), ffi::LUA_REGISTRYINDEX, table_id); } // Register the type - self.register_userdata_metatable(registry)?; - Ok(()) + lua.register_userdata_metatable(registry)?; } + Ok(()) } /// Create a Lua userdata "proxy" object from a custom userdata type. @@ -1816,11 +1709,11 @@ impl Lua { /// struct MyUserData(i32); /// /// impl UserData for MyUserData { - /// fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + /// fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) { /// fields.add_field_method_get("val", |_, this| Ok(this.0)); /// } /// - /// fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + /// fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { /// methods.add_function("new", |_, value: i32| Ok(MyUserData(value))); /// } /// } @@ -1836,7 +1729,8 @@ impl Lua { where T: UserData + 'static, { - unsafe { self.make_userdata(UserDataCell::new(UserDataProxy::<T>(PhantomData))) } + let lua = self.lock(); + unsafe { lua.make_userdata(UserDataVariant::new(UserDataProxy::<T>(PhantomData))) } } /// Sets the metatable for a Luau builtin vector type. @@ -1862,7 +1756,8 @@ impl Lua { /// Returns a handle to the global environment. pub fn globals(&self) -> Table { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); unsafe { let _sg = StackGuard::new(state); assert_stack(state, 1); @@ -1870,19 +1765,20 @@ impl Lua { ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS); #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))] ffi::lua_pushvalue(state, ffi::LUA_GLOBALSINDEX); - Table(self.pop_ref()) + Table(lua.pop_ref()) } } /// Returns a handle to the active `Thread`. For calls to `Lua` this will be the main Lua thread, /// for parameters given to a callback, this will be whatever Lua thread called the callback. pub fn current_thread(&self) -> Thread { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); unsafe { let _sg = StackGuard::new(state); assert_stack(state, 1); ffi::lua_pushthread(state); - Thread::new(self.pop_ref()) + Thread::new(&lua, lua.pop_ref()) } } @@ -1906,31 +1802,32 @@ impl Lua { /// dropped. `Function` types will error when called, and `AnyUserData` will be typeless. It /// would be impossible to prevent handles to scoped values from escaping anyway, since you /// would always be able to smuggle them through Lua state. - pub fn scope<'lua, 'scope, R>( - &'lua self, - f: impl FnOnce(&Scope<'lua, 'scope>) -> Result<R>, - ) -> Result<R> - where - 'lua: 'scope, - { - f(&Scope::new(self)) - } + // pub fn scope<'lua, 'scope, R>( + // &'lua self, + // f: impl FnOnce(&Scope<'lua, 'scope>) -> Result<R>, + // ) -> Result<R> + // where + // 'lua: 'scope, + // { + // f(&Scope::new(self)) + // } /// Attempts to coerce a Lua value into a String in a manner consistent with Lua's internal /// behavior. /// /// To succeed, the value must be a string (in which case this is a no-op), an integer, or a /// number. - pub fn coerce_string<'lua>(&'lua self, v: Value<'lua>) -> Result<Option<String<'lua>>> { + pub fn coerce_string(&self, v: Value) -> Result<Option<String>> { Ok(match v { Value::String(s) => Some(s), v => unsafe { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); let _sg = StackGuard::new(state); check_stack(state, 4)?; - self.push_value(&v)?; - let res = if self.unlikely_memory_error() { + lua.push_value(&v)?; + let res = if lua.unlikely_memory_error() { ffi::lua_tolstring(state, -1, ptr::null_mut()) } else { protect_lua!(state, 1, 1, |state| { @@ -1938,7 +1835,7 @@ impl Lua { })? }; if !res.is_null() { - Some(String(self.pop_ref())) + Some(String(lua.pop_ref())) } else { None } @@ -1956,11 +1853,12 @@ impl Lua { Ok(match v { Value::Integer(i) => Some(i), v => unsafe { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); let _sg = StackGuard::new(state); check_stack(state, 2)?; - self.push_value(&v)?; + lua.push_value(&v)?; let mut isint = 0; let i = ffi::lua_tointegerx(state, -1, &mut isint); if isint == 0 { @@ -1981,11 +1879,12 @@ impl Lua { Ok(match v { Value::Number(n) => Some(n), v => unsafe { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); let _sg = StackGuard::new(state); check_stack(state, 2)?; - self.push_value(&v)?; + lua.push_value(&v)?; let mut isnum = 0; let n = ffi::lua_tonumberx(state, -1, &mut isnum); if isnum == 0 { @@ -1998,25 +1897,22 @@ impl Lua { } /// Converts a value that implements `IntoLua` into a `Value` instance. - pub fn pack<'lua, T: IntoLua>(&'lua self, t: T) -> Result<Value<'lua>> { + pub fn pack<T: IntoLua>(&self, t: T) -> Result<Value> { t.into_lua(self) } /// Converts a `Value` instance into a value that implements `FromLua`. - pub fn unpack<'lua, T: FromLua<'lua>>(&'lua self, value: Value<'lua>) -> Result<T> { + pub fn unpack<T: FromLua>(&self, value: Value) -> Result<T> { T::from_lua(value, self) } /// Converts a value that implements `IntoLuaMulti` into a `MultiValue` instance. - pub fn pack_multi<'lua, T: IntoLuaMulti>(&'lua self, t: T) -> Result<MultiValue<'lua>> { + pub fn pack_multi<T: IntoLuaMulti>(&self, t: T) -> Result<MultiValue> { t.into_lua_multi(self) } /// Converts a `MultiValue` instance into a value that implements `FromLuaMulti`. - pub fn unpack_multi<'lua, T: FromLuaMulti<'lua>>( - &'lua self, - value: MultiValue<'lua>, - ) -> Result<T> { + pub fn unpack_multi<T: FromLuaMulti>(&self, value: MultiValue) -> Result<T> { T::from_lua_multi(value, self) } @@ -2024,16 +1920,17 @@ impl Lua { /// /// This value will be available to rust from all `Lua` instances which share the same main /// state. - pub fn set_named_registry_value<'lua, T>(&'lua self, name: &str, t: T) -> Result<()> + pub fn set_named_registry_value<T>(&self, name: &str, t: T) -> Result<()> where T: IntoLua, { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); unsafe { let _sg = StackGuard::new(state); check_stack(state, 5)?; - self.push(t)?; + lua.push(t)?; rawset_field(state, ffi::LUA_REGISTRYINDEX, name) } } @@ -2044,20 +1941,21 @@ impl Lua { /// get a value previously set by [`set_named_registry_value`]. /// /// [`set_named_registry_value`]: #method.set_named_registry_value - pub fn named_registry_value<'lua, T>(&'lua self, name: &str) -> Result<T> + pub fn named_registry_value<T>(&self, name: &str) -> Result<T> where - T: FromLua<'lua>, + T: FromLua, { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); unsafe { let _sg = StackGuard::new(state); check_stack(state, 3)?; - let protect = !self.unlikely_memory_error(); + let protect = !lua.unlikely_memory_error(); push_string(state, name.as_bytes(), protect)?; ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX); - T::from_stack(-1, self) + T::from_stack(-1, &lua) } } @@ -2081,14 +1979,15 @@ impl Lua { /// /// [`RegistryKey`]: crate::RegistryKey pub fn create_registry_value<T: IntoLua>(&self, t: T) -> Result<RegistryKey> { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); unsafe { let _sg = StackGuard::new(state); check_stack(state, 4)?; - self.push(t)?; + lua.push(t)?; - let unref_list = (*self.extra.get()).registry_unref_list.clone(); + let unref_list = (*lua.extra.get()).registry_unref_list.clone(); // Check if the value is nil (no need to store it in the registry) if ffi::lua_isnil(state, -1) != 0 { @@ -2096,9 +1995,7 @@ impl Lua { } // Try to reuse previously allocated slot - let free_registry_id = mlua_expect!(unref_list.lock(), "unref list poisoned") - .as_mut() - .and_then(|x| x.pop()); + let free_registry_id = unref_list.lock().as_mut().and_then(|x| x.pop()); if let Some(registry_id) = free_registry_id { // It must be safe to replace the value without triggering memory error ffi::lua_rawseti(state, ffi::LUA_REGISTRYINDEX, registry_id as Integer); @@ -2106,7 +2003,7 @@ impl Lua { } // Allocate a new RegistryKey slot - let registry_id = if self.unlikely_memory_error() { + let registry_id = if lua.unlikely_memory_error() { ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX) } else { protect_lua!(state, 1, 0, |state| { @@ -2123,12 +2020,13 @@ impl Lua { /// previously placed by [`create_registry_value`]. /// /// [`create_registry_value`]: #method.create_registry_value - pub fn registry_value<'lua, T: FromLua<'lua>>(&'lua self, key: &RegistryKey) -> Result<T> { - if !self.owns_registry_value(key) { + pub fn registry_value<T: FromLua>(&self, key: &RegistryKey) -> Result<T> { + let lua = self.lock(); + if !lua.owns_registry_value(key) { return Err(Error::MismatchedRegistryKey); } - let state = self.state(); + let state = lua.state(); match key.id() { ffi::LUA_REFNIL => T::from_lua(Value::Nil, self), registry_id => unsafe { @@ -2136,7 +2034,7 @@ impl Lua { check_stack(state, 1)?; ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, registry_id as Integer); - T::from_stack(-1, self) + T::from_stack(-1, &lua) }, } } @@ -2151,12 +2049,13 @@ impl Lua { /// [`create_registry_value`]: #method.create_registry_value /// [`expire_registry_values`]: #method.expire_registry_values pub fn remove_registry_value(&self, key: RegistryKey) -> Result<()> { - if !self.owns_registry_value(&key) { + let lua = self.lock(); + if !lua.owns_registry_value(&key) { return Err(Error::MismatchedRegistryKey); } unsafe { - ffi::luaL_unref(self.state(), ffi::LUA_REGISTRYINDEX, key.take()); + ffi::luaL_unref(lua.state(), ffi::LUA_REGISTRYINDEX, key.take()); } Ok(()) } @@ -2166,18 +2065,15 @@ impl Lua { /// See [`create_registry_value`] for more details. /// /// [`create_registry_value`]: #method.create_registry_value - pub fn replace_registry_value<'lua, T: IntoLua>( - &'lua self, - key: &RegistryKey, - t: T, - ) -> Result<()> { - if !self.owns_registry_value(key) { + pub fn replace_registry_value<T: IntoLua>(&self, key: &RegistryKey, t: T) -> Result<()> { + let lua = self.lock(); + if !lua.owns_registry_value(key) { return Err(Error::MismatchedRegistryKey); } let t = t.into_lua(self)?; - let state = self.state(); + let state = lua.state(); unsafe { let _sg = StackGuard::new(state); check_stack(state, 2)?; @@ -2198,7 +2094,7 @@ impl Lua { } (value, registry_id) => { // It must be safe to replace the value without triggering memory error - self.push_value(&value)?; + lua.push_value(&value)?; ffi::lua_rawseti(state, ffi::LUA_REGISTRYINDEX, registry_id as Integer); } } @@ -2213,8 +2109,7 @@ impl Lua { /// `Error::MismatchedRegistryKey` if passed a `RegistryKey` that was not created with a /// matching `Lua` state. pub fn owns_registry_value(&self, key: &RegistryKey) -> bool { - let registry_unref_list = unsafe { &(*self.extra.get()).registry_unref_list }; - Arc::ptr_eq(&key.unref_list, registry_unref_list) + self.lock().owns_registry_value(key) } /// Remove any registry values whose `RegistryKey`s have all been dropped. @@ -2223,12 +2118,10 @@ impl Lua { /// but you can call this method to remove any unreachable registry values not manually removed /// by `Lua::remove_registry_value`. pub fn expire_registry_values(&self) { - let state = self.state(); + let lua = self.lock(); + let state = lua.state(); unsafe { - let mut unref_list = mlua_expect!( - (*self.extra.get()).registry_unref_list.lock(), - "unref list poisoned" - ); + let mut unref_list = (*lua.extra.get()).registry_unref_list.lock(); let unref_list = mem::replace(&mut *unref_list, Some(Vec::new())); for id in mlua_expect!(unref_list, "unref list not set") { ffi::luaL_unref(state, ffi::LUA_REGISTRYINDEX, id); @@ -2268,7 +2161,8 @@ impl Lua { /// ``` #[track_caller] pub fn set_app_data<T: MaybeSend + 'static>(&self, data: T) -> Option<T> { - let extra = unsafe { &*self.extra.get() }; + let lua = self.lock(); + let extra = unsafe { &*lua.extra.get() }; extra.app_data.insert(data) } @@ -2281,7 +2175,8 @@ impl Lua { /// /// See [`Lua::set_app_data()`] for examples. pub fn try_set_app_data<T: MaybeSend + 'static>(&self, data: T) -> StdResult<Option<T>, T> { - let extra = unsafe { &*self.extra.get() }; + let lua = self.lock(); + let extra = unsafe { &*lua.extra.get() }; extra.app_data.try_insert(data) } @@ -2293,8 +2188,9 @@ impl Lua { /// can be taken out at the same time. #[track_caller] pub fn app_data_ref<T: 'static>(&self) -> Option<AppDataRef<T>> { - let extra = unsafe { &*self.extra.get() }; - extra.app_data.borrow() + let guard = self.lock_arc(); + let extra = unsafe { &*guard.extra.get() }; + extra.app_data.borrow(Some(guard)) } /// Gets a mutable reference to an application data object stored by [`Lua::set_app_data()`] of type `T`. @@ -2304,8 +2200,9 @@ impl Lua { /// Panics if the data object of type `T` is currently borrowed. #[track_caller] pub fn app_data_mut<T: 'static>(&self) -> Option<AppDataRefMut<T>> { - let extra = unsafe { &*self.extra.get() }; - extra.app_data.borrow_mut() + let guard = self.lock_arc(); + let extra = unsafe { &*guard.extra.get() }; + extra.app_data.borrow_mut(Some(guard)) } /// Removes an application data of type `T`. @@ -2315,16 +2212,322 @@ impl Lua { /// Panics if the app data container is currently borrowed. #[track_caller] pub fn remove_app_data<T: 'static>(&self) -> Option<T> { - let extra = unsafe { &*self.extra.get() }; + let lua = self.lock(); + let extra = unsafe { &*lua.extra.get() }; extra.app_data.remove() } + // FIXME + // /// Pushes a value that implements `IntoLua` onto the Lua stack. + // /// + // /// Uses 2 stack spaces, does not call checkstack. + // #[doc(hidden)] + // #[inline(always)] + // pub unsafe fn push(&self, value: impl IntoLua) -> Result<()> { + // // value.push_into_stack(self) + // } + + /// Returns internal `Poll::Pending` constant used for executing async callbacks. + #[cfg(feature = "async")] + #[doc(hidden)] + #[inline] + pub fn poll_pending() -> LightUserData { + LightUserData(&ASYNC_POLL_PENDING as *const u8 as *mut c_void) + } + + // Luau version located in `luau/mod.rs` + #[cfg(not(feature = "luau"))] + fn disable_c_modules(&self) -> Result<()> { + let package: Table = self.globals().get("package")?; + + package.set( + "loadlib", + self.create_function(|_, ()| -> Result<()> { + Err(Error::SafetyError( + "package.loadlib is disabled in safe mode".to_string(), + )) + })?, + )?; + + #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] + let searchers: Table = package.get("searchers")?; + #[cfg(any(feature = "lua51", feature = "luajit"))] + let searchers: Table = package.get("loaders")?; + + let loader = self.create_function(|_, ()| Ok("\n\tcan't load C modules in safe mode"))?; + + // The third and fourth searchers looks for a loader as a C library + searchers.raw_set(3, loader)?; + searchers.raw_remove(4)?; + + Ok(()) + } + + pub(crate) unsafe fn try_from_ptr(state: *mut ffi::lua_State) -> Option<Self> { + let extra = extra_data(state); + if extra.is_null() { + return None; + } + Some(Lua(Arc::clone((*extra).inner.assume_init_ref()))) + } + + #[inline(always)] + pub(crate) fn lock(&self) -> ReentrantMutexGuard<LuaInner> { + self.0.lock() + } + + #[inline(always)] + pub(crate) fn lock_arc(&self) -> LuaGuard { + LuaGuard(self.0.lock_arc()) + } + + #[inline(always)] + pub(crate) unsafe fn guard_unchecked(&self) -> ManuallyDrop<ReentrantMutexGuard<LuaInner>> { + ManuallyDrop::new(self.0.make_guard_unchecked()) + } + + #[inline(always)] + pub(crate) fn weak(&self) -> WeakLua { + WeakLua(Arc::downgrade(&self.0)) + } +} + +impl LuaInner { + #[inline(always)] + pub(crate) fn lua(&self) -> &Lua { + unsafe { (*self.extra.get()).lua() } + } + + #[inline(always)] + pub(crate) fn weak(&self) -> &WeakLua { + unsafe { (*self.extra.get()).weak() } + } + + #[inline(always)] + pub(crate) fn state(&self) -> *mut ffi::lua_State { + self.state.get() + } + + #[cfg(feature = "luau")] + #[inline(always)] + pub(crate) fn main_state(&self) -> *mut ffi::lua_State { + self.main_state + } + + #[inline(always)] + pub(crate) fn ref_thread(&self) -> *mut ffi::lua_State { + unsafe { (*self.extra.get()).ref_thread } + } + + /// See [`Lua::try_set_app_data`] + pub(crate) fn try_set_app_data<T: MaybeSend + 'static>( + &self, + data: T, + ) -> StdResult<Option<T>, T> { + let extra = unsafe { &*self.extra.get() }; + extra.app_data.try_insert(data) + } + + /// See [`Lua::app_data_ref`] + #[track_caller] + pub(crate) fn app_data_ref<T: 'static>(&self) -> Option<AppDataRef<T>> { + let extra = unsafe { &*self.extra.get() }; + extra.app_data.borrow(None) + } + + /// See [`Lua::app_data_mut`] + #[track_caller] + pub(crate) fn app_data_mut<T: 'static>(&self) -> Option<AppDataRefMut<T>> { + let extra = unsafe { &*self.extra.get() }; + extra.app_data.borrow_mut(None) + } + + /// See [`Lua::create_registry_value`] + pub(crate) fn owns_registry_value(&self, key: &RegistryKey) -> bool { + let registry_unref_list = unsafe { &(*self.extra.get()).registry_unref_list }; + Arc::ptr_eq(&key.unref_list, registry_unref_list) + } + + pub(crate) fn load_chunk( + &self, + name: Option<&CStr>, + env: Option<Table>, + mode: Option<ChunkMode>, + source: &[u8], + ) -> Result<Function> { + let state = self.state(); + unsafe { + let _sg = StackGuard::new(state); + check_stack(state, 1)?; + + let mode_str = match mode { + Some(ChunkMode::Binary) => cstr!("b"), + Some(ChunkMode::Text) => cstr!("t"), + None => cstr!("bt"), + }; + + match ffi::luaL_loadbufferx( + state, + source.as_ptr() as *const c_char, + source.len(), + name.map(|n| n.as_ptr()).unwrap_or_else(ptr::null), + mode_str, + ) { + ffi::LUA_OK => { + if let Some(env) = env { + self.push_ref(&env.0); + #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] + ffi::lua_setupvalue(state, -2, 1); + #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))] + ffi::lua_setfenv(state, -2); + } + + #[cfg(feature = "luau-jit")] + if (*self.extra.get()).enable_jit && ffi::luau_codegen_supported() != 0 { + ffi::luau_codegen_compile(state, -1); + } + + Ok(Function(self.pop_ref())) + } + err => Err(pop_error(state, err)), + } + } + } + + /// Sets a 'hook' function for a thread (coroutine). + #[cfg(not(feature = "luau"))] + pub(crate) unsafe fn set_thread_hook<F>( + &self, + state: *mut ffi::lua_State, + triggers: HookTriggers, + callback: F, + ) where + F: Fn(&Lua, Debug) -> Result<()> + MaybeSend + 'static, + { + unsafe extern "C-unwind" fn hook_proc(state: *mut ffi::lua_State, ar: *mut ffi::lua_Debug) { + let extra = extra_data(state); + if (*extra).hook_thread != state { + // Hook was destined for a different thread, ignore + ffi::lua_sethook(state, None, 0, 0); + return; + } + callback_error_ext(state, extra, move |_| { + let hook_cb = (*extra).hook_callback.clone(); + let hook_cb = mlua_expect!(hook_cb, "no hook callback set in hook_proc"); + if Arc::strong_count(&hook_cb) > 2 { + return Ok(()); // Don't allow recursion + } + let lua = (*extra).lua(); + let rawlua = lua.lock(); + let _guard = StateGuard::new(&rawlua, state); + let debug = Debug::new(lua, ar); + hook_cb(lua, debug) + }) + } + + (*self.extra.get()).hook_callback = Some(Arc::new(callback)); + (*self.extra.get()).hook_thread = state; // Mark for what thread the hook is set + ffi::lua_sethook(state, Some(hook_proc), triggers.mask(), triggers.count()); + } + + /// Wraps a Lua function into a new thread (or coroutine). + /// + /// Takes function by reference. + fn create_thread_inner(&self, func: &Function) -> Result<Thread> { + let state = self.state(); + unsafe { + let _sg = StackGuard::new(state); + check_stack(state, 3)?; + + let thread_state = if self.unlikely_memory_error() { + ffi::lua_newthread(state) + } else { + protect_lua!(state, 0, 1, |state| ffi::lua_newthread(state))? + }; + self.push_ref(&func.0); + ffi::lua_xmove(state, thread_state, 1); + + Ok(Thread::new(&self, self.pop_ref())) + } + } + + /// Wraps a Lua function into a new or recycled thread (coroutine). + #[cfg(feature = "async")] + pub(crate) fn create_recycled_thread(&self, func: &Function) -> Result<Thread> { + #[cfg(any(feature = "lua54", feature = "luau"))] + unsafe { + let state = self.state(); + let _sg = StackGuard::new(state); + check_stack(state, 1)?; + + if let Some(index) = (*self.extra.get()).thread_pool.pop() { + let thread_state = ffi::lua_tothread(self.ref_thread(), index); + self.push_ref(&func.0); + ffi::lua_xmove(state, thread_state, 1); + + #[cfg(feature = "luau")] + { + // Inherit `LUA_GLOBALSINDEX` from the caller + ffi::lua_xpush(state, thread_state, ffi::LUA_GLOBALSINDEX); + ffi::lua_replace(thread_state, ffi::LUA_GLOBALSINDEX); + } + + return Ok(Thread::new(self, ValueRef::new(self, index))); + } + }; + self.create_thread_inner(func) + } + + /// Resets thread (coroutine) and returns to the pool for later use. + #[cfg(feature = "async")] + #[cfg(any(feature = "lua54", feature = "luau"))] + pub(crate) unsafe fn recycle_thread(&self, thread: &mut Thread) -> bool { + let extra = &mut *self.extra.get(); + if extra.thread_pool.len() < extra.thread_pool.capacity() { + let thread_state = ffi::lua_tothread(extra.ref_thread, thread.0.index); + #[cfg(all(feature = "lua54", not(feature = "vendored")))] + let status = ffi::lua_resetthread(thread_state); + #[cfg(all(feature = "lua54", feature = "vendored"))] + let status = ffi::lua_closethread(thread_state, self.state()); + #[cfg(feature = "lua54")] + if status != ffi::LUA_OK { + // Error object is on top, drop it + ffi::lua_settop(thread_state, 0); + } + #[cfg(feature = "luau")] + ffi::lua_resetthread(thread_state); + extra.thread_pool.push(thread.0.index); + thread.0.drop = false; + return true; + } + false + } + + // FIXME + // #[inline] + // pub(crate) fn pop_multivalue_from_pool(&self) -> Option<VecDeque<Value>> { + // let extra = unsafe { &mut *self.extra.get() }; + // extra.multivalue_pool.pop() + // } + + // FIXME + // #[inline] + // pub(crate) fn push_multivalue_to_pool(&self, mut multivalue: VecDeque<Value>) { + // let extra = unsafe { &mut *self.extra.get() }; + // if extra.multivalue_pool.len() < MULTIVALUE_POOL_SIZE { + // multivalue.clear(); + // extra + // .multivalue_pool + // .push(unsafe { mem::transmute(multivalue) }); + // } + // } + /// Pushes a value that implements `IntoLua` onto the Lua stack. /// /// Uses 2 stack spaces, does not call checkstack. #[doc(hidden)] #[inline(always)] - pub unsafe fn push<'lua>(&'lua self, value: impl IntoLua) -> Result<()> { + pub unsafe fn push(&self, value: impl IntoLua) -> Result<()> { value.push_into_stack(self) } @@ -2363,7 +2566,7 @@ impl Lua { /// /// Uses 2 stack spaces, does not call checkstack. #[doc(hidden)] - pub unsafe fn pop_value(&self) -> Value { + pub(crate) unsafe fn pop_value(&self) -> Value { let state = self.state(); match ffi::lua_type(state, -1) { ffi::LUA_TNIL => { @@ -2451,7 +2654,7 @@ impl Lua { } } - ffi::LUA_TTHREAD => Value::Thread(Thread::new(self.pop_ref())), + ffi::LUA_TTHREAD => Value::Thread(Thread::new(self, self.pop_ref())), #[cfg(feature = "luau")] ffi::LUA_TBUFFER => { @@ -2554,7 +2757,7 @@ impl Lua { ffi::LUA_TTHREAD => { ffi::lua_xpush(state, self.ref_thread(), idx); - Value::Thread(Thread::new(self.pop_ref_thread())) + Value::Thread(Thread::new(self, self.pop_ref_thread())) } #[cfg(feature = "luau")] @@ -2576,21 +2779,12 @@ impl Lua { } // Pushes a ValueRef value onto the stack, uses 1 stack space, does not call checkstack - pub(crate) unsafe fn push_ref(&self, vref: &ValueRef) { - assert!( - Arc::ptr_eq(&vref.lua.0, &self.0), - "Lua instance passed Value created from a different main Lua state" - ); - ffi::lua_xpush(self.ref_thread(), self.state(), vref.index); - } - - #[cfg(all(feature = "unstable", not(feature = "send")))] - pub(crate) unsafe fn push_owned_ref(&self, vref: &crate::types::OwnedValueRef) { + pub(crate) fn push_ref(&self, vref: &ValueRef) { assert!( - Arc::ptr_eq(&vref.inner, &self.0), + self.weak() == &vref.lua, "Lua instance passed Value created from a different main Lua state" ); - ffi::lua_xpush(self.ref_thread(), self.state(), vref.index); + unsafe { ffi::lua_xpush(self.ref_thread(), self.state(), vref.index) }; } // Pops the topmost element of the stack and stores a reference to it. This pins the object, @@ -2622,29 +2816,15 @@ impl Lua { } } - pub(crate) fn drop_ref_index(&self, index: c_int) { + pub(crate) fn drop_ref(&self, vref: &ValueRef) { unsafe { let ref_thread = self.ref_thread(); ffi::lua_pushnil(ref_thread); - ffi::lua_replace(ref_thread, index); - (*self.extra.get()).ref_free.push(index); + ffi::lua_replace(ref_thread, vref.index); + (*self.extra.get()).ref_free.push(vref.index); } } - #[cfg(all(feature = "unstable", not(feature = "send")))] - pub(crate) fn adopt_owned_ref(&self, vref: crate::types::OwnedValueRef) -> ValueRef { - assert!( - Arc::ptr_eq(&vref.inner, &self.0), - "Lua instance passed Value created from a different main Lua state" - ); - let index = vref.index; - unsafe { - ptr::read(&vref.inner); - mem::forget(vref); - } - ValueRef::new(self, index) - } - #[inline] pub(crate) unsafe fn push_error_traceback(&self) { let state = self.state(); @@ -2655,9 +2835,95 @@ impl Lua { ffi::lua_pushcfunction(state, error_traceback); } - unsafe fn register_userdata_metatable<'lua, T: 'static>( - &'lua self, - mut registry: UserDataRegistry<'lua, T>, + #[inline] + pub(crate) unsafe fn unlikely_memory_error(&self) -> bool { + // MemoryInfo is empty in module mode so we cannot predict memory limits + match MemoryState::get(self.main_state) { + mem_state if !mem_state.is_null() => (*mem_state).memory_limit() == 0, + #[cfg(feature = "module")] + _ => (*self.extra.get()).skip_memory_check, // Check the special flag (only for module mode) + #[cfg(not(feature = "module"))] + _ => false, + } + } + + pub(crate) unsafe fn make_userdata<T>(&self, data: UserDataVariant<T>) -> Result<AnyUserData> + where + T: UserData + 'static, + { + self.make_userdata_with_metatable(data, || { + // Check if userdata/metatable is already registered + let type_id = TypeId::of::<T>(); + if let Some(&table_id) = (*self.extra.get()).registered_userdata.get(&type_id) { + return Ok(table_id as Integer); + } + + // Create new metatable from UserData definition + let mut registry = UserDataRegistry::new(); + T::register(&mut registry); + + self.register_userdata_metatable(registry) + }) + } + + pub(crate) unsafe fn make_any_userdata<T>( + &self, + data: UserDataVariant<T>, + ) -> Result<AnyUserData> + where + T: 'static, + { + self.make_userdata_with_metatable(data, || { + // Check if userdata/metatable is already registered + let type_id = TypeId::of::<T>(); + if let Some(&table_id) = (*self.extra.get()).registered_userdata.get(&type_id) { + return Ok(table_id as Integer); + } + + // Create empty metatable + let registry = UserDataRegistry::new(); + self.register_userdata_metatable::<T>(registry) + }) + } + + unsafe fn make_userdata_with_metatable<T>( + &self, + data: UserDataVariant<T>, + get_metatable_id: impl FnOnce() -> Result<Integer>, + ) -> Result<AnyUserData> { + let state = self.state(); + let _sg = StackGuard::new(state); + check_stack(state, 3)?; + + // We push metatable first to ensure having correct metatable with `__gc` method + ffi::lua_pushnil(state); + ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, get_metatable_id()?); + let protect = !self.unlikely_memory_error(); + #[cfg(not(feature = "lua54"))] + push_userdata(state, data, protect)?; + #[cfg(feature = "lua54")] + push_userdata_uv(state, data, USER_VALUE_MAXSLOT as c_int, protect)?; + ffi::lua_replace(state, -3); + ffi::lua_setmetatable(state, -2); + + // Set empty environment for Lua 5.1 + #[cfg(any(feature = "lua51", feature = "luajit"))] + if protect { + protect_lua!(state, 1, 1, fn(state) { + ffi::lua_newtable(state); + ffi::lua_setuservalue(state, -2); + })?; + } else { + ffi::lua_newtable(state); + ffi::lua_setuservalue(state, -2); + } + + Ok(AnyUserData(self.pop_ref(), SubtypeId::None)) + } + + unsafe fn register_userdata_metatable<T: 'static>( + &self, + mut registry: UserDataRegistry<T>, ) -> Result<Integer> { let state = self.state(); let _sg = StackGuard::new(state); @@ -2680,7 +2946,8 @@ impl Lua { let mut has_name = false; for (k, f) in registry.meta_fields { has_name = has_name || k == MetaMethod::Type; - mlua_assert!(f(self, 0)? == 1, "field function must return one value"); + let inner = mem::transmute::<&LuaInner, &LuaInner>(self); + mlua_assert!(f(inner, 0)? == 1, "field function must return one value"); rawset_field(state, -2, MetaMethod::validate(&k)?)?; } // Set `__name/__type` if not provided @@ -2705,7 +2972,8 @@ impl Lua { push_table(state, 0, fields_nrec, true)?; } for (k, f) in registry.fields { - mlua_assert!(f(self, 0)? == 1, "field function must return one value"); + let inner = mem::transmute::<&LuaInner, &LuaInner>(self); + mlua_assert!(f(inner, 0)? == 1, "field function must return one value"); rawset_field(state, -2, &k)?; } rawset_field(state, metatable_index, "__index")?; @@ -2786,7 +3054,7 @@ impl Lua { let extra_init = None; #[cfg(not(feature = "luau"))] let extra_init: Option<fn(*mut ffi::lua_State) -> Result<()>> = Some(|state| { - ffi::lua_pushcfunction(state, util::userdata_destructor::<UserDataCell<T>>); + ffi::lua_pushcfunction(state, util::userdata_destructor::<UserDataVariant<T>>); rawset_field(state, -2, "__gc") }); @@ -2835,6 +3103,12 @@ impl Lua { } } + #[inline(always)] + pub(crate) unsafe fn get_userdata_ref<T: 'static>(&self, idx: c_int) -> Result<UserDataRef<T>> { + let guard = self.lua().lock_arc(); + (*get_userdata::<UserDataVariant<T>>(self.state(), idx)).try_make_ref(guard) + } + // Returns `TypeId` for the userdata ref, checking that it's registered and not destructed. // // Returns `None` if the userdata is registered but non-static. @@ -2887,18 +3161,8 @@ impl Lua { Ok(type_id) } - // Creates a Function out of a Callback containing a 'static Fn. This is safe ONLY because the - // Fn is 'static, otherwise it could capture 'lua arguments improperly. Without ATCs, we - // cannot easily deal with the "correct" callback type of: - // - // Box<for<'lua> Fn(&'lua Lua, MultiValue<'lua>) -> Result<MultiValue<'lua>>)> - // - // So we instead use a caller provided lifetime, which without the 'static requirement would be - // unsafe. - pub(crate) fn create_callback<'lua>( - &'lua self, - func: Callback<'lua, 'static>, - ) -> Result<Function<'lua>> { + // Creates a Function out of a Callback containing a 'static Fn. + pub(crate) fn create_callback(&self, func: Callback) -> Result<Function> { unsafe extern "C-unwind" fn call_callback(state: *mut ffi::lua_State) -> c_int { // Normal functions can be scoped and therefore destroyed, // so we need to check that the first upvalue is valid @@ -2915,11 +3179,11 @@ impl Lua { return Err(Error::CallbackDestructed); } - let lua: &Lua = mem::transmute((*extra).inner.assume_init_ref()); - let _guard = StateGuard::new(&lua.0, state); + let lua = (*extra).lua().lock(); + let _guard = StateGuard::new(&lua, state); let func = &*(*upvalue).data; - func(lua, nargs) + func(mem::transmute::<&LuaInner, &LuaInner>(&lua), nargs) }) } @@ -2945,10 +3209,7 @@ impl Lua { } #[cfg(feature = "async")] - pub(crate) fn create_async_callback<'lua>( - &'lua self, - func: AsyncCallback<'lua, 'static>, - ) -> Result<Function<'lua>> { + pub(crate) fn create_async_callback(&self, func: AsyncCallback) -> Result<Function> { #[cfg(any( feature = "lua54", feature = "lua53", @@ -2969,14 +3230,17 @@ impl Lua { let extra = (*upvalue).extra.get(); callback_error_ext(state, extra, |nargs| { // Lua ensures that `LUA_MINSTACK` stack spaces are available (after pushing arguments) - let lua: &Lua = mem::transmute((*extra).inner.assume_init_ref()); - let _guard = StateGuard::new(&lua.0, state); + let lua = (*extra).lua(); + // The lock must be already held as the callback is executed + let rawlua = lua.guard_unchecked(); + let rawlua = mem::transmute::<&LuaInner, &LuaInner>(&rawlua); + let _guard = StateGuard::new(rawlua, state); - let args = MultiValue::from_stack_multi(nargs, lua)?; + let args = MultiValue::from_stack_multi(nargs, rawlua)?; let func = &*(*upvalue).data; - let fut = func(lua, args); + let fut = func(rawlua, args); let extra = Arc::clone(&(*upvalue).extra); - let protect = !lua.unlikely_memory_error(); + let protect = !rawlua.unlikely_memory_error(); push_gc_userdata(state, AsyncPollUpvalue { data: fut, extra }, protect)?; if protect { protect_lua!(state, 1, 1, fn(state) { @@ -2995,11 +3259,13 @@ impl Lua { let extra = (*upvalue).extra.get(); callback_error_ext(state, extra, |_| { // Lua ensures that `LUA_MINSTACK` stack spaces are available (after pushing arguments) - let lua: &Lua = mem::transmute((*extra).inner.assume_init_ref()); - let _guard = StateGuard::new(&lua.0, state); + let lua = (*extra).lua(); + // The lock must be already held as the future is polled + let rawlua = lua.guard_unchecked(); + let _guard = StateGuard::new(&rawlua, state); let fut = &mut (*upvalue).data; - let mut ctx = Context::from_waker(lua.waker()); + let mut ctx = Context::from_waker(rawlua.waker()); match fut.as_mut().poll(&mut ctx) { Poll::Pending => { ffi::lua_pushnil(state); @@ -3017,9 +3283,9 @@ impl Lua { Ok(nresults + 1) } nresults => { - let results = MultiValue::from_stack_multi(nresults, lua)?; + let results = MultiValue::from_stack_multi(nresults, &rawlua)?; ffi::lua_pushinteger(state, nresults as _); - lua.push(lua.create_sequence_from(results)?)?; + rawlua.push(lua.create_sequence_from(results)?)?; Ok(2) } } @@ -3058,17 +3324,18 @@ impl Lua { len as c_int } - let coroutine = self.globals().get::<_, Table>("coroutine")?; + let lua = self.lua(); + let coroutine = lua.globals().get::<_, Table>("coroutine")?; - let env = self.create_table_with_capacity(0, 3)?; + let env = lua.create_table_with_capacity(0, 3)?; env.set("get_poll", get_poll)?; // Cache `yield` function env.set("yield", coroutine.get::<_, Function>("yield")?)?; unsafe { - env.set("unpack", self.create_c_function(unpack)?)?; + env.set("unpack", lua.create_c_function(unpack)?)?; } - self.load( + lua.load( r#" local poll = get_poll(...) while true do @@ -3105,181 +3372,51 @@ impl Lua { pub(crate) unsafe fn set_waker(&self, waker: NonNull<Waker>) -> NonNull<Waker> { mem::replace(&mut (*self.extra.get()).waker, waker) } +} - /// Returns internal `Poll::Pending` constant used for executing async callbacks. - #[cfg(feature = "async")] - #[doc(hidden)] - #[inline] - pub fn poll_pending() -> LightUserData { - LightUserData(&ASYNC_POLL_PENDING as *const u8 as *mut c_void) - } - - pub(crate) unsafe fn make_userdata<T>(&self, data: UserDataCell<T>) -> Result<AnyUserData> - where - T: UserData + 'static, - { - self.make_userdata_with_metatable(data, || { - // Check if userdata/metatable is already registered - let type_id = TypeId::of::<T>(); - if let Some(&table_id) = (*self.extra.get()).registered_userdata.get(&type_id) { - return Ok(table_id as Integer); - } - - // Create new metatable from UserData definition - let mut registry = UserDataRegistry::new(); - T::add_fields(&mut registry); - T::add_methods(&mut registry); - - self.register_userdata_metatable(registry) - }) - } - - pub(crate) unsafe fn make_any_userdata<T>(&self, data: UserDataCell<T>) -> Result<AnyUserData> - where - T: 'static, - { - self.make_userdata_with_metatable(data, || { - // Check if userdata/metatable is already registered - let type_id = TypeId::of::<T>(); - if let Some(&table_id) = (*self.extra.get()).registered_userdata.get(&type_id) { - return Ok(table_id as Integer); - } - - // Create empty metatable - let registry = UserDataRegistry::new(); - self.register_userdata_metatable::<T>(registry) - }) +impl WeakLua { + #[inline(always)] + pub(crate) fn lock(&self) -> LuaGuard { + LuaGuard::new(self.0.upgrade().unwrap()) } +} - unsafe fn make_userdata_with_metatable<T>( - &self, - data: UserDataCell<T>, - get_metatable_id: impl FnOnce() -> Result<Integer>, - ) -> Result<AnyUserData> { - let state = self.state(); - let _sg = StackGuard::new(state); - check_stack(state, 3)?; - - // We push metatable first to ensure having correct metatable with `__gc` method - ffi::lua_pushnil(state); - ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, get_metatable_id()?); - let protect = !self.unlikely_memory_error(); - #[cfg(not(feature = "lua54"))] - push_userdata(state, data, protect)?; - #[cfg(feature = "lua54")] - push_userdata_uv(state, data, USER_VALUE_MAXSLOT as c_int, protect)?; - ffi::lua_replace(state, -3); - ffi::lua_setmetatable(state, -2); - - // Set empty environment for Lua 5.1 - #[cfg(any(feature = "lua51", feature = "luajit"))] - if protect { - protect_lua!(state, 1, 1, fn(state) { - ffi::lua_newtable(state); - ffi::lua_setuservalue(state, -2); - })?; - } else { - ffi::lua_newtable(state); - ffi::lua_setuservalue(state, -2); - } - - Ok(AnyUserData(self.pop_ref(), SubtypeId::None)) +impl PartialEq for WeakLua { + fn eq(&self, other: &Self) -> bool { + Weak::ptr_eq(&self.0, &other.0) } +} - // Luau version located in `luau/mod.rs` - #[cfg(not(feature = "luau"))] - fn disable_c_modules(&self) -> Result<()> { - let package: Table = self.globals().get("package")?; - - package.set( - "loadlib", - self.create_function(|_, ()| -> Result<()> { - Err(Error::SafetyError( - "package.loadlib is disabled in safe mode".to_string(), - )) - })?, - )?; - - #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] - let searchers: Table = package.get("searchers")?; - #[cfg(any(feature = "lua51", feature = "luajit"))] - let searchers: Table = package.get("loaders")?; - - let loader = self.create_function(|_, ()| Ok("\n\tcan't load C modules in safe mode"))?; - - // The third and fourth searchers looks for a loader as a C library - searchers.raw_set(3, loader)?; - searchers.raw_remove(4)?; - - Ok(()) - } +impl Eq for WeakLua {} - pub(crate) unsafe fn try_from_ptr(state: *mut ffi::lua_State) -> Option<Self> { - let extra = extra_data(state); - if extra.is_null() { - return None; - } - Some(Lua(Arc::clone((*extra).inner.assume_init_ref()))) +impl LuaGuard { + pub(crate) fn new(handle: Arc<ReentrantMutex<LuaInner>>) -> Self { + Self(handle.lock_arc()) } +} - #[inline] - pub(crate) unsafe fn unlikely_memory_error(&self) -> bool { - // MemoryInfo is empty in module mode so we cannot predict memory limits - match MemoryState::get(self.main_state) { - mem_state if !mem_state.is_null() => (*mem_state).memory_limit() == 0, - #[cfg(feature = "module")] - _ => (*self.extra.get()).skip_memory_check, // Check the special flag (only for module mode) - #[cfg(not(feature = "module"))] - _ => false, - } - } +impl Deref for LuaGuard { + type Target = LuaInner; - #[cfg(feature = "unstable")] - #[inline] - pub(crate) fn clone(&self) -> Arc<LuaInner> { - Arc::clone(&self.0) + fn deref(&self) -> &Self::Target { + &*self.0 } } -impl LuaInner { - #[inline(always)] - pub(crate) fn state(&self) -> *mut ffi::lua_State { - self.state.get() - } +impl ExtraData { + // Index of `error_traceback` function in auxiliary thread stack + #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))] + const ERROR_TRACEBACK_IDX: c_int = 1; - #[cfg(feature = "luau")] #[inline(always)] - pub(crate) fn main_state(&self) -> *mut ffi::lua_State { - self.main_state + const fn lua(&self) -> &Lua { + unsafe { mem::transmute(self.inner.assume_init_ref()) } } #[inline(always)] - pub(crate) fn ref_thread(&self) -> *mut ffi::lua_State { - unsafe { (*self.extra.get()).ref_thread } - } - - #[inline] - pub(crate) fn pop_multivalue_from_pool(&self) -> Option<VecDeque<Value>> { - let extra = unsafe { &mut *self.extra.get() }; - extra.multivalue_pool.pop() + const fn weak(&self) -> &WeakLua { + unsafe { mem::transmute(self.weak.assume_init_ref()) } } - - #[inline] - pub(crate) fn push_multivalue_to_pool(&self, mut multivalue: VecDeque<Value>) { - let extra = unsafe { &mut *self.extra.get() }; - if extra.multivalue_pool.len() < MULTIVALUE_POOL_SIZE { - multivalue.clear(); - extra - .multivalue_pool - .push(unsafe { mem::transmute(multivalue) }); - } - } -} - -impl ExtraData { - // Index of `error_traceback` function in auxiliary thread stack - #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))] - const ERROR_TRACEBACK_IDX: c_int = 1; } struct StateGuard<'a>(&'a LuaInner, *mut ffi::lua_State); diff --git a/src/multi.rs b/src/multi.rs index 00f9e62..e56aeb9 100644 --- a/src/multi.rs +++ b/src/multi.rs @@ -5,7 +5,7 @@ use std::os::raw::c_int; use std::result::Result as StdResult; use crate::error::Result; -use crate::lua::Lua; +use crate::lua::{Lua, LuaInner}; use crate::util::check_stack; use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, MultiValue, Nil}; @@ -13,7 +13,7 @@ use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, MultiValue, Nil /// on success, or in the case of an error, returning `nil` and an error message. impl<T: IntoLua, E: IntoLua> IntoLuaMulti for StdResult<T, E> { #[inline] - fn into_lua_multi(self, lua: &Lua) -> Result<MultiValue<'_>> { + fn into_lua_multi(self, lua: &Lua) -> Result<MultiValue> { match self { Ok(val) => (val,).into_lua_multi(lua), Err(err) => (Nil, err).into_lua_multi(lua), @@ -21,7 +21,7 @@ impl<T: IntoLua, E: IntoLua> IntoLuaMulti for StdResult<T, E> { } #[inline] - unsafe fn push_into_stack_multi(self, lua: &Lua) -> Result<c_int> { + unsafe fn push_into_stack_multi(self, lua: &LuaInner) -> Result<c_int> { match self { Ok(val) => (val,).push_into_stack_multi(lua), Err(err) => (Nil, err).push_into_stack_multi(lua), @@ -31,7 +31,7 @@ impl<T: IntoLua, E: IntoLua> IntoLuaMulti for StdResult<T, E> { impl<E: IntoLua> IntoLuaMulti for StdResult<(), E> { #[inline] - fn into_lua_multi(self, lua: &Lua) -> Result<MultiValue<'_>> { + fn into_lua_multi(self, lua: &Lua) -> Result<MultiValue> { match self { Ok(_) => Ok(MultiValue::new()), Err(err) => (Nil, err).into_lua_multi(lua), @@ -39,7 +39,7 @@ impl<E: IntoLua> IntoLuaMulti for StdResult<(), E> { } #[inline] - unsafe fn push_into_stack_multi(self, lua: &Lua) -> Result<c_int> { + unsafe fn push_into_stack_multi(self, lua: &LuaInner) -> Result<c_int> { match self { Ok(_) => Ok(0), Err(err) => (Nil, err).push_into_stack_multi(lua), @@ -49,39 +49,34 @@ impl<E: IntoLua> IntoLuaMulti for StdResult<(), E> { impl<T: IntoLua> IntoLuaMulti for T { #[inline] - fn into_lua_multi(self, lua: &Lua) -> Result<MultiValue<'_>> { + fn into_lua_multi(self, lua: &Lua) -> Result<MultiValue> { let mut v = MultiValue::with_lua_and_capacity(lua, 1); v.push_back(self.into_lua(lua)?); Ok(v) } #[inline] - unsafe fn push_into_stack_multi(self, lua: &Lua) -> Result<c_int> { + unsafe fn push_into_stack_multi(self, lua: &LuaInner) -> Result<c_int> { self.push_into_stack(lua)?; Ok(1) } } -impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for T { +impl<T: FromLua> FromLuaMulti for T { #[inline] - fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> { + fn from_lua_multi(mut values: MultiValue, lua: &Lua) -> Result<Self> { T::from_lua(values.pop_front().unwrap_or(Nil), lua) } #[inline] - fn from_lua_args( - mut args: MultiValue<'lua>, - i: usize, - to: Option<&str>, - lua: &'lua Lua, - ) -> Result<Self> { + fn from_lua_args(mut args: MultiValue, i: usize, to: Option<&str>, lua: &Lua) -> Result<Self> { T::from_lua_arg(args.pop_front().unwrap_or(Nil), i, to, lua) } #[inline] - unsafe fn from_stack_multi(nvals: c_int, lua: &'lua Lua) -> Result<Self> { + unsafe fn from_stack_multi(nvals: c_int, lua: &LuaInner) -> Result<Self> { if nvals == 0 { - return T::from_lua(Nil, lua); + return T::from_lua(Nil, lua.lua()); } T::from_stack(-nvals, lua) } @@ -91,25 +86,25 @@ impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for T { nargs: c_int, i: usize, to: Option<&str>, - lua: &'lua Lua, + lua: &LuaInner, ) -> Result<Self> { if nargs == 0 { - return T::from_lua_arg(Nil, i, to, lua); + return T::from_lua_arg(Nil, i, to, lua.lua()); } T::from_stack_arg(-nargs, i, to, lua) } } -impl IntoLuaMulti for MultiValue<'_> { +impl IntoLuaMulti for MultiValue { #[inline] - fn into_lua_multi(self, _: &Lua) -> Result<MultiValue<'_>> { + fn into_lua_multi(self, _: &Lua) -> Result<MultiValue> { unsafe { Ok(transmute(self)) } } } -impl<'lua> FromLuaMulti<'lua> for MultiValue<'lua> { +impl FromLuaMulti for MultiValue { #[inline] - fn from_lua_multi(values: MultiValue<'lua>, _: &'lua Lua) -> Result<Self> { + fn from_lua_multi(values: MultiValue, _: &Lua) -> Result<Self> { Ok(values) } } @@ -187,16 +182,16 @@ impl<T> DerefMut for Variadic<T> { impl<T: IntoLua> IntoLuaMulti for Variadic<T> { #[inline] - fn into_lua_multi(self, lua: &Lua) -> Result<MultiValue<'_>> { + fn into_lua_multi(self, lua: &Lua) -> Result<MultiValue> { let mut values = MultiValue::with_lua_and_capacity(lua, self.0.len()); values.extend_from_values(self.0.into_iter().map(|val| val.into_lua(lua)))?; Ok(values) } } -impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for Variadic<T> { +impl<T: FromLua> FromLuaMulti for Variadic<T> { #[inline] - fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> { + fn from_lua_multi(mut values: MultiValue, lua: &Lua) -> Result<Self> { values .drain(..) .map(|val| T::from_lua(val, lua)) @@ -209,24 +204,24 @@ macro_rules! impl_tuple { () => ( impl IntoLuaMulti for () { #[inline] - fn into_lua_multi(self, lua: &Lua) -> Result<MultiValue<'_>> { + fn into_lua_multi(self, lua: &Lua) -> Result<MultiValue> { Ok(MultiValue::with_lua_and_capacity(lua, 0)) } #[inline] - unsafe fn push_into_stack_multi(self, _lua: &Lua) -> Result<c_int> { + unsafe fn push_into_stack_multi(self, _lua: &LuaInner) -> Result<c_int> { Ok(0) } } - impl<'lua> FromLuaMulti<'lua> for () { + impl FromLuaMulti for () { #[inline] - fn from_lua_multi(_values: MultiValue<'lua>, _lua: &'lua Lua) -> Result<Self> { + fn from_lua_multi(_values: MultiValue, _lua: &Lua) -> Result<Self> { Ok(()) } #[inline] - unsafe fn from_stack_multi(nvals: c_int, lua: &'lua Lua) -> Result<Self> { + unsafe fn from_stack_multi(nvals: c_int, lua: &LuaInner) -> Result<Self> { if nvals > 0 { ffi::lua_pop(lua.state(), nvals); } @@ -242,7 +237,7 @@ macro_rules! impl_tuple { { #[allow(unused_mut, non_snake_case)] #[inline] - fn into_lua_multi(self, lua: &Lua) -> Result<MultiValue<'_>> { + fn into_lua_multi(self, lua: &Lua) -> Result<MultiValue> { let ($($name,)* $last,) = self; let mut results = $last.into_lua_multi(lua)?; @@ -252,7 +247,7 @@ macro_rules! impl_tuple { #[allow(non_snake_case)] #[inline] - unsafe fn push_into_stack_multi(self, lua: &Lua) -> Result<c_int> { + unsafe fn push_into_stack_multi(self, lua: &LuaInner) -> Result<c_int> { let ($($name,)* $last,) = self; let mut nresults = 0; $( @@ -268,13 +263,13 @@ macro_rules! impl_tuple { } } - impl<'lua, $($name,)* $last> FromLuaMulti<'lua> for ($($name,)* $last,) - where $($name: FromLua<'lua>,)* - $last: FromLuaMulti<'lua> + impl<$($name,)* $last> FromLuaMulti for ($($name,)* $last,) + where $($name: FromLua,)* + $last: FromLuaMulti { #[allow(unused_mut, non_snake_case)] #[inline] - fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> { + fn from_lua_multi(mut values: MultiValue, lua: &Lua) -> Result<Self> { $(let $name = FromLua::from_lua(values.pop_front().unwrap_or(Nil), lua)?;)* let $last = FromLuaMulti::from_lua_multi(values, lua)?; Ok(($($name,)* $last,)) @@ -282,7 +277,7 @@ macro_rules! impl_tuple { #[allow(unused_mut, non_snake_case)] #[inline] - fn from_lua_args(mut args: MultiValue<'lua>, mut i: usize, to: Option<&str>, lua: &'lua Lua) -> Result<Self> { + fn from_lua_args(mut args: MultiValue, mut i: usize, to: Option<&str>, lua: &Lua) -> Result<Self> { $( let $name = FromLua::from_lua_arg(args.pop_front().unwrap_or(Nil), i, to, lua)?; i += 1; @@ -293,13 +288,13 @@ macro_rules! impl_tuple { #[allow(unused_mut, non_snake_case)] #[inline] - unsafe fn from_stack_multi(mut nvals: c_int, lua: &'lua Lua) -> Result<Self> { + unsafe fn from_stack_multi(mut nvals: c_int, lua: &LuaInner) -> Result<Self> { $( let $name = if nvals > 0 { nvals -= 1; FromLua::from_stack(-(nvals + 1), lua) } else { - FromLua::from_lua(Nil, lua) + FromLua::from_lua(Nil, lua.lua()) }?; )* let $last = FromLuaMulti::from_stack_multi(nvals, lua)?; @@ -308,13 +303,13 @@ macro_rules! impl_tuple { #[allow(unused_mut, non_snake_case)] #[inline] - unsafe fn from_stack_args(mut nargs: c_int, mut i: usize, to: Option<&str>, lua: &'lua Lua) -> Result<Self> { + unsafe fn from_stack_args(mut nargs: c_int, mut i: usize, to: Option<&str>, lua: &LuaInner) -> Result<Self> { $( let $name = if nargs > 0 { nargs -= 1; FromLua::from_stack_arg(-(nargs + 1), i, to, lua) } else { - FromLua::from_lua_arg(Nil, i, to, lua) + FromLua::from_lua_arg(Nil, i, to, lua.lua()) }?; i += 1; )* diff --git a/src/prelude.rs b/src/prelude.rs index e4459c2..c2929f7 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -35,10 +35,3 @@ pub use crate::{ DeserializeOptions as LuaDeserializeOptions, LuaSerdeExt, SerializeOptions as LuaSerializeOptions, }; - -#[cfg(feature = "unstable")] -#[doc(no_inline)] -pub use crate::{ - OwnedAnyUserData as LuaOwnedAnyUserData, OwnedFunction as LuaOwnedFunction, - OwnedString as LuaOwnedString, OwnedTable as LuaOwnedTable, OwnedThread as LuaOwnedThread, -}; diff --git a/src/serde/de.rs b/src/serde/de.rs index 3cc182d..542180f 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -14,8 +14,8 @@ use crate::value::Value; /// A struct for deserializing Lua values into Rust values. #[derive(Debug)] -pub struct Deserializer<'lua> { - value: Value<'lua>, +pub struct Deserializer { + value: Value, options: Options, visited: Rc<RefCell<FxHashSet<*const c_void>>>, } @@ -93,14 +93,14 @@ impl Options { } } -impl<'lua> Deserializer<'lua> { +impl Deserializer { /// Creates a new Lua Deserializer for the `Value`. - pub fn new(value: Value<'lua>) -> Self { + pub fn new(value: Value) -> Self { Self::new_with_options(value, Options::default()) } /// Creates a new Lua Deserializer for the `Value` with custom options. - pub fn new_with_options(value: Value<'lua>, options: Options) -> Self { + pub fn new_with_options(value: Value, options: Options) -> Self { Deserializer { value, options, @@ -109,7 +109,7 @@ impl<'lua> Deserializer<'lua> { } fn from_parts( - value: Value<'lua>, + value: Value, options: Options, visited: Rc<RefCell<FxHashSet<*const c_void>>>, ) -> Self { @@ -121,7 +121,7 @@ impl<'lua> Deserializer<'lua> { } } -impl<'lua, 'de> serde::Deserializer<'de> for Deserializer<'lua> { +impl<'de> serde::Deserializer<'de> for Deserializer { type Error = Error; #[inline] @@ -150,8 +150,9 @@ impl<'lua, 'de> serde::Deserializer<'de> for Deserializer<'lua> { } #[cfg(feature = "luau")] Value::UserData(ud) if ud.1 == crate::types::SubtypeId::Buffer => unsafe { + let lua = ud.0.lua.lock(); let mut size = 0usize; - let buf = ffi::lua_tobuffer(ud.0.lua.ref_thread(), ud.0.index, &mut size); + let buf = ffi::lua_tobuffer(lua.ref_thread(), ud.0.index, &mut size); mlua_assert!(!buf.is_null(), "invalid Luau buffer"); let buf = std::slice::from_raw_parts(buf as *const u8, size); visitor.visit_bytes(buf) @@ -394,13 +395,13 @@ impl<'lua, 'de> serde::Deserializer<'de> for Deserializer<'lua> { } } -struct SeqDeserializer<'lua> { - seq: TableSequence<'lua, Value<'lua>>, +struct SeqDeserializer { + seq: TableSequence<Value>, options: Options, visited: Rc<RefCell<FxHashSet<*const c_void>>>, } -impl<'lua, 'de> de::SeqAccess<'de> for SeqDeserializer<'lua> { +impl<'de> de::SeqAccess<'de> for SeqDeserializer { type Error = Error; fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>> @@ -466,13 +467,13 @@ impl<'de> de::SeqAccess<'de> for VecDeserializer { } } -pub(crate) enum MapPairs<'lua> { - Iter(TablePairs<'lua, Value<'lua>, Value<'lua>>), - Vec(Vec<(Value<'lua>, Value<'lua>)>), +pub(crate) enum MapPairs { + Iter(TablePairs<Value, Value>), + Vec(Vec<(Value, Value)>), } -impl<'lua> MapPairs<'lua> { - pub(crate) fn new(t: Table<'lua>, sort_keys: bool) -> Result<Self> { +impl MapPairs { + pub(crate) fn new(t: Table, sort_keys: bool) -> Result<Self> { if sort_keys { let mut pairs = t.pairs::<Value, Value>().collect::<Result<Vec<_>>>()?; pairs.sort_by(|(a, _), (b, _)| b.cmp(a)); // reverse order as we pop values from the end @@ -497,8 +498,8 @@ impl<'lua> MapPairs<'lua> { } } -impl<'lua> Iterator for MapPairs<'lua> { - type Item = Result<(Value<'lua>, Value<'lua>)>; +impl Iterator for MapPairs { + type Item = Result<(Value, Value)>; fn next(&mut self) -> Option<Self::Item> { match self { @@ -508,15 +509,15 @@ impl<'lua> Iterator for MapPairs<'lua> { } } -struct MapDeserializer<'lua> { - pairs: MapPairs<'lua>, - value: Option<Value<'lua>>, +struct MapDeserializer { + pairs: MapPairs, + value: Option<Value>, options: Options, visited: Rc<RefCell<FxHashSet<*const c_void>>>, processed: usize, } -impl<'lua, 'de> de::MapAccess<'de> for MapDeserializer<'lua> { +impl<'de> de::MapAccess<'de> for MapDeserializer { type Error = Error; fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>> @@ -566,16 +567,16 @@ impl<'lua, 'de> de::MapAccess<'de> for MapDeserializer<'lua> { } } -struct EnumDeserializer<'lua> { +struct EnumDeserializer { variant: StdString, - value: Option<Value<'lua>>, + value: Option<Value>, options: Options, visited: Rc<RefCell<FxHashSet<*const c_void>>>, } -impl<'lua, 'de> de::EnumAccess<'de> for EnumDeserializer<'lua> { +impl<'de> de::EnumAccess<'de> for EnumDeserializer { type Error = Error; - type Variant = VariantDeserializer<'lua>; + type Variant = VariantDeserializer; fn variant_seed<T>(self, seed: T) -> Result<(T::Value, Self::Variant)> where @@ -591,13 +592,13 @@ impl<'lua, 'de> de::EnumAccess<'de> for EnumDeserializer<'lua> { } } -struct VariantDeserializer<'lua> { - value: Option<Value<'lua>>, +struct VariantDeserializer { + value: Option<Value>, options: Options, visited: Rc<RefCell<FxHashSet<*const c_void>>>, } -impl<'lua, 'de> de::VariantAccess<'de> for VariantDeserializer<'lua> { +impl<'de> de::VariantAccess<'de> for VariantDeserializer { type Error = Error; fn unit_variant(self) -> Result<()> { diff --git a/src/serde/mod.rs b/src/serde/mod.rs index 877b889..9495281 100644 --- a/src/serde/mod.rs +++ b/src/serde/mod.rs @@ -99,7 +99,7 @@ pub trait LuaSerdeExt: Sealed { /// "#).exec() /// } /// ``` - fn to_value<'lua, T: Serialize + ?Sized>(&'lua self, t: &T) -> Result<Value<'lua>>; + fn to_value<T: Serialize + ?Sized>(&self, t: &T) -> Result<Value>; /// Converts `T` into a [`Value`] instance with options. /// @@ -124,7 +124,7 @@ pub trait LuaSerdeExt: Sealed { /// "#).exec() /// } /// ``` - fn to_value_with<'lua, T>(&'lua self, t: &T, options: ser::Options) -> Result<Value<'lua>> + fn to_value_with<T>(&self, t: &T, options: ser::Options) -> Result<Value> where T: Serialize + ?Sized; @@ -199,20 +199,21 @@ impl LuaSerdeExt for Lua { } fn array_metatable(&self) -> Table { + let lua = self.lock(); unsafe { - push_array_metatable(self.ref_thread()); - Table(self.pop_ref_thread()) + push_array_metatable(lua.ref_thread()); + Table(lua.pop_ref_thread()) } } - fn to_value<'lua, T>(&'lua self, t: &T) -> Result<Value<'lua>> + fn to_value<T>(&self, t: &T) -> Result<Value> where T: Serialize + ?Sized, { t.serialize(ser::Serializer::new(self)) } - fn to_value_with<'lua, T>(&'lua self, t: &T, options: ser::Options) -> Result<Value<'lua>> + fn to_value_with<T>(&self, t: &T, options: ser::Options) -> Result<Value> where T: Serialize + ?Sized, { diff --git a/src/serde/ser.rs b/src/serde/ser.rs index 6ee57a1..df3a16c 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -8,8 +8,8 @@ use crate::value::{IntoLua, Value}; /// A struct for serializing Rust values into Lua values. #[derive(Debug)] -pub struct Serializer<'lua> { - lua: &'lua Lua, +pub struct Serializer<'a> { + lua: &'a Lua, options: Options, } @@ -109,14 +109,14 @@ impl Options { } } -impl<'lua> Serializer<'lua> { +impl<'a> Serializer<'a> { /// Creates a new Lua Serializer with default options. - pub fn new(lua: &'lua Lua) -> Self { + pub fn new(lua: &'a Lua) -> Self { Self::new_with_options(lua, Options::default()) } /// Creates a new Lua Serializer with custom options. - pub fn new_with_options(lua: &'lua Lua, options: Options) -> Self { + pub fn new_with_options(lua: &'a Lua, options: Options) -> Self { Serializer { lua, options } } } @@ -124,28 +124,28 @@ impl<'lua> Serializer<'lua> { macro_rules! lua_serialize_number { ($name:ident, $t:ty) => { #[inline] - fn $name(self, value: $t) -> Result<Value<'lua>> { + fn $name(self, value: $t) -> Result<Value> { value.into_lua(self.lua) } }; } -impl<'lua> ser::Serializer for Serializer<'lua> { - type Ok = Value<'lua>; +impl<'a> ser::Serializer for Serializer<'a> { + type Ok = Value; type Error = Error; // Associated types for keeping track of additional state while serializing // compound data structures like sequences and maps. - type SerializeSeq = SerializeSeq<'lua>; - type SerializeTuple = SerializeSeq<'lua>; - type SerializeTupleStruct = SerializeSeq<'lua>; - type SerializeTupleVariant = SerializeTupleVariant<'lua>; - type SerializeMap = SerializeMap<'lua>; - type SerializeStruct = SerializeStruct<'lua>; - type SerializeStructVariant = SerializeStructVariant<'lua>; + type SerializeSeq = SerializeSeq<'a>; + type SerializeTuple = SerializeSeq<'a>; + type SerializeTupleStruct = SerializeSeq<'a>; + type SerializeTupleVariant = SerializeTupleVariant<'a>; + type SerializeMap = SerializeMap<'a>; + type SerializeStruct = SerializeStruct<'a>; + type SerializeStructVariant = SerializeStructVariant<'a>; #[inline] - fn serialize_bool(self, value: bool) -> Result<Value<'lua>> { + fn serialize_bool(self, value: bool) -> Result<Value> { Ok(Value::Boolean(value)) } @@ -164,22 +164,22 @@ impl<'lua> ser::Serializer for Serializer<'lua> { lua_serialize_number!(serialize_f64, f64); #[inline] - fn serialize_char(self, value: char) -> Result<Value<'lua>> { + fn serialize_char(self, value: char) -> Result<Value> { self.serialize_str(&value.to_string()) } #[inline] - fn serialize_str(self, value: &str) -> Result<Value<'lua>> { + fn serialize_str(self, value: &str) -> Result<Value> { self.lua.create_string(value).map(Value::String) } #[inline] - fn serialize_bytes(self, value: &[u8]) -> Result<Value<'lua>> { + fn serialize_bytes(self, value: &[u8]) -> Result<Value> { self.lua.create_string(value).map(Value::String) } #[inline] - fn serialize_none(self) -> Result<Value<'lua>> { + fn serialize_none(self) -> Result<Value> { if self.options.serialize_none_to_null { Ok(self.lua.null()) } else { @@ -188,7 +188,7 @@ impl<'lua> ser::Serializer for Serializer<'lua> { } #[inline] - fn serialize_some<T>(self, value: &T) -> Result<Value<'lua>> + fn serialize_some<T>(self, value: &T) -> Result<Value> where T: Serialize + ?Sized, { @@ -196,7 +196,7 @@ impl<'lua> ser::Serializer for Serializer<'lua> { } #[inline] - fn serialize_unit(self) -> Result<Value<'lua>> { + fn serialize_unit(self) -> Result<Value> { if self.options.serialize_unit_to_null { Ok(self.lua.null()) } else { @@ -205,7 +205,7 @@ impl<'lua> ser::Serializer for Serializer<'lua> { } #[inline] - fn serialize_unit_struct(self, _name: &'static str) -> Result<Value<'lua>> { + fn serialize_unit_struct(self, _name: &'static str) -> Result<Value> { if self.options.serialize_unit_to_null { Ok(self.lua.null()) } else { @@ -219,12 +219,12 @@ impl<'lua> ser::Serializer for Serializer<'lua> { _name: &'static str, _variant_index: u32, variant: &'static str, - ) -> Result<Value<'lua>> { + ) -> Result<Value> { self.serialize_str(variant) } #[inline] - fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<Value<'lua>> + fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<Value> where T: Serialize + ?Sized, { @@ -238,7 +238,7 @@ impl<'lua> ser::Serializer for Serializer<'lua> { _variant_index: u32, variant: &'static str, value: &T, - ) -> Result<Value<'lua>> + ) -> Result<Value> where T: Serialize + ?Sized, { @@ -255,7 +255,7 @@ impl<'lua> ser::Serializer for Serializer<'lua> { if self.options.set_array_metatable { table.set_metatable(Some(self.lua.array_metatable())); } - Ok(SerializeSeq::new(table, self.options)) + Ok(SerializeSeq::new(self.lua, table, self.options)) } #[inline] @@ -286,6 +286,7 @@ impl<'lua> ser::Serializer for Serializer<'lua> { _len: usize, ) -> Result<Self::SerializeTupleVariant> { Ok(SerializeTupleVariant { + lua: self.lua, variant, table: self.lua.create_table()?, options: self.options, @@ -295,6 +296,7 @@ impl<'lua> ser::Serializer for Serializer<'lua> { #[inline] fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> { Ok(SerializeMap { + lua: self.lua, key: None, table: self.lua.create_table_with_capacity(0, len.unwrap_or(0))?, options: self.options, @@ -330,6 +332,7 @@ impl<'lua> ser::Serializer for Serializer<'lua> { len: usize, ) -> Result<Self::SerializeStructVariant> { Ok(SerializeStructVariant { + lua: self.lua, variant, table: self.lua.create_table_with_capacity(0, len)?, options: self.options, @@ -338,19 +341,19 @@ impl<'lua> ser::Serializer for Serializer<'lua> { } #[doc(hidden)] -pub struct SerializeSeq<'lua> { - lua: &'lua Lua, +pub struct SerializeSeq<'a> { + lua: &'a Lua, #[cfg(feature = "luau")] vector: Option<crate::types::Vector>, - table: Option<Table<'lua>>, + table: Option<Table>, next: usize, options: Options, } -impl<'lua> SerializeSeq<'lua> { - const fn new(table: Table<'lua>, options: Options) -> Self { +impl<'a> SerializeSeq<'a> { + fn new(lua: &'a Lua, table: Table, options: Options) -> Self { Self { - lua: table.0.lua, + lua, #[cfg(feature = "luau")] vector: None, table: Some(table), @@ -360,7 +363,7 @@ impl<'lua> SerializeSeq<'lua> { } #[cfg(feature = "luau")] - const fn new_vector(lua: &'lua Lua, options: Options) -> Self { + const fn new_vector(lua: &'a Lua, options: Options) -> Self { Self { lua, vector: Some(crate::types::Vector::zero()), @@ -371,8 +374,8 @@ impl<'lua> SerializeSeq<'lua> { } } -impl<'lua> ser::SerializeSeq for SerializeSeq<'lua> { - type Ok = Value<'lua>; +impl ser::SerializeSeq for SerializeSeq<'_> { + type Ok = Value; type Error = Error; fn serialize_element<T>(&mut self, value: &T) -> Result<()> @@ -386,13 +389,13 @@ impl<'lua> ser::SerializeSeq for SerializeSeq<'lua> { Ok(()) } - fn end(self) -> Result<Value<'lua>> { + fn end(self) -> Result<Value> { Ok(Value::Table(self.table.unwrap())) } } -impl<'lua> ser::SerializeTuple for SerializeSeq<'lua> { - type Ok = Value<'lua>; +impl ser::SerializeTuple for SerializeSeq<'_> { + type Ok = Value; type Error = Error; fn serialize_element<T>(&mut self, value: &T) -> Result<()> @@ -402,13 +405,13 @@ impl<'lua> ser::SerializeTuple for SerializeSeq<'lua> { ser::SerializeSeq::serialize_element(self, value) } - fn end(self) -> Result<Value<'lua>> { + fn end(self) -> Result<Value> { ser::SerializeSeq::end(self) } } -impl<'lua> ser::SerializeTupleStruct for SerializeSeq<'lua> { - type Ok = Value<'lua>; +impl ser::SerializeTupleStruct for SerializeSeq<'_> { + type Ok = Value; type Error = Error; fn serialize_field<T>(&mut self, value: &T) -> Result<()> @@ -426,7 +429,7 @@ impl<'lua> ser::SerializeTupleStruct for SerializeSeq<'lua> { ser::SerializeSeq::serialize_element(self, value) } - fn end(self) -> Result<Value<'lua>> { + fn end(self) -> Result<Value> { #[cfg(feature = "luau")] if let Some(vector) = self.vector { return Ok(Value::Vector(vector)); @@ -436,49 +439,49 @@ impl<'lua> ser::SerializeTupleStruct for SerializeSeq<'lua> { } #[doc(hidden)] -pub struct SerializeTupleVariant<'lua> { +pub struct SerializeTupleVariant<'a> { + lua: &'a Lua, variant: &'static str, - table: Table<'lua>, + table: Table, options: Options, } -impl<'lua> ser::SerializeTupleVariant for SerializeTupleVariant<'lua> { - type Ok = Value<'lua>; +impl ser::SerializeTupleVariant for SerializeTupleVariant<'_> { + type Ok = Value; type Error = Error; fn serialize_field<T>(&mut self, value: &T) -> Result<()> where T: Serialize + ?Sized, { - let lua = self.table.0.lua; - self.table.raw_push(lua.to_value_with(value, self.options)?) + self.table + .raw_push(self.lua.to_value_with(value, self.options)?) } - fn end(self) -> Result<Value<'lua>> { - let lua = self.table.0.lua; - let table = lua.create_table()?; + fn end(self) -> Result<Value> { + let table = self.lua.create_table()?; table.raw_set(self.variant, self.table)?; Ok(Value::Table(table)) } } #[doc(hidden)] -pub struct SerializeMap<'lua> { - table: Table<'lua>, - key: Option<Value<'lua>>, +pub struct SerializeMap<'a> { + lua: &'a Lua, + table: Table, + key: Option<Value>, options: Options, } -impl<'lua> ser::SerializeMap for SerializeMap<'lua> { - type Ok = Value<'lua>; +impl ser::SerializeMap for SerializeMap<'_> { + type Ok = Value; type Error = Error; fn serialize_key<T>(&mut self, key: &T) -> Result<()> where T: Serialize + ?Sized, { - let lua = self.table.0.lua; - self.key = Some(lua.to_value_with(key, self.options)?); + self.key = Some(self.lua.to_value_with(key, self.options)?); Ok(()) } @@ -486,29 +489,28 @@ impl<'lua> ser::SerializeMap for SerializeMap<'lua> { where T: Serialize + ?Sized, { - let lua = self.table.0.lua; let key = mlua_expect!( self.key.take(), "serialize_value called before serialize_key" ); - let value = lua.to_value_with(value, self.options)?; + let value = self.lua.to_value_with(value, self.options)?; self.table.raw_set(key, value) } - fn end(self) -> Result<Value<'lua>> { + fn end(self) -> Result<Value> { Ok(Value::Table(self.table)) } } #[doc(hidden)] -pub struct SerializeStruct<'lua> { - lua: &'lua Lua, - inner: Option<Value<'lua>>, +pub struct SerializeStruct<'a> { + lua: &'a Lua, + inner: Option<Value>, options: Options, } -impl<'lua> ser::SerializeStruct for SerializeStruct<'lua> { - type Ok = Value<'lua>; +impl ser::SerializeStruct for SerializeStruct<'_> { + type Ok = Value; type Error = Error; fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()> @@ -529,7 +531,7 @@ impl<'lua> ser::SerializeStruct for SerializeStruct<'lua> { Ok(()) } - fn end(self) -> Result<Value<'lua>> { + fn end(self) -> Result<Value> { match self.inner { Some(table @ Value::Table(_)) => Ok(table), Some(value) if self.options.detect_serde_json_arbitrary_precision => { @@ -551,29 +553,28 @@ impl<'lua> ser::SerializeStruct for SerializeStruct<'lua> { } #[doc(hidden)] -pub struct SerializeStructVariant<'lua> { +pub struct SerializeStructVariant<'a> { + lua: &'a Lua, variant: &'static str, - table: Table<'lua>, + table: Table, options: Options, } -impl<'lua> ser::SerializeStructVariant for SerializeStructVariant<'lua> { - type Ok = Value<'lua>; +impl ser::SerializeStructVariant for SerializeStructVariant<'_> { + type Ok = Value; type Error = Error; fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()> where T: Serialize + ?Sized, { - let lua = self.table.0.lua; self.table - .raw_set(key, lua.to_value_with(value, self.options)?)?; + .raw_set(key, self.lua.to_value_with(value, self.options)?)?; Ok(()) } - fn end(self) -> Result<Value<'lua>> { - let lua = self.table.0.lua; - let table = lua.create_table_with_capacity(0, 1)?; + fn end(self) -> Result<Value> { + let table = self.lua.create_table_with_capacity(0, 1)?; table.raw_set(self.variant, self.table)?; Ok(Value::Table(table)) } diff --git a/src/string.rs b/src/string.rs index add8bdc..cde30ee 100644 --- a/src/string.rs +++ b/src/string.rs @@ -17,30 +17,9 @@ use crate::types::ValueRef; /// /// Unlike Rust strings, Lua strings may not be valid UTF-8. #[derive(Clone)] -pub struct String<'lua>(pub(crate) ValueRef<'lua>); +pub struct String(pub(crate) ValueRef); -/// Owned handle to an internal Lua string. -/// -/// The owned handle holds a *strong* reference to the current Lua instance. -/// Be warned, if you place it into a Lua type (eg. [`UserData`] or a Rust callback), it is *very easy* -/// to accidentally cause reference cycles that would prevent destroying Lua instance. -/// -/// [`UserData`]: crate::UserData -#[cfg(feature = "unstable")] -#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] -#[derive(Clone)] -pub struct OwnedString(pub(crate) crate::types::OwnedValueRef); - -#[cfg(feature = "unstable")] -impl OwnedString { - /// Get borrowed handle to the underlying Lua string. - #[cfg_attr(feature = "send", allow(unused))] - pub const fn to_ref(&self) -> String { - String(self.0.to_ref()) - } -} - -impl<'lua> String<'lua> { +impl String { /// Get a `&str` slice if the Lua string is valid UTF-8. /// /// # Examples @@ -116,7 +95,8 @@ impl<'lua> String<'lua> { /// Get the bytes that make up this string, including the trailing nul byte. pub fn as_bytes_with_nul(&self) -> &[u8] { - let ref_thread = self.0.lua.ref_thread(); + let lua = self.0.lua.lock(); + let ref_thread = lua.ref_thread(); unsafe { mlua_debug_assert!( ffi::lua_type(ref_thread, self.0.index) == ffi::LUA_TSTRING, @@ -141,17 +121,9 @@ impl<'lua> String<'lua> { pub fn to_pointer(&self) -> *const c_void { self.0.to_pointer() } - - /// Convert this handle to owned version. - #[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] - #[inline] - pub fn into_owned(self) -> OwnedString { - OwnedString(self.0.into_owned()) - } } -impl<'lua> fmt::Debug for String<'lua> { +impl fmt::Debug for String { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let bytes = self.as_bytes(); // Check if the string is valid utf8 @@ -180,13 +152,13 @@ impl<'lua> fmt::Debug for String<'lua> { } } -impl<'lua> AsRef<[u8]> for String<'lua> { +impl AsRef<[u8]> for String { fn as_ref(&self) -> &[u8] { self.as_bytes() } } -impl<'lua> Borrow<[u8]> for String<'lua> { +impl Borrow<[u8]> for String { fn borrow(&self) -> &[u8] { self.as_bytes() } @@ -200,7 +172,7 @@ impl<'lua> Borrow<[u8]> for String<'lua> { // The only downside is that this disallows a comparison with `Cow<str>`, as that only implements // `AsRef<str>`, which collides with this impl. Requiring `AsRef<str>` would fix that, but limit us // in other ways. -impl<'lua, T> PartialEq<T> for String<'lua> +impl<T> PartialEq<T> for String where T: AsRef<[u8]> + ?Sized, { @@ -209,16 +181,16 @@ where } } -impl<'lua> Eq for String<'lua> {} +impl Eq for String {} -impl<'lua> Hash for String<'lua> { +impl Hash for String { fn hash<H: Hasher>(&self, state: &mut H) { self.as_bytes().hash(state); } } #[cfg(feature = "serialize")] -impl<'lua> Serialize for String<'lua> { +impl Serialize for String { fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error> where S: Serializer, @@ -230,40 +202,9 @@ impl<'lua> Serialize for String<'lua> { } } -// Additional shortcuts -#[cfg(feature = "unstable")] -impl OwnedString { - /// Get a `&str` slice if the Lua string is valid UTF-8. - /// - /// This is a shortcut for [`String::to_str()`]. - #[inline] - pub fn to_str(&self) -> Result<&str> { - let s = self.to_ref(); - // Reattach lifetime to &self - unsafe { std::mem::transmute(s.to_str()) } - } - - /// Get the bytes that make up this string. - /// - /// This is a shortcut for [`String::as_bytes()`]. - #[inline] - pub fn as_bytes(&self) -> &[u8] { - let s = self.to_ref(); - // Reattach lifetime to &self - unsafe { std::mem::transmute(s.as_bytes()) } - } -} - -#[cfg(feature = "unstable")] -impl fmt::Debug for OwnedString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.to_ref().fmt(f) - } -} - -#[cfg(test)] -mod assertions { - use super::*; +// #[cfg(test)] +// mod assertions { +// use super::*; - static_assertions::assert_not_impl_any!(String: Send); -} +// static_assertions::assert_not_impl_any!(String: Send); +// } diff --git a/src/table.rs b/src/table.rs index 9eca8d5..3e0edb5 100644 --- a/src/table.rs +++ b/src/table.rs @@ -22,30 +22,9 @@ use futures_util::future::{self, LocalBoxFuture}; /// Handle to an internal Lua table. #[derive(Clone)] -pub struct Table<'lua>(pub(crate) ValueRef<'lua>); +pub struct Table(pub(crate) ValueRef); -/// Owned handle to an internal Lua table. -/// -/// The owned handle holds a *strong* reference to the current Lua instance. -/// Be warned, if you place it into a Lua type (eg. [`UserData`] or a Rust callback), it is *very easy* -/// to accidentally cause reference cycles that would prevent destroying Lua instance. -/// -/// [`UserData`]: crate::UserData -#[cfg(feature = "unstable")] -#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] -#[derive(Clone, Debug)] -pub struct OwnedTable(pub(crate) crate::types::OwnedValueRef); - -#[cfg(feature = "unstable")] -impl OwnedTable { - /// Get borrowed handle to the underlying Lua table. - #[cfg_attr(feature = "send", allow(unused))] - pub const fn to_ref(&self) -> Table { - Table(self.0.to_ref()) - } -} - -impl<'lua> Table<'lua> { +impl Table { /// Sets a key-value pair in the table. /// /// If the value is `nil`, this will effectively remove the pair. @@ -85,15 +64,15 @@ impl<'lua> Table<'lua> { return self.raw_set(key, value); } - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); check_stack(state, 5)?; lua.push_ref(&self.0); - key.push_into_stack(lua)?; - value.push_into_stack(lua)?; + key.push_into_stack(&lua)?; + value.push_into_stack(&lua)?; protect_lua!(state, 3, 0, fn(state) ffi::lua_settable(state, -3)) } } @@ -122,23 +101,23 @@ impl<'lua> Table<'lua> { /// ``` /// /// [`raw_get`]: #method.raw_get - pub fn get<K: IntoLua, V: FromLua<'lua>>(&self, key: K) -> Result<V> { + pub fn get<K: IntoLua, V: FromLua>(&self, key: K) -> Result<V> { // Fast track if !self.has_metatable() { return self.raw_get(key); } - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); check_stack(state, 4)?; lua.push_ref(&self.0); - key.push_into_stack(lua)?; + key.push_into_stack(&lua)?; protect_lua!(state, 2, 1, fn(state) ffi::lua_gettable(state, -2))?; - V::from_stack(-1, lua) + V::from_stack(-1, &lua) } } @@ -158,14 +137,14 @@ impl<'lua> Table<'lua> { return self.raw_push(value); } - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); check_stack(state, 4)?; lua.push_ref(&self.0); - value.push_into_stack(lua)?; + value.push_into_stack(&lua)?; protect_lua!(state, 2, 0, fn(state) { let len = ffi::luaL_len(state, -2) as Integer; ffi::lua_seti(state, -2, len + 1); @@ -177,13 +156,13 @@ impl<'lua> Table<'lua> { /// Removes the last element from the table and returns it. /// /// This might invoke the `__len` and `__newindex` metamethods. - pub fn pop<V: FromLua<'lua>>(&self) -> Result<V> { + pub fn pop<V: FromLua>(&self) -> Result<V> { // Fast track if !self.has_metatable() { return self.raw_pop(); } - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -196,7 +175,7 @@ impl<'lua> Table<'lua> { ffi::lua_pushnil(state); ffi::lua_seti(state, -3, len); })?; - V::from_stack(-1, lua) + V::from_stack(-1, &lua) } } @@ -257,15 +236,15 @@ impl<'lua> Table<'lua> { #[cfg(feature = "luau")] self.check_readonly_write()?; - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); check_stack(state, 5)?; lua.push_ref(&self.0); - key.push_into_stack(lua)?; - value.push_into_stack(lua)?; + key.push_into_stack(&lua)?; + value.push_into_stack(&lua)?; if lua.unlikely_memory_error() { ffi::lua_rawset(state, -3); @@ -278,18 +257,18 @@ impl<'lua> Table<'lua> { } /// Gets the value associated to `key` without invoking metamethods. - pub fn raw_get<K: IntoLua, V: FromLua<'lua>>(&self, key: K) -> Result<V> { - let lua = self.0.lua; + pub fn raw_get<K: IntoLua, V: FromLua>(&self, key: K) -> Result<V> { + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); check_stack(state, 3)?; lua.push_ref(&self.0); - key.push_into_stack(lua)?; + key.push_into_stack(&lua)?; ffi::lua_rawget(state, -2); - V::from_stack(-1, lua) + V::from_stack(-1, &lua) } } @@ -301,14 +280,14 @@ impl<'lua> Table<'lua> { return Err(Error::runtime("index out of bounds")); } - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); check_stack(state, 5)?; lua.push_ref(&self.0); - value.push_into_stack(lua)?; + value.push_into_stack(&lua)?; protect_lua!(state, 2, 0, |state| { for i in (idx..=size).rev() { // table[i+1] = table[i] @@ -325,14 +304,14 @@ impl<'lua> Table<'lua> { #[cfg(feature = "luau")] self.check_readonly_write()?; - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); check_stack(state, 4)?; lua.push_ref(&self.0); - value.push_into_stack(lua)?; + value.push_into_stack(&lua)?; unsafe fn callback(state: *mut ffi::lua_State) { let len = ffi::lua_rawlen(state, -2) as Integer; @@ -349,11 +328,11 @@ impl<'lua> Table<'lua> { } /// Removes the last element from the table and returns it, without invoking metamethods. - pub fn raw_pop<V: FromLua<'lua>>(&self) -> Result<V> { + pub fn raw_pop<V: FromLua>(&self) -> Result<V> { #[cfg(feature = "luau")] self.check_readonly_write()?; - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -366,7 +345,7 @@ impl<'lua> Table<'lua> { ffi::lua_pushnil(state); ffi::lua_rawseti(state, -3, len); - V::from_stack(-1, lua) + V::from_stack(-1, &lua) } } @@ -378,9 +357,9 @@ impl<'lua> Table<'lua> { /// /// For other key types this is equivalent to setting `table[key] = nil`. pub fn raw_remove<K: IntoLua>(&self, key: K) -> Result<()> { - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); - let key = key.into_lua(lua)?; + let key = key.into_lua(lua.lua())?; match key { Value::Integer(idx) => { let size = self.raw_len() as Integer; @@ -414,7 +393,7 @@ impl<'lua> Table<'lua> { #[cfg(feature = "luau")] self.check_readonly_write()?; - let lua = self.0.lua; + let lua = self.0.lua.lock(); unsafe { #[cfg(feature = "luau")] ffi::lua_cleartable(lua.ref_thread(), self.0.index); @@ -458,7 +437,7 @@ impl<'lua> Table<'lua> { return Ok(self.raw_len() as Integer); } - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -471,8 +450,8 @@ impl<'lua> Table<'lua> { /// Returns the result of the Lua `#` operator, without invoking the `__len` metamethod. pub fn raw_len(&self) -> usize { - let ref_thread = self.0.lua.ref_thread(); - unsafe { ffi::lua_rawlen(ref_thread, self.0.index) } + let lua = self.0.lua.lock(); + unsafe { ffi::lua_rawlen(lua.ref_thread(), self.0.index) } } /// Returns `true` if the table is empty, without invoking metamethods. @@ -485,7 +464,7 @@ impl<'lua> Table<'lua> { } // Check hash part - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -504,8 +483,8 @@ impl<'lua> Table<'lua> { /// Returns a reference to the metatable of this table, or `None` if no metatable is set. /// /// Unlike the `getmetatable` Lua function, this method ignores the `__metatable` field. - pub fn get_metatable(&self) -> Option<Table<'lua>> { - let lua = self.0.lua; + pub fn get_metatable(&self) -> Option<Table> { + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -524,14 +503,14 @@ impl<'lua> Table<'lua> { /// /// If `metatable` is `None`, the metatable is removed (if no metatable is set, this does /// nothing). - pub fn set_metatable(&self, metatable: Option<Table<'lua>>) { + pub fn set_metatable(&self, metatable: Option<Table>) { // Workaround to throw readonly error without returning Result #[cfg(feature = "luau")] if self.is_readonly() { panic!("attempt to modify a readonly table"); } - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -551,7 +530,8 @@ impl<'lua> Table<'lua> { #[doc(hidden)] #[inline] pub fn has_metatable(&self) -> bool { - let ref_thread = self.0.lua.ref_thread(); + let lua = self.0.lua.lock(); + let ref_thread = lua.ref_thread(); unsafe { if ffi::lua_getmetatable(ref_thread, self.0.index) != 0 { ffi::lua_pop(ref_thread, 1); @@ -567,7 +547,8 @@ impl<'lua> Table<'lua> { #[cfg(any(feature = "luau", doc))] #[cfg_attr(docsrs, doc(cfg(feature = "luau")))] pub fn set_readonly(&self, enabled: bool) { - let ref_thread = self.0.lua.ref_thread(); + let lua = self.0.lua.lock(); + let ref_thread = lua.ref_thread(); unsafe { ffi::lua_setreadonly(ref_thread, self.0.index, enabled as _); if !enabled { @@ -583,7 +564,8 @@ impl<'lua> Table<'lua> { #[cfg(any(feature = "luau", doc))] #[cfg_attr(docsrs, doc(cfg(feature = "luau")))] pub fn is_readonly(&self) -> bool { - let ref_thread = self.0.lua.ref_thread(); + let lua = self.0.lua.lock(); + let ref_thread = lua.ref_thread(); unsafe { ffi::lua_getreadonly(ref_thread, self.0.index) != 0 } } @@ -598,14 +580,6 @@ impl<'lua> Table<'lua> { self.0.to_pointer() } - /// Convert this handle to owned version. - #[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] - #[inline] - pub fn into_owned(self) -> OwnedTable { - OwnedTable(self.0.into_owned()) - } - /// Consume this table and return an iterator over the pairs of the table. /// /// This works like the Lua `pairs` function, but does not invoke the `__pairs` metamethod. @@ -639,7 +613,7 @@ impl<'lua> Table<'lua> { /// /// [`Result`]: crate::Result /// [Lua manual]: http://www.lua.org/manual/5.4/manual.html#pdf-next - pub fn pairs<K: FromLua<'lua>, V: FromLua<'lua>>(self) -> TablePairs<'lua, K, V> { + pub fn pairs<K: FromLua, V: FromLua>(self) -> TablePairs<K, V> { TablePairs { table: self.0, key: Some(Nil), @@ -653,10 +627,10 @@ impl<'lua> Table<'lua> { /// It does not invoke the `__pairs` metamethod. pub fn for_each<K, V>(&self, mut f: impl FnMut(K, V) -> Result<()>) -> Result<()> where - K: FromLua<'lua>, - V: FromLua<'lua>, + K: FromLua, + V: FromLua, { - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -665,8 +639,8 @@ impl<'lua> Table<'lua> { lua.push_ref(&self.0); ffi::lua_pushnil(state); while ffi::lua_next(state, -2) != 0 { - let k = K::from_stack(-2, lua)?; - let v = V::from_stack(-1, lua)?; + let k = K::from_stack(-2, &lua)?; + let v = V::from_stack(-1, &lua)?; f(k, v)?; // Keep key for next iteration ffi::lua_pop(state, 1); @@ -713,7 +687,7 @@ impl<'lua> Table<'lua> { /// [`pairs`]: #method.pairs /// [`Result`]: crate::Result /// [Lua manual]: http://www.lua.org/manual/5.4/manual.html#pdf-next - pub fn sequence_values<V: FromLua<'lua>>(self) -> TableSequence<'lua, V> { + pub fn sequence_values<V: FromLua>(self) -> TableSequence<V> { TableSequence { table: self.0, index: 1, @@ -723,16 +697,16 @@ impl<'lua> Table<'lua> { #[doc(hidden)] #[deprecated(since = "0.9.0", note = "use `sequence_values` instead")] - pub fn raw_sequence_values<V: FromLua<'lua>>(self) -> TableSequence<'lua, V> { + pub fn raw_sequence_values<V: FromLua>(self) -> TableSequence<V> { self.sequence_values() } #[cfg(feature = "serialize")] pub(crate) fn for_each_value<V>(&self, mut f: impl FnMut(V) -> Result<()>) -> Result<()> where - V: FromLua<'lua>, + V: FromLua, { - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -742,7 +716,7 @@ impl<'lua> Table<'lua> { let len = ffi::lua_rawlen(state, -1); for i in 1..=len { ffi::lua_rawgeti(state, -1, i as _); - f(V::from_stack(-1, lua)?)?; + f(V::from_stack(-1, &lua)?)?; ffi::lua_pop(state, 1); } } @@ -755,14 +729,14 @@ impl<'lua> Table<'lua> { #[cfg(feature = "luau")] self.check_readonly_write()?; - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); check_stack(state, 5)?; lua.push_ref(&self.0); - value.push_into_stack(lua)?; + value.push_into_stack(&lua)?; let idx = idx.try_into().unwrap(); if lua.unlikely_memory_error() { @@ -776,7 +750,7 @@ impl<'lua> Table<'lua> { #[cfg(feature = "serialize")] pub(crate) fn is_array(&self) -> bool { - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -828,7 +802,7 @@ impl<'lua> Table<'lua> { } } -impl fmt::Debug for Table<'_> { +impl fmt::Debug for Table { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { if fmt.alternate() { return self.fmt_pretty(fmt, 0, &mut HashSet::new()); @@ -837,25 +811,25 @@ impl fmt::Debug for Table<'_> { } } -impl<'lua> PartialEq for Table<'lua> { +impl PartialEq for Table { fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } -impl<'lua> AsRef<Table<'lua>> for Table<'lua> { +impl AsRef<Table> for Table { #[inline] fn as_ref(&self) -> &Self { self } } -impl<'lua, T> PartialEq<[T]> for Table<'lua> +impl<T> PartialEq<[T]> for Table where T: IntoLua + Clone, { fn eq(&self, other: &[T]) -> bool { - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -870,7 +844,7 @@ where if val == Nil { return i == other.len(); } - match other.get(i).map(|v| v.clone().into_lua(lua)) { + match other.get(i).map(|v| v.clone().into_lua(lua.lua())) { Some(Ok(other_val)) if val == other_val => continue, _ => return false, } @@ -880,7 +854,7 @@ where } } -impl<'lua, T> PartialEq<&[T]> for Table<'lua> +impl<T> PartialEq<&[T]> for Table where T: IntoLua + Clone, { @@ -890,7 +864,7 @@ where } } -impl<'lua, T, const N: usize> PartialEq<[T; N]> for Table<'lua> +impl<T, const N: usize> PartialEq<[T; N]> for Table where T: IntoLua + Clone, { @@ -901,24 +875,24 @@ where } /// An extension trait for `Table`s that provides a variety of convenient functionality. -pub trait TableExt<'lua>: Sealed { +pub trait TableExt: Sealed { /// Calls the table as function assuming it has `__call` metamethod. /// /// The metamethod is called with the table as its first argument, followed by the passed arguments. fn call<A, R>(&self, args: A) -> Result<R> where A: IntoLuaMulti, - R: FromLuaMulti<'lua>; + R: FromLuaMulti; /// Asynchronously calls the table as function assuming it has `__call` metamethod. /// /// The metamethod is called with the table as its first argument, followed by the passed arguments. #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn call_async<A, R>(&self, args: A) -> LocalBoxFuture<'lua, Result<R>> + fn call_async<A, R>(&self, args: A) -> LocalBoxFuture<'static, Result<R>> where A: IntoLuaMulti, - R: FromLuaMulti<'lua> + 'lua; + R: FromLuaMulti + 'static; /// Gets the function associated to `key` from the table and executes it, /// passing the table itself along with `args` as function arguments. @@ -930,7 +904,7 @@ pub trait TableExt<'lua>: Sealed { fn call_method<A, R>(&self, name: &str, args: A) -> Result<R> where A: IntoLuaMulti, - R: FromLuaMulti<'lua>; + R: FromLuaMulti; /// Gets the function associated to `key` from the table and executes it, /// passing `args` as function arguments. @@ -942,7 +916,7 @@ pub trait TableExt<'lua>: Sealed { fn call_function<A, R>(&self, name: &str, args: A) -> Result<R> where A: IntoLuaMulti, - R: FromLuaMulti<'lua>; + R: FromLuaMulti; /// Gets the function associated to `key` from the table and asynchronously executes it, /// passing the table itself along with `args` as function arguments and returning Future. @@ -952,10 +926,10 @@ pub trait TableExt<'lua>: Sealed { /// This might invoke the `__index` metamethod. #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn call_async_method<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'lua, Result<R>> + fn call_async_method<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'static, Result<R>> where A: IntoLuaMulti, - R: FromLuaMulti<'lua> + 'lua; + R: FromLuaMulti + 'static; /// Gets the function associated to `key` from the table and asynchronously executes it, /// passing `args` as function arguments and returning Future. @@ -965,29 +939,30 @@ pub trait TableExt<'lua>: Sealed { /// This might invoke the `__index` metamethod. #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn call_async_function<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'lua, Result<R>> + fn call_async_function<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'static, Result<R>> where A: IntoLuaMulti, - R: FromLuaMulti<'lua> + 'lua; + R: FromLuaMulti + 'static; } -impl<'lua> TableExt<'lua> for Table<'lua> { +impl TableExt for Table { fn call<A, R>(&self, args: A) -> Result<R> where A: IntoLuaMulti, - R: FromLuaMulti<'lua>, + R: FromLuaMulti, { // Convert table to a function and call via pcall that respects the `__call` metamethod. Function(self.0.clone()).call(args) } #[cfg(feature = "async")] - fn call_async<A, R>(&self, args: A) -> LocalBoxFuture<'lua, Result<R>> + fn call_async<A, R>(&self, args: A) -> LocalBoxFuture<'static, Result<R>> where A: IntoLuaMulti, - R: FromLuaMulti<'lua> + 'lua, + R: FromLuaMulti + 'static, { - let args = match args.into_lua_multi(self.0.lua) { + let lua = self.0.lua.lock(); + let args = match args.into_lua_multi(lua.lua()) { Ok(args) => args, Err(e) => return Box::pin(future::err(e)), }; @@ -998,7 +973,7 @@ impl<'lua> TableExt<'lua> for Table<'lua> { fn call_method<A, R>(&self, name: &str, args: A) -> Result<R> where A: IntoLuaMulti, - R: FromLuaMulti<'lua>, + R: FromLuaMulti, { self.get::<_, Function>(name)?.call((self, args)) } @@ -1006,30 +981,30 @@ impl<'lua> TableExt<'lua> for Table<'lua> { fn call_function<A, R>(&self, name: &str, args: A) -> Result<R> where A: IntoLuaMulti, - R: FromLuaMulti<'lua>, + R: FromLuaMulti, { self.get::<_, Function>(name)?.call(args) } #[cfg(feature = "async")] - fn call_async_method<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'lua, Result<R>> + fn call_async_method<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'static, Result<R>> where A: IntoLuaMulti, - R: FromLuaMulti<'lua> + 'lua, + R: FromLuaMulti + 'static, { self.call_async_function(name, (self, args)) } #[cfg(feature = "async")] - fn call_async_function<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'lua, Result<R>> + fn call_async_function<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'static, Result<R>> where A: IntoLuaMulti, - R: FromLuaMulti<'lua> + 'lua, + R: FromLuaMulti + 'static, { - let lua = self.0.lua; + let lua = self.0.lua.lock(); match self.get::<_, Function>(name) { Ok(func) => { - let args = match args.into_lua_multi(lua) { + let args = match args.into_lua_multi(lua.lua()) { Ok(args) => args, Err(e) => return Box::pin(future::err(e)), }; @@ -1042,14 +1017,14 @@ impl<'lua> TableExt<'lua> for Table<'lua> { /// A wrapped [`Table`] with customized serialization behavior. #[cfg(feature = "serialize")] -pub(crate) struct SerializableTable<'a, 'lua> { - table: &'a Table<'lua>, +pub(crate) struct SerializableTable<'a> { + table: &'a Table, options: crate::serde::de::Options, visited: Rc<RefCell<FxHashSet<*const c_void>>>, } #[cfg(feature = "serialize")] -impl<'lua> Serialize for Table<'lua> { +impl Serialize for Table { #[inline] fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> { SerializableTable::new(self, Default::default(), Default::default()).serialize(serializer) @@ -1057,10 +1032,10 @@ impl<'lua> Serialize for Table<'lua> { } #[cfg(feature = "serialize")] -impl<'a, 'lua> SerializableTable<'a, 'lua> { +impl<'a> SerializableTable<'a> { #[inline] pub(crate) fn new( - table: &'a Table<'lua>, + table: &'a Table, options: crate::serde::de::Options, visited: Rc<RefCell<FxHashSet<*const c_void>>>, ) -> Self { @@ -1073,7 +1048,7 @@ impl<'a, 'lua> SerializableTable<'a, 'lua> { } #[cfg(feature = "serialize")] -impl<'a, 'lua> Serialize for SerializableTable<'a, 'lua> { +impl<'a> Serialize for SerializableTable<'a> { fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error> where S: Serializer, @@ -1157,22 +1132,22 @@ impl<'a, 'lua> Serialize for SerializableTable<'a, 'lua> { /// This struct is created by the [`Table::pairs`] method. /// /// [`Table::pairs`]: crate::Table::pairs -pub struct TablePairs<'lua, K, V> { - table: ValueRef<'lua>, - key: Option<Value<'lua>>, +pub struct TablePairs<K, V> { + table: ValueRef, + key: Option<Value>, _phantom: PhantomData<(K, V)>, } -impl<'lua, K, V> Iterator for TablePairs<'lua, K, V> +impl<K, V> Iterator for TablePairs<K, V> where - K: FromLua<'lua>, - V: FromLua<'lua>, + K: FromLua, + V: FromLua, { type Item = Result<(K, V)>; fn next(&mut self) -> Option<Self::Item> { if let Some(prev_key) = self.key.take() { - let lua = self.table.lua; + let lua = self.table.lua.lock(); let state = lua.state(); let res = (|| unsafe { @@ -1189,8 +1164,8 @@ where let key = lua.stack_value(-2); Ok(Some(( key.clone(), - K::from_lua(key, lua)?, - V::from_stack(-1, lua)?, + K::from_lua(key, lua.lua())?, + V::from_stack(-1, &lua)?, ))) } else { Ok(None) @@ -1216,21 +1191,21 @@ where /// This struct is created by the [`Table::sequence_values`] method. /// /// [`Table::sequence_values`]: crate::Table::sequence_values -pub struct TableSequence<'lua, V> { +pub struct TableSequence<V> { // TODO: Use `&Table` - table: ValueRef<'lua>, + table: ValueRef, index: Integer, _phantom: PhantomData<V>, } -impl<'lua, V> Iterator for TableSequence<'lua, V> +impl<V> Iterator for TableSequence<V> where - V: FromLua<'lua>, + V: FromLua, { type Item = Result<V>; fn next(&mut self) -> Option<Self::Item> { - let lua = self.table.lua; + let lua = self.table.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -1243,19 +1218,16 @@ where ffi::LUA_TNIL => None, _ => { self.index += 1; - Some(V::from_stack(-1, lua)) + Some(V::from_stack(-1, &lua)) } } } } } -#[cfg(test)] -mod assertions { - use super::*; +// #[cfg(test)] +// mod assertions { +// use super::*; - static_assertions::assert_not_impl_any!(Table: Send); - - #[cfg(feature = "unstable")] - static_assertions::assert_not_impl_any!(OwnedTable: Send); -} +// static_assertions::assert_not_impl_any!(Table: Send); +// } diff --git a/src/thread.rs b/src/thread.rs index 489416f..b6a0e86 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -3,6 +3,7 @@ use std::os::raw::{c_int, c_void}; use crate::error::{Error, Result}; #[allow(unused)] use crate::lua::Lua; +use crate::lua::LuaInner; use crate::types::ValueRef; use crate::util::{check_stack, error_traceback_thread, pop_error, StackGuard}; use crate::value::{FromLuaMulti, IntoLuaMulti}; @@ -43,31 +44,7 @@ pub enum ThreadStatus { /// Handle to an internal Lua thread (coroutine). #[derive(Clone, Debug)] -pub struct Thread<'lua>(pub(crate) ValueRef<'lua>, pub(crate) *mut ffi::lua_State); - -/// Owned handle to an internal Lua thread (coroutine). -/// -/// The owned handle holds a *strong* reference to the current Lua instance. -/// Be warned, if you place it into a Lua type (eg. [`UserData`] or a Rust callback), it is *very easy* -/// to accidentally cause reference cycles that would prevent destroying Lua instance. -/// -/// [`UserData`]: crate::UserData -#[cfg(feature = "unstable")] -#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] -#[derive(Clone, Debug)] -pub struct OwnedThread( - pub(crate) crate::types::OwnedValueRef, - pub(crate) *mut ffi::lua_State, -); - -#[cfg(feature = "unstable")] -impl OwnedThread { - /// Get borrowed handle to the underlying Lua table. - #[cfg_attr(feature = "send", allow(unused))] - pub const fn to_ref(&self) -> Thread { - Thread(self.0.to_ref(), self.1) - } -} +pub struct Thread(pub(crate) ValueRef, pub(crate) *mut ffi::lua_State); /// Thread (coroutine) representation as an async [`Future`] or [`Stream`]. /// @@ -78,17 +55,17 @@ impl OwnedThread { #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] #[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct AsyncThread<'lua, R> { - thread: Thread<'lua>, - init_args: Option<Result<MultiValue<'lua>>>, +pub struct AsyncThread<R> { + thread: Thread, + init_args: Option<Result<MultiValue>>, ret: PhantomData<R>, recycle: bool, } -impl<'lua> Thread<'lua> { +impl Thread { #[inline(always)] - pub(crate) fn new(r#ref: ValueRef<'lua>) -> Self { - let state = unsafe { ffi::lua_tothread(r#ref.lua.ref_thread(), r#ref.index) }; + pub(crate) fn new(lua: &LuaInner, r#ref: ValueRef) -> Self { + let state = unsafe { ffi::lua_tothread(lua.ref_thread(), r#ref.index) }; Thread(r#ref, state) } @@ -140,13 +117,14 @@ impl<'lua> Thread<'lua> { pub fn resume<A, R>(&self, args: A) -> Result<R> where A: IntoLuaMulti, - R: FromLuaMulti<'lua>, + R: FromLuaMulti, { - if self.status() != ThreadStatus::Resumable { + let lua = self.0.lua.lock(); + + if unsafe { self.status_unprotected() } != ThreadStatus::Resumable { return Err(Error::CoroutineInactive); } - let lua = self.0.lua; let state = lua.state(); let thread_state = self.state(); unsafe { @@ -157,7 +135,7 @@ impl<'lua> Thread<'lua> { check_stack(state, nresults + 1)?; ffi::lua_xmove(thread_state, state, nresults); - R::from_stack_multi(nresults, lua) + R::from_stack_multi(nresults, &lua) } } @@ -165,11 +143,11 @@ impl<'lua> Thread<'lua> { /// /// It's similar to `resume()` but leaves `nresults` values on the thread stack. unsafe fn resume_inner<A: IntoLuaMulti>(&self, args: A) -> Result<c_int> { - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); let thread_state = self.state(); - let nargs = args.push_into_stack_multi(lua)?; + let nargs = args.push_into_stack_multi(&lua)?; if nargs > 0 { check_stack(thread_state, nargs)?; ffi::lua_xmove(state, thread_state, nargs); @@ -195,20 +173,25 @@ impl<'lua> Thread<'lua> { /// Gets the status of the thread. pub fn status(&self) -> ThreadStatus { + let _guard = self.0.lua.lock(); + unsafe { self.status_unprotected() } + } + + /// Gets the status of the thread without locking the Lua state. + pub(crate) unsafe fn status_unprotected(&self) -> ThreadStatus { let thread_state = self.state(); - if thread_state == self.0.lua.state() { + // FIXME: skip double lock + if thread_state == self.0.lua.lock().state() { // The coroutine is currently running return ThreadStatus::Unresumable; } - unsafe { - let status = ffi::lua_status(thread_state); - if status != ffi::LUA_OK && status != ffi::LUA_YIELD { - ThreadStatus::Error - } else if status == ffi::LUA_YIELD || ffi::lua_gettop(thread_state) > 0 { - ThreadStatus::Resumable - } else { - ThreadStatus::Unresumable - } + let status = ffi::lua_status(thread_state); + if status != ffi::LUA_OK && status != ffi::LUA_YIELD { + ThreadStatus::Error + } else if status == ffi::LUA_YIELD || ffi::lua_gettop(thread_state) > 0 { + ThreadStatus::Resumable + } else { + ThreadStatus::Unresumable } } @@ -222,7 +205,7 @@ impl<'lua> Thread<'lua> { where F: Fn(&Lua, Debug) -> Result<()> + MaybeSend + 'static, { - let lua = self.0.lua; + let lua = self.0.lua.lock(); unsafe { lua.set_thread_hook(self.state(), triggers, callback); } @@ -244,8 +227,8 @@ impl<'lua> Thread<'lua> { /// [Lua 5.4]: https://www.lua.org/manual/5.4/manual.html#lua_closethread #[cfg(any(feature = "lua54", feature = "luau"))] #[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "luau"))))] - pub fn reset(&self, func: crate::function::Function<'lua>) -> Result<()> { - let lua = self.0.lua; + pub fn reset(&self, func: crate::function::Function) -> Result<()> { + let lua = self.0.lua.lock(); let thread_state = self.state(); if thread_state == lua.state() { return Err(Error::runtime("cannot reset a running thread")); @@ -323,12 +306,13 @@ impl<'lua> Thread<'lua> { /// ``` #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - pub fn into_async<A, R>(self, args: A) -> AsyncThread<'lua, R> + pub fn into_async<A, R>(self, args: A) -> AsyncThread<R> where A: IntoLuaMulti, - R: FromLuaMulti<'lua>, + R: FromLuaMulti, { - let args = args.into_lua_multi(self.0.lua); + let lua = self.0.lua.lock(); + let args = args.into_lua_multi(lua.lua()); AsyncThread { thread: self, init_args: Some(args), @@ -372,7 +356,7 @@ impl<'lua> Thread<'lua> { #[cfg_attr(docsrs, doc(cfg(feature = "luau")))] #[doc(hidden)] pub fn sandbox(&self) -> Result<()> { - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); let thread_state = self.state(); unsafe { @@ -391,44 +375,16 @@ impl<'lua> Thread<'lua> { pub fn to_pointer(&self) -> *const c_void { self.0.to_pointer() } - - /// Convert this handle to owned version. - #[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] - #[inline] - pub fn into_owned(self) -> OwnedThread { - OwnedThread(self.0.into_owned(), self.1) - } } -impl<'lua> PartialEq for Thread<'lua> { +impl PartialEq for Thread { fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } -// Additional shortcuts -#[cfg(feature = "unstable")] -impl OwnedThread { - /// Resumes execution of this thread. - /// - /// See [`Thread::resume()`] for more details. - pub fn resume<'lua, A, R>(&'lua self, args: A) -> Result<R> - where - A: IntoLuaMulti, - R: FromLuaMulti<'lua>, - { - self.to_ref().resume(args) - } - - /// Gets the status of the thread. - pub fn status(&self) -> ThreadStatus { - self.to_ref().status() - } -} - #[cfg(feature = "async")] -impl<'lua, R> AsyncThread<'lua, R> { +impl<R> AsyncThread<R> { #[inline] pub(crate) fn set_recyclable(&mut self, recyclable: bool) { self.recycle = recyclable; @@ -437,15 +393,15 @@ impl<'lua, R> AsyncThread<'lua, R> { #[cfg(feature = "async")] #[cfg(any(feature = "lua54", feature = "luau"))] -impl<'lua, R> Drop for AsyncThread<'lua, R> { +impl<R> Drop for AsyncThread<R> { fn drop(&mut self) { if self.recycle { unsafe { - let lua = self.thread.0.lua; + let lua = self.thread.0.lua.lock(); // For Lua 5.4 this also closes all pending to-be-closed variables if !lua.recycle_thread(&mut self.thread) { #[cfg(feature = "lua54")] - if self.thread.status() == ThreadStatus::Error { + if self.thread.status_unprotected() == ThreadStatus::Error { #[cfg(not(feature = "vendored"))] ffi::lua_resetthread(self.thread.state()); #[cfg(feature = "vendored")] @@ -458,24 +414,21 @@ impl<'lua, R> Drop for AsyncThread<'lua, R> { } #[cfg(feature = "async")] -impl<'lua, R> Stream for AsyncThread<'lua, R> -where - R: FromLuaMulti<'lua>, -{ +impl<R: FromLuaMulti> Stream for AsyncThread<R> { type Item = Result<R>; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { - if self.thread.status() != ThreadStatus::Resumable { - return Poll::Ready(None); - } - - let lua = self.thread.0.lua; + let lua = self.thread.0.lua.lock(); let state = lua.state(); let thread_state = self.thread.state(); unsafe { + if self.thread.status_unprotected() != ThreadStatus::Resumable { + return Poll::Ready(None); + } + let _sg = StackGuard::new(state); let _thread_sg = StackGuard::with_top(thread_state, 0); - let _wg = WakerGuard::new(lua, cx.waker()); + let _wg = WakerGuard::new(&lua, cx.waker()); // This is safe as we are not moving the whole struct let this = self.get_unchecked_mut(); @@ -493,30 +446,27 @@ where ffi::lua_xmove(thread_state, state, nresults); cx.waker().wake_by_ref(); - Poll::Ready(Some(R::from_stack_multi(nresults, lua))) + Poll::Ready(Some(R::from_stack_multi(nresults, &lua))) } } } #[cfg(feature = "async")] -impl<'lua, R> Future for AsyncThread<'lua, R> -where - R: FromLuaMulti<'lua>, -{ +impl<R: FromLuaMulti> Future for AsyncThread<R> { type Output = Result<R>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { - if self.thread.status() != ThreadStatus::Resumable { - return Poll::Ready(Err(Error::CoroutineInactive)); - } - - let lua = self.thread.0.lua; + let lua = self.thread.0.lua.lock(); let state = lua.state(); let thread_state = self.thread.state(); unsafe { + if self.thread.status_unprotected() != ThreadStatus::Resumable { + return Poll::Ready(Err(Error::CoroutineInactive)); + } + let _sg = StackGuard::new(state); let _thread_sg = StackGuard::with_top(thread_state, 0); - let _wg = WakerGuard::new(lua, cx.waker()); + let _wg = WakerGuard::new(&lua, cx.waker()); // This is safe as we are not moving the whole struct let this = self.get_unchecked_mut(); @@ -539,7 +489,7 @@ where check_stack(state, nresults + 1)?; ffi::lua_xmove(thread_state, state, nresults); - Poll::Ready(R::from_stack_multi(nresults, lua)) + Poll::Ready(R::from_stack_multi(nresults, &lua)) } } } @@ -552,7 +502,7 @@ unsafe fn is_poll_pending(state: *mut ffi::lua_State) -> bool { #[cfg(feature = "async")] struct WakerGuard<'lua, 'a> { - lua: &'lua Lua, + lua: &'lua LuaInner, prev: NonNull<Waker>, _phantom: PhantomData<&'a ()>, } @@ -560,7 +510,7 @@ struct WakerGuard<'lua, 'a> { #[cfg(feature = "async")] impl<'lua, 'a> WakerGuard<'lua, 'a> { #[inline] - pub fn new(lua: &'lua Lua, waker: &'a Waker) -> Result<WakerGuard<'lua, 'a>> { + pub fn new(lua: &'lua LuaInner, waker: &'a Waker) -> Result<WakerGuard<'lua, 'a>> { let prev = unsafe { lua.set_waker(NonNull::from(waker)) }; Ok(WakerGuard { lua, diff --git a/src/types.rs b/src/types.rs index aa8ccad..f15f79e 100644 --- a/src/types.rs +++ b/src/types.rs @@ -5,22 +5,20 @@ use std::ops::{Deref, DerefMut}; use std::os::raw::{c_int, c_void}; use std::result::Result as StdResult; use std::sync::atomic::{AtomicI32, Ordering}; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use std::{fmt, mem, ptr}; +use parking_lot::{Mutex, RawMutex, RawThreadId}; use rustc_hash::FxHashMap; use crate::error::Result; #[cfg(not(feature = "luau"))] use crate::hook::Debug; -use crate::lua::{ExtraData, Lua}; +use crate::lua::{ExtraData, Lua, LuaGuard, LuaInner, WeakLua}; #[cfg(feature = "async")] use {crate::value::MultiValue, futures_util::future::LocalBoxFuture}; -#[cfg(feature = "unstable")] -use {crate::lua::LuaInner, std::marker::PhantomData}; - #[cfg(all(feature = "luau", feature = "serialize"))] use serde::ser::{Serialize, SerializeTupleStruct, Serializer}; @@ -43,21 +41,21 @@ pub(crate) enum SubtypeId { #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct LightUserData(pub *mut c_void); -pub(crate) type Callback<'lua, 'a> = Box<dyn Fn(&'lua Lua, c_int) -> Result<c_int> + 'a>; +pub(crate) type Callback<'a> = Box<dyn Fn(&'a LuaInner, c_int) -> Result<c_int> + 'static>; pub(crate) struct Upvalue<T> { pub(crate) data: T, pub(crate) extra: Arc<UnsafeCell<ExtraData>>, } -pub(crate) type CallbackUpvalue = Upvalue<Callback<'static, 'static>>; +pub(crate) type CallbackUpvalue = Upvalue<Callback<'static>>; #[cfg(feature = "async")] -pub(crate) type AsyncCallback<'lua, 'a> = - Box<dyn Fn(&'lua Lua, MultiValue<'lua>) -> LocalBoxFuture<'lua, Result<c_int>> + 'a>; +pub(crate) type AsyncCallback<'a> = + Box<dyn Fn(&'a LuaInner, MultiValue) -> LocalBoxFuture<'a, Result<c_int>> + 'static>; #[cfg(feature = "async")] -pub(crate) type AsyncCallbackUpvalue = Upvalue<AsyncCallback<'static, 'static>>; +pub(crate) type AsyncCallbackUpvalue = Upvalue<AsyncCallback<'static>>; #[cfg(feature = "async")] pub(crate) type AsyncPollUpvalue = Upvalue<LocalBoxFuture<'static, Result<c_int>>>; @@ -184,6 +182,9 @@ impl PartialEq<[f32; Self::SIZE]> for Vector { } } +pub(crate) type ArcReentrantMutexGuard<T> = + parking_lot::lock_api::ArcReentrantMutexGuard<RawMutex, RawThreadId, T>; + pub(crate) struct DestructedUserdata; /// An auto generated key into the Lua registry. @@ -233,7 +234,7 @@ impl Drop for RegistryKey { let registry_id = self.id(); // We don't need to collect nil slot if registry_id > ffi::LUA_REFNIL { - let mut unref_list = mlua_expect!(self.unref_list.lock(), "unref list poisoned"); + let mut unref_list = self.unref_list.lock(); if let Some(list) = unref_list.as_mut() { list.push(registry_id); } @@ -273,16 +274,16 @@ impl RegistryKey { } } -pub(crate) struct ValueRef<'lua> { - pub(crate) lua: &'lua Lua, +pub(crate) struct ValueRef { + pub(crate) lua: WeakLua, pub(crate) index: c_int, pub(crate) drop: bool, } -impl<'lua> ValueRef<'lua> { - pub(crate) const fn new(lua: &'lua Lua, index: c_int) -> Self { +impl ValueRef { + pub(crate) fn new(lua: &LuaInner, index: c_int) -> Self { ValueRef { - lua, + lua: lua.weak().clone(), index, drop: true, } @@ -290,95 +291,39 @@ impl<'lua> ValueRef<'lua> { #[inline] pub(crate) fn to_pointer(&self) -> *const c_void { - unsafe { ffi::lua_topointer(self.lua.ref_thread(), self.index) } - } - - #[cfg(feature = "unstable")] - #[inline] - pub(crate) fn into_owned(self) -> OwnedValueRef { - assert!(self.drop, "Cannot turn non-drop reference into owned"); - let owned_ref = OwnedValueRef::new(self.lua.clone(), self.index); - mem::forget(self); - owned_ref + let lua = self.lua.lock(); + unsafe { ffi::lua_topointer(lua.ref_thread(), self.index) } } } -impl<'lua> fmt::Debug for ValueRef<'lua> { +impl fmt::Debug for ValueRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Ref({:p})", self.to_pointer()) } } -impl<'lua> Clone for ValueRef<'lua> { +impl Clone for ValueRef { fn clone(&self) -> Self { - self.lua.clone_ref(self) + self.lua.lock().clone_ref(self) } } -impl<'lua> Drop for ValueRef<'lua> { +impl Drop for ValueRef { fn drop(&mut self) { if self.drop { - self.lua.drop_ref_index(self.index); + self.lua.lock().drop_ref(self); } } } -impl<'lua> PartialEq for ValueRef<'lua> { +impl PartialEq for ValueRef { fn eq(&self, other: &Self) -> bool { - let ref_thread = self.lua.ref_thread(); assert!( - ref_thread == other.lua.ref_thread(), + self.lua == other.lua, "Lua instance passed Value created from a different main Lua state" ); - unsafe { ffi::lua_rawequal(ref_thread, self.index, other.index) == 1 } - } -} - -#[cfg(feature = "unstable")] -pub(crate) struct OwnedValueRef { - pub(crate) inner: Arc<LuaInner>, - pub(crate) index: c_int, - _non_send: PhantomData<*const ()>, -} - -#[cfg(feature = "unstable")] -impl fmt::Debug for OwnedValueRef { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "OwnedRef({:p})", self.to_ref().to_pointer()) - } -} - -#[cfg(feature = "unstable")] -impl Clone for OwnedValueRef { - fn clone(&self) -> Self { - self.to_ref().clone().into_owned() - } -} - -#[cfg(feature = "unstable")] -impl Drop for OwnedValueRef { - fn drop(&mut self) { - let lua: &Lua = unsafe { mem::transmute(&self.inner) }; - lua.drop_ref_index(self.index); - } -} - -#[cfg(feature = "unstable")] -impl OwnedValueRef { - pub(crate) const fn new(inner: Arc<LuaInner>, index: c_int) -> Self { - OwnedValueRef { - inner, - index, - _non_send: PhantomData, - } - } - - pub(crate) const fn to_ref(&self) -> ValueRef { - ValueRef { - lua: unsafe { mem::transmute(&self.inner) }, - index: self.index, - drop: false, - } + let lua = self.lua.lock(); + unsafe { ffi::lua_rawequal(lua.ref_thread(), self.index, other.index) == 1 } } } @@ -411,7 +356,7 @@ impl AppData { } #[track_caller] - pub(crate) fn borrow<T: 'static>(&self) -> Option<AppDataRef<T>> { + pub(crate) fn borrow<T: 'static>(&self, guard: Option<LuaGuard>) -> Option<AppDataRef<T>> { let data = unsafe { &*self.container.get() } .get(&TypeId::of::<T>())? .borrow(); @@ -419,11 +364,15 @@ impl AppData { Some(AppDataRef { data: Ref::filter_map(data, |data| data.downcast_ref()).ok()?, borrow: &self.borrow, + _guard: guard, }) } #[track_caller] - pub(crate) fn borrow_mut<T: 'static>(&self) -> Option<AppDataRefMut<T>> { + pub(crate) fn borrow_mut<T: 'static>( + &self, + guard: Option<LuaGuard>, + ) -> Option<AppDataRefMut<T>> { let data = unsafe { &*self.container.get() } .get(&TypeId::of::<T>())? .borrow_mut(); @@ -431,6 +380,7 @@ impl AppData { Some(AppDataRefMut { data: RefMut::filter_map(data, |data| data.downcast_mut()).ok()?, borrow: &self.borrow, + _guard: guard, }) } @@ -455,6 +405,7 @@ impl AppData { pub struct AppDataRef<'a, T: ?Sized + 'a> { data: Ref<'a, T>, borrow: &'a Cell<usize>, + _guard: Option<LuaGuard>, } impl<T: ?Sized> Drop for AppDataRef<'_, T> { @@ -490,6 +441,7 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for AppDataRef<'_, T> { pub struct AppDataRefMut<'a, T: ?Sized + 'a> { data: RefMut<'a, T>, borrow: &'a Cell<usize>, + _guard: Option<LuaGuard>, } impl<T: ?Sized> Drop for AppDataRefMut<'_, T> { @@ -526,13 +478,10 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for AppDataRefMut<'_, T> { } } -#[cfg(test)] -mod assertions { - use super::*; - - static_assertions::assert_impl_all!(RegistryKey: Send, Sync); - static_assertions::assert_not_impl_any!(ValueRef: Send); +// #[cfg(test)] +// mod assertions { +// use super::*; - #[cfg(feature = "unstable")] - static_assertions::assert_not_impl_any!(OwnedValueRef: Send); -} +// static_assertions::assert_impl_all!(RegistryKey: Send, Sync); +// static_assertions::assert_not_impl_any!(ValueRef: Send); +// } diff --git a/src/userdata.rs b/src/userdata.rs index 408333b..b21000c 100644 --- a/src/userdata.rs +++ b/src/userdata.rs @@ -1,10 +1,7 @@ -use std::any::{type_name, TypeId}; -use std::cell::{Ref, RefCell, RefMut}; +use std::any::TypeId; use std::ffi::CStr; use std::fmt; use std::hash::Hash; -use std::mem; -use std::ops::{Deref, DerefMut}; use std::os::raw::{c_char, c_int, c_void}; use std::string::String as StdString; @@ -19,10 +16,11 @@ use { use crate::error::{Error, Result}; use crate::function::Function; -use crate::lua::Lua; +use crate::lua::{Lua, LuaGuard}; use crate::string::String; use crate::table::{Table, TablePairs}; use crate::types::{MaybeSend, SubtypeId, ValueRef}; +use crate::userdata_cell::{UserDataRef, UserDataRefMut, UserDataVariant}; use crate::util::{check_stack, get_userdata, take_userdata, StackGuard}; use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Value}; use crate::UserDataRegistry; @@ -254,7 +252,7 @@ impl AsRef<str> for MetaMethod { /// Method registry for [`UserData`] implementors. /// /// [`UserData`]: crate::UserData -pub trait UserDataMethods<'lua, T> { +pub trait UserDataMethods<'a, 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 @@ -262,10 +260,10 @@ pub trait UserDataMethods<'lua, T> { /// /// If `add_meta_method` is used to set the `__index` metamethod, the `__index` metamethod will /// be used as a fall-back if no regular method is found. - fn add_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M) + fn add_method<M, A, R>(&mut self, name: impl ToString, method: M) where - M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + M: Fn(&'a Lua, &T, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti; /// Add a regular method which accepts a `&mut T` as the first parameter. @@ -273,10 +271,10 @@ pub trait UserDataMethods<'lua, T> { /// Refer to [`add_method`] for more information about the implementation. /// /// [`add_method`]: #method.add_method - fn add_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, method: M) + fn add_method_mut<M, A, R>(&mut self, name: impl ToString, method: M) where - M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + M: FnMut(&'a Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti; /// Add an async method which accepts a `&T` as the first parameter and returns Future. @@ -288,13 +286,12 @@ pub trait UserDataMethods<'lua, T> { /// [`add_method`]: #method.add_method #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn add_async_method<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M) + fn add_async_method<M, A, MR, R>(&mut self, name: impl ToString, method: M) where - 'lua: 's, T: 'static, - M: Fn(&'lua Lua, &'s T, A) -> MR + MaybeSend + 'static, - A: FromLuaMulti<'lua>, - MR: Future<Output = Result<R>> + 's, + M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static, + A: FromLuaMulti, + MR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti; /// Add an async method which accepts a `&mut T` as the first parameter and returns Future. @@ -306,13 +303,12 @@ pub trait UserDataMethods<'lua, T> { /// [`add_method`]: #method.add_method #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn add_async_method_mut<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M) + fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl ToString, method: M) where - 'lua: 's, T: 'static, - M: Fn(&'lua Lua, &'s mut T, A) -> MR + MaybeSend + 'static, - A: FromLuaMulti<'lua>, - MR: Future<Output = Result<R>> + 's, + M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static, + A: FromLuaMulti, + MR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti; /// Add a regular method as a function which accepts generic arguments, the first argument will @@ -325,10 +321,10 @@ pub trait UserDataMethods<'lua, T> { /// [`AnyUserData`]: crate::AnyUserData /// [`add_method`]: #method.add_method /// [`add_method_mut`]: #method.add_method_mut - fn add_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F) + fn add_function<F, A, R>(&mut self, name: impl ToString, function: F) where - F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + F: Fn(&'a Lua, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti; /// Add a regular method as a mutable function which accepts generic arguments. @@ -336,10 +332,10 @@ pub trait UserDataMethods<'lua, T> { /// This is a version of [`add_function`] that accepts a FnMut argument. /// /// [`add_function`]: #method.add_function - fn add_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, function: F) + fn add_function_mut<F, A, R>(&mut self, name: impl ToString, function: F) where - F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + F: FnMut(&'a Lua, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti; /// Add a regular method as an async function which accepts generic arguments @@ -352,11 +348,11 @@ pub trait UserDataMethods<'lua, T> { /// [`add_function`]: #method.add_function #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn add_async_function<F, A, FR, R>(&mut self, name: impl AsRef<str>, function: F) + fn add_async_function<F, A, FR, R>(&mut self, name: impl ToString, function: F) where - F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static, - A: FromLuaMulti<'lua>, - FR: Future<Output = Result<R>> + 'lua, + F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static, + A: FromLuaMulti, + FR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti; /// Add a metamethod which accepts a `&T` as the first parameter. @@ -367,10 +363,10 @@ pub trait UserDataMethods<'lua, T> { /// side has a metatable. To prevent this, use [`add_meta_function`]. /// /// [`add_meta_function`]: #method.add_meta_function - fn add_meta_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M) + fn add_meta_method<M, A, R>(&mut self, name: impl ToString, method: M) where - M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + M: Fn(&'a Lua, &T, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti; /// Add a metamethod as a function which accepts a `&mut T` as the first parameter. @@ -381,10 +377,10 @@ pub trait UserDataMethods<'lua, T> { /// side has a metatable. To prevent this, use [`add_meta_function`]. /// /// [`add_meta_function`]: #method.add_meta_function - fn add_meta_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, method: M) + fn add_meta_method_mut<M, A, R>(&mut self, name: impl ToString, method: M) where - M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + M: FnMut(&'a Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti; /// Add an async metamethod which accepts a `&T` as the first parameter and returns Future. @@ -396,13 +392,12 @@ pub trait UserDataMethods<'lua, T> { /// [`add_meta_method`]: #method.add_meta_method #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn add_async_meta_method<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M) + fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl ToString, method: M) where - 'lua: 's, T: 'static, - M: Fn(&'lua Lua, &'s T, A) -> MR + MaybeSend + 'static, - A: FromLuaMulti<'lua>, - MR: Future<Output = Result<R>> + 's, + M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static, + A: FromLuaMulti, + MR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti; /// Add an async metamethod which accepts a `&mut T` as the first parameter and returns Future. @@ -414,13 +409,12 @@ pub trait UserDataMethods<'lua, T> { /// [`add_meta_method_mut`]: #method.add_meta_method_mut #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn add_async_meta_method_mut<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M) + fn add_async_meta_method_mut<M, A, MR, R>(&mut self, name: impl ToString, method: M) where - 'lua: 's, T: 'static, - M: Fn(&'lua Lua, &'s mut T, A) -> MR + MaybeSend + 'static, - A: FromLuaMulti<'lua>, - MR: Future<Output = Result<R>> + 's, + M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static, + A: FromLuaMulti, + MR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti; /// Add a metamethod which accepts generic arguments. @@ -428,10 +422,10 @@ pub trait UserDataMethods<'lua, T> { /// Metamethods for binary operators can be triggered if either the left or right argument to /// the binary operator has a metatable, so the first argument here is not necessarily a /// userdata of type `T`. - fn add_meta_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F) + fn add_meta_function<F, A, R>(&mut self, name: impl ToString, function: F) where - F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + F: Fn(&'a Lua, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti; /// Add a metamethod as a mutable function which accepts generic arguments. @@ -439,10 +433,10 @@ pub trait UserDataMethods<'lua, T> { /// This is a version of [`add_meta_function`] that accepts a FnMut argument. /// /// [`add_meta_function`]: #method.add_meta_function - fn add_meta_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, function: F) + fn add_meta_function_mut<F, A, R>(&mut self, name: impl ToString, function: F) where - F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + F: FnMut(&'a Lua, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti; /// Add a metamethod which accepts generic arguments and returns Future. @@ -454,25 +448,18 @@ pub trait UserDataMethods<'lua, T> { /// [`add_meta_function`]: #method.add_meta_function #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl AsRef<str>, function: F) + fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl ToString, function: F) where - F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static, - A: FromLuaMulti<'lua>, - FR: Future<Output = Result<R>> + 'lua, + F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static, + A: FromLuaMulti, + FR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti; - - // - // Below are internal methods used in generated code - // - - #[doc(hidden)] - fn append_methods_from<S>(&mut self, _other: UserDataRegistry<'lua, S>) {} } /// Field registry for [`UserData`] implementors. /// /// [`UserData`]: crate::UserData -pub trait UserDataFields<'lua, T> { +pub trait UserDataFields<'a, T> { /// Add a static field to the `UserData`. /// /// Static fields are implemented by updating the `__index` metamethod and returning the @@ -482,7 +469,7 @@ pub trait UserDataFields<'lua, T> { /// /// If `add_meta_method` is used to set the `__index` metamethod, it will /// be used as a fall-back if no regular field or method are found. - fn add_field<V>(&mut self, name: impl AsRef<str>, value: V) + fn add_field<V>(&mut self, name: impl ToString, value: V) where V: IntoLua + Clone + 'static; @@ -493,9 +480,9 @@ pub trait UserDataFields<'lua, T> { /// /// If `add_meta_method` is used to set the `__index` metamethod, the `__index` metamethod will /// 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 AsRef<str>, method: M) + fn add_field_method_get<M, R>(&mut self, name: impl ToString, method: M) where - M: Fn(&'lua Lua, &T) -> Result<R> + MaybeSend + 'static, + M: Fn(&'a 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. @@ -505,10 +492,10 @@ pub trait UserDataFields<'lua, T> { /// /// If `add_meta_method` is used to set the `__newindex` metamethod, the `__newindex` metamethod will /// be used as a fall-back if no regular field is found. - fn add_field_method_set<M, A>(&mut self, name: impl AsRef<str>, method: M) + fn add_field_method_set<M, A>(&mut self, name: impl ToString, method: M) where - M: FnMut(&'lua Lua, &mut T, A) -> Result<()> + MaybeSend + 'static, - A: FromLua<'lua>; + M: FnMut(&'a 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` /// argument. @@ -517,9 +504,9 @@ pub trait UserDataFields<'lua, T> { /// /// [`AnyUserData`]: crate::AnyUserData /// [`add_field_method_get`]: #method.add_field_method_get - fn add_field_function_get<F, R>(&mut self, name: impl AsRef<str>, function: F) + fn add_field_function_get<F, R>(&mut self, name: impl ToString, function: F) where - F: Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R> + MaybeSend + 'static, + F: Fn(&'a Lua, AnyUserData) -> Result<R> + MaybeSend + 'static, R: IntoLua; /// Add a regular field setter as a function which accepts a generic [`AnyUserData`] of type `T` @@ -529,10 +516,10 @@ pub trait UserDataFields<'lua, T> { /// /// [`AnyUserData`]: crate::AnyUserData /// [`add_field_method_set`]: #method.add_field_method_set - fn add_field_function_set<F, A>(&mut self, name: impl AsRef<str>, function: F) + fn add_field_function_set<F, A>(&mut self, name: impl ToString, function: F) where - F: FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()> + MaybeSend + 'static, - A: FromLua<'lua>; + F: FnMut(&'a Lua, AnyUserData, A) -> Result<()> + MaybeSend + 'static, + A: FromLua; /// Add a metatable field. /// @@ -542,7 +529,7 @@ pub trait UserDataFields<'lua, T> { /// /// `mlua` will trigger an error on an attempt to define a protected metamethod, /// like `__gc` or `__metatable`. - fn add_meta_field<V>(&mut self, name: impl AsRef<str>, value: V) + fn add_meta_field<V>(&mut self, name: impl ToString, value: V) where V: IntoLua + Clone + 'static; @@ -554,17 +541,10 @@ pub trait UserDataFields<'lua, T> { /// /// `mlua` will trigger an error on an attempt to define a protected metamethod, /// like `__gc` or `__metatable`. - fn add_meta_field_with<F, R>(&mut self, name: impl AsRef<str>, f: F) + fn add_meta_field_with<F, R>(&mut self, name: impl ToString, f: F) where - F: Fn(&'lua Lua) -> Result<R> + MaybeSend + 'static, + F: Fn(&'a Lua) -> Result<R> + MaybeSend + 'static, R: IntoLua; - - // - // Below are internal methods used in generated code - // - - #[doc(hidden)] - fn append_fields_from<S>(&mut self, _other: UserDataRegistry<'lua, S>) {} } /// Trait for custom userdata types. @@ -602,11 +582,11 @@ pub trait UserDataFields<'lua, T> { /// struct MyUserData(i32); /// /// impl UserData for MyUserData { -/// fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { +/// fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) { /// fields.add_field_method_get("val", |_, this| Ok(this.0)); /// } /// -/// fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { +/// fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { /// methods.add_method_mut("add", |_, this, value: i32| { /// this.0 += value; /// Ok(()) @@ -637,140 +617,19 @@ pub trait UserDataFields<'lua, T> { pub trait UserData: Sized { /// Adds custom fields specific to this userdata. #[allow(unused_variables)] - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {} + fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) {} /// Adds custom methods and operators specific to this userdata. #[allow(unused_variables)] - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {} -} - -// Wraps UserData in a way to always implement `serde::Serialize` trait. -pub(crate) struct UserDataCell<T>(RefCell<UserDataVariant<T>>); - -impl<T> UserDataCell<T> { - #[inline] - pub(crate) fn new(data: T) -> Self { - UserDataCell(RefCell::new(UserDataVariant::new(data))) - } - - #[inline] - pub(crate) fn new_ref(data: &T) -> Self { - UserDataCell(RefCell::new(UserDataVariant::new_ref(data))) - } - - #[inline] - pub(crate) fn new_ref_mut(data: &mut T) -> Self { - UserDataCell(RefCell::new(UserDataVariant::new_ref_mut(data))) - } - - #[cfg(feature = "serialize")] - #[inline] - pub(crate) fn new_ser(data: T) -> Self - where - T: Serialize + 'static, - { - UserDataCell(RefCell::new(UserDataVariant::new_ser(data))) - } - - // Immutably borrows the wrapped value. - #[inline] - pub(crate) fn try_borrow(&self) -> Result<Ref<T>> { - self.0 - .try_borrow() - .map(|r| Ref::map(r, |r| r.deref())) - .map_err(|_| Error::UserDataBorrowError) - } - - // Mutably borrows the wrapped value. - #[inline] - pub(crate) fn try_borrow_mut(&self) -> Result<RefMut<T>> { - self.0 - .try_borrow_mut() - .map_err(|_| Error::UserDataBorrowMutError) - .and_then(|r| { - RefMut::filter_map(r, |r| r.try_deref_mut().ok()) - .map_err(|_| Error::UserDataBorrowMutError) - }) - } - - // Consumes this `UserDataCell`, returning the wrapped value. - #[inline] - fn into_inner(self) -> Result<T> { - self.0.into_inner().into_inner() - } -} - -pub(crate) enum UserDataVariant<T> { - Default(Box<T>), - Ref(*const T), - RefMut(*mut T), - #[cfg(feature = "serialize")] - Serializable(Box<dyn erased_serde::Serialize>), -} - -impl<T> UserDataVariant<T> { - #[inline] - fn new(data: T) -> Self { - UserDataVariant::Default(Box::new(data)) - } - - #[inline] - fn new_ref(data: &T) -> Self { - UserDataVariant::Ref(data) - } - - #[inline] - fn new_ref_mut(data: &mut T) -> Self { - UserDataVariant::RefMut(data) - } - - #[cfg(feature = "serialize")] - #[inline] - fn new_ser(data: T) -> Self - where - T: Serialize + 'static, - { - UserDataVariant::Serializable(Box::new(data)) - } - - #[inline] - fn try_deref_mut(&mut self) -> Result<&mut T> { - match self { - Self::Default(data) => Ok(data.deref_mut()), - Self::Ref(_) => Err(Error::UserDataBorrowMutError), - Self::RefMut(data) => unsafe { Ok(&mut **data) }, - #[cfg(feature = "serialize")] - Self::Serializable(data) => unsafe { Ok(&mut *(data.as_mut() as *mut _ as *mut T)) }, - } - } - - #[inline] - fn into_inner(self) -> Result<T> { - match self { - Self::Default(data) => Ok(*data), - Self::Ref(_) | Self::RefMut(_) => Err(Error::UserDataTypeMismatch), - #[cfg(feature = "serialize")] - Self::Serializable(data) => unsafe { - Ok(*Box::from_raw(Box::into_raw(data) as *mut T)) - }, - } - } -} + fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) {} -impl<T> Deref for UserDataVariant<T> { - type Target = T; - - #[inline] - fn deref(&self) -> &Self::Target { - match self { - Self::Default(data) => data, - Self::Ref(data) => unsafe { &**data }, - Self::RefMut(data) => unsafe { &**data }, - #[cfg(feature = "serialize")] - Self::Serializable(data) => unsafe { - &*(data.as_ref() as *const _ as *const Self::Target) - }, - } + /// Registers this type for use in Lua. + /// + /// This method is responsible for calling `add_fields` and `add_methods` on the provided + /// [`UserDataRegistry`]. + fn register(registry: &mut UserDataRegistry<Self>) { + Self::add_fields(registry); + Self::add_methods(registry); } } @@ -791,31 +650,12 @@ impl<T> Deref for UserDataVariant<T> { /// [`is`]: crate::AnyUserData::is /// [`borrow`]: crate::AnyUserData::borrow #[derive(Clone, Debug)] -pub struct AnyUserData<'lua>(pub(crate) ValueRef<'lua>, pub(crate) SubtypeId); +pub struct AnyUserData(pub(crate) ValueRef, pub(crate) SubtypeId); -/// Owned handle to an internal Lua userdata. -/// -/// The owned handle holds a *strong* reference to the current Lua instance. -/// Be warned, if you place it into a Lua type (eg. [`UserData`] or a Rust callback), it is *very easy* -/// to accidentally cause reference cycles that would prevent destroying Lua instance. -#[cfg(feature = "unstable")] -#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] -#[derive(Clone, Debug)] -pub struct OwnedAnyUserData(pub(crate) crate::types::OwnedValueRef, pub(crate) SubtypeId); - -#[cfg(feature = "unstable")] -impl OwnedAnyUserData { - /// Get borrowed handle to the underlying Lua userdata. - #[cfg_attr(feature = "send", allow(unused))] - pub const fn to_ref(&self) -> AnyUserData { - AnyUserData(self.0.to_ref(), self.1) - } -} - -impl<'lua> AnyUserData<'lua> { +impl AnyUserData { /// Checks whether the type of this userdata is `T`. pub fn is<T: 'static>(&self) -> bool { - self.inspect(|_: &UserDataCell<T>| Ok(())).is_ok() + self.inspect::<T, _, _>(|_, _| Ok(())).is_ok() } /// Borrow this userdata immutably if it is of type `T`. @@ -825,8 +665,8 @@ impl<'lua> AnyUserData<'lua> { /// Returns a `UserDataBorrowError` if the userdata is already mutably borrowed. Returns a /// `UserDataTypeMismatch` if the userdata is not of type `T`. #[inline] - pub fn borrow<T: 'static>(&self) -> Result<Ref<T>> { - self.inspect(|cell| cell.try_borrow()) + pub fn borrow<T: 'static>(&self) -> Result<UserDataRef<T>> { + self.inspect(|variant, guard| variant.try_make_ref(guard)) } /// Borrow this userdata mutably if it is of type `T`. @@ -836,8 +676,8 @@ impl<'lua> AnyUserData<'lua> { /// Returns a `UserDataBorrowMutError` if the userdata cannot be mutably borrowed. /// Returns a `UserDataTypeMismatch` if the userdata is not of type `T`. #[inline] - pub fn borrow_mut<T: 'static>(&self) -> Result<RefMut<T>> { - self.inspect(|cell| cell.try_borrow_mut()) + pub fn borrow_mut<T: 'static>(&self) -> Result<UserDataRefMut<T>> { + self.inspect(|variant, guard| variant.try_make_mut_ref(guard)) } /// Takes the value out of this userdata. @@ -845,7 +685,7 @@ impl<'lua> AnyUserData<'lua> { /// /// Keeps associated user values unchanged (they will be collected by Lua's GC). pub fn take<T: 'static>(&self) -> Result<T> { - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -855,8 +695,8 @@ impl<'lua> AnyUserData<'lua> { match type_id { Some(type_id) if type_id == TypeId::of::<T>() => { // Try to borrow userdata exclusively - let _ = (*get_userdata::<UserDataCell<T>>(state, -1)).try_borrow_mut()?; - take_userdata::<UserDataCell<T>>(state).into_inner() + let _ = (*get_userdata::<UserDataVariant<T>>(state, -1)).try_borrow_mut()?; + take_userdata::<UserDataVariant<T>>(state).into_inner() } _ => Err(Error::UserDataTypeMismatch), } @@ -883,13 +723,13 @@ impl<'lua> AnyUserData<'lua> { /// [`set_user_value`]: #method.set_user_value /// [`nth_user_value`]: #method.nth_user_value #[inline] - pub fn user_value<V: FromLua<'lua>>(&self) -> Result<V> { + pub fn user_value<V: FromLua>(&self) -> Result<V> { self.nth_user_value(1) } #[doc(hidden)] #[deprecated(since = "0.9.0", note = "please use `user_value` instead")] - pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> { + pub fn get_user_value<V: FromLua>(&self) -> Result<V> { self.nth_user_value(1) } @@ -908,7 +748,7 @@ impl<'lua> AnyUserData<'lua> { return Err(Error::runtime("user value index out of bounds")); } - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -956,12 +796,12 @@ impl<'lua> AnyUserData<'lua> { /// For other Lua versions this functionality is provided using a wrapping table. /// /// [`set_nth_user_value`]: #method.set_nth_user_value - pub fn nth_user_value<V: FromLua<'lua>>(&self, n: usize) -> Result<V> { + pub fn nth_user_value<V: FromLua>(&self, n: usize) -> Result<V> { if n < 1 || n > u16::MAX as usize { return Err(Error::runtime("user value index out of bounds")); } - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -972,7 +812,7 @@ impl<'lua> AnyUserData<'lua> { #[cfg(feature = "lua54")] if n < USER_VALUE_MAXSLOT { ffi::lua_getiuservalue(state, -1, n as c_int); - return V::from_lua(lua.pop_value(), lua); + return V::from_lua(lua.pop_value(), lua.lua()); } // Multiple (extra) user values are emulated by storing them in a table @@ -987,13 +827,13 @@ impl<'lua> AnyUserData<'lua> { ffi::lua_rawgeti(state, -1, n as ffi::lua_Integer); })?; - V::from_lua(lua.pop_value(), lua) + V::from_lua(lua.pop_value(), lua.lua()) } } #[doc(hidden)] #[deprecated(since = "0.9.0", note = "please use `nth_user_value` instead")] - pub fn get_nth_user_value<V: FromLua<'lua>>(&self, n: usize) -> Result<V> { + pub fn get_nth_user_value<V: FromLua>(&self, n: usize) -> Result<V> { self.nth_user_value(n) } @@ -1003,7 +843,7 @@ impl<'lua> AnyUserData<'lua> { /// /// [`named_user_value`]: #method.named_user_value pub fn set_named_user_value<V: IntoLua>(&self, name: &str, v: V) -> Result<()> { - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -1037,8 +877,8 @@ impl<'lua> AnyUserData<'lua> { /// Returns an associated value by name set by [`set_named_user_value`]. /// /// [`set_named_user_value`]: #method.set_named_user_value - pub fn named_user_value<V: FromLua<'lua>>(&self, name: &str) -> Result<V> { - let lua = self.0.lua; + pub fn named_user_value<V: FromLua>(&self, name: &str) -> Result<V> { + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -1056,13 +896,13 @@ impl<'lua> AnyUserData<'lua> { ffi::lua_rawget(state, -2); })?; - V::from_lua(lua.pop_value(), lua) + V::from_lua(lua.pop_value(), lua.lua()) } } #[doc(hidden)] #[deprecated(since = "0.9.0", note = "please use `named_user_value` instead")] - pub fn get_named_user_value<V: FromLua<'lua>>(&self, name: &str) -> Result<V> { + pub fn get_named_user_value<V: FromLua>(&self, name: &str) -> Result<V> { self.named_user_value(name) } @@ -1075,12 +915,12 @@ impl<'lua> AnyUserData<'lua> { /// /// [`UserDataMetatable`]: crate::UserDataMetatable #[inline] - pub fn get_metatable(&self) -> Result<UserDataMetatable<'lua>> { + pub fn get_metatable(&self) -> Result<UserDataMetatable> { self.get_raw_metatable().map(UserDataMetatable) } - fn get_raw_metatable(&self) -> Result<Table<'lua>> { - let lua = self.0.lua; + fn get_raw_metatable(&self) -> Result<Table> { + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -1102,18 +942,11 @@ impl<'lua> AnyUserData<'lua> { self.0.to_pointer() } - /// Convert this handle to owned version. - #[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] - #[inline] - pub fn into_owned(self) -> OwnedAnyUserData { - OwnedAnyUserData(self.0.into_owned(), self.1) - } - #[cfg(feature = "async")] #[inline] pub(crate) fn type_id(&self) -> Result<Option<TypeId>> { - unsafe { self.0.lua.get_userdata_ref_type_id(&self.0) } + 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). @@ -1126,7 +959,7 @@ impl<'lua> AnyUserData<'lua> { SubtypeId::CData => return Ok(Some("cdata".to_owned())), } - let lua = self.0.lua; + let lua = self.0.lua.lock(); let state = lua.state(); unsafe { let _sg = StackGuard::new(state); @@ -1170,32 +1003,33 @@ impl<'lua> AnyUserData<'lua> { /// Returns `true` if this `AnyUserData` is serializable (eg. was created using `create_ser_userdata`). #[cfg(feature = "serialize")] pub(crate) fn is_serializable(&self) -> bool { - let lua = self.0.lua; + let lua = self.0.lua.lock(); let is_serializable = || unsafe { - // Userdata can be unregistered or destructed + // Userdata must be registered and not destructed let _ = lua.get_userdata_ref_type_id(&self.0)?; - let ud = &*get_userdata::<UserDataCell<()>>(lua.ref_thread(), self.0.index); - match &*ud.0.try_borrow().map_err(|_| Error::UserDataBorrowError)? { - UserDataVariant::Serializable(_) => Result::Ok(true), + let ud = &*get_userdata::<UserDataVariant<()>>(lua.ref_thread(), self.0.index); + match ud { + UserDataVariant::Serializable(..) => Result::Ok(true), _ => Result::Ok(false), } }; is_serializable().unwrap_or(false) } - fn inspect<'a, T, F, R>(&'a self, func: F) -> Result<R> + pub(crate) fn inspect<'a, T, F, R>(&'a self, func: F) -> Result<R> where T: 'static, - F: FnOnce(&'a UserDataCell<T>) -> Result<R>, + F: FnOnce(&'a UserDataVariant<T>, LuaGuard) -> Result<R>, { - let lua = self.0.lua; + let lua = self.0.lua.lock(); unsafe { let type_id = lua.get_userdata_ref_type_id(&self.0)?; match type_id { Some(type_id) if type_id == TypeId::of::<T>() => { let ref_thread = lua.ref_thread(); - func(&*get_userdata::<UserDataCell<T>>(ref_thread, self.0.index)) + let ud = get_userdata::<UserDataVariant<T>>(ref_thread, self.0.index); + func(&*ud, lua) } _ => Err(Error::UserDataTypeMismatch), } @@ -1203,13 +1037,13 @@ impl<'lua> AnyUserData<'lua> { } } -impl<'lua> PartialEq for AnyUserData<'lua> { +impl PartialEq for AnyUserData { fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } -impl<'lua> AsRef<AnyUserData<'lua>> for AnyUserData<'lua> { +impl AsRef<AnyUserData> for AnyUserData { #[inline] fn as_ref(&self) -> &Self { self @@ -1223,50 +1057,16 @@ unsafe fn getuservalue_table(state: *mut ffi::lua_State, idx: c_int) -> c_int { return ffi::lua_getuservalue(state, idx); } -// Additional shortcuts -#[cfg(feature = "unstable")] -impl OwnedAnyUserData { - /// Borrow this userdata immutably if it is of type `T`. - /// - /// This is a shortcut for [`AnyUserData::borrow()`] - #[inline] - pub fn borrow<T: 'static>(&self) -> Result<Ref<T>> { - let ud = self.to_ref(); - let t = ud.borrow::<T>()?; - // Reattach lifetime to &self - Ok(unsafe { mem::transmute::<Ref<T>, Ref<T>>(t) }) - } - - /// Borrow this userdata mutably if it is of type `T`. - /// - /// This is a shortcut for [`AnyUserData::borrow_mut()`] - #[inline] - pub fn borrow_mut<T: 'static>(&self) -> Result<RefMut<T>> { - let ud = self.to_ref(); - let t = ud.borrow_mut::<T>()?; - // Reattach lifetime to &self - Ok(unsafe { mem::transmute::<RefMut<T>, RefMut<T>>(t) }) - } - - /// Takes the value out of this userdata. - /// - /// This is a shortcut for [`AnyUserData::take()`] - #[inline] - pub fn take<T: 'static>(&self) -> Result<T> { - self.to_ref().take() - } -} - /// Handle to a `UserData` metatable. #[derive(Clone, Debug)] -pub struct UserDataMetatable<'lua>(pub(crate) Table<'lua>); +pub struct UserDataMetatable(pub(crate) Table); -impl<'lua> UserDataMetatable<'lua> { +impl UserDataMetatable { /// Gets the value associated to `key` from the metatable. /// /// If no value is associated to `key`, returns the `Nil` value. /// Access to restricted metamethods such as `__gc` or `__metatable` will cause an error. - pub fn get<V: FromLua<'lua>>(&self, key: impl AsRef<str>) -> Result<V> { + pub fn get<V: FromLua>(&self, key: impl AsRef<str>) -> Result<V> { self.0.raw_get(MetaMethod::validate(key.as_ref())?) } @@ -1295,7 +1095,7 @@ impl<'lua> UserDataMetatable<'lua> { /// The pairs are wrapped in a [`Result`], since they are lazily converted to `V` type. /// /// [`Result`]: crate::Result - pub fn pairs<V: FromLua<'lua>>(self) -> UserDataMetatablePairs<'lua, V> { + pub fn pairs<V: FromLua>(self) -> UserDataMetatablePairs<V> { UserDataMetatablePairs(self.0.pairs()) } } @@ -1308,11 +1108,11 @@ impl<'lua> UserDataMetatable<'lua> { /// /// [`UserData`]: crate::UserData /// [`UserDataMetatable::pairs`]: crate::UserDataMetatable::method.pairs -pub struct UserDataMetatablePairs<'lua, V>(TablePairs<'lua, StdString, V>); +pub struct UserDataMetatablePairs<V>(TablePairs<StdString, V>); -impl<'lua, V> Iterator for UserDataMetatablePairs<'lua, V> +impl<V> Iterator for UserDataMetatablePairs<V> where - V: FromLua<'lua>, + V: FromLua, { type Item = Result<(StdString, V)>; @@ -1332,12 +1132,12 @@ where } #[cfg(feature = "serialize")] -impl<'lua> Serialize for AnyUserData<'lua> { +impl Serialize for AnyUserData { fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error> where S: Serializer, { - let lua = self.0.lua; + let lua = self.0.lua.lock(); // Special case for Luau buffer type #[cfg(feature = "luau")] @@ -1351,74 +1151,19 @@ impl<'lua> Serialize for AnyUserData<'lua> { return serializer.serialize_bytes(buf); } - let data = unsafe { + unsafe { let _ = lua .get_userdata_ref_type_id(&self.0) .map_err(ser::Error::custom)?; - let ud = &*get_userdata::<UserDataCell<()>>(lua.ref_thread(), self.0.index); - ud.0.try_borrow() - .map_err(|_| ser::Error::custom(Error::UserDataBorrowError))? - }; - match &*data { - UserDataVariant::Serializable(ser) => ser.serialize(serializer), - _ => Err(ser::Error::custom("cannot serialize <userdata>")), + let ud = &*get_userdata::<UserDataVariant<()>>(lua.ref_thread(), self.0.index); + ud.serialize(serializer) } } } -/// A wrapper type for an immutably borrowed value from a `AnyUserData`. -/// -/// It implements [`FromLua`] and can be used to receive a typed userdata from Lua. -pub struct UserDataRef<'lua, T: 'static>(#[allow(unused)] AnyUserData<'lua>, Ref<'lua, T>); - -impl<'lua, T: 'static> Deref for UserDataRef<'lua, T> { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.1 - } -} - -impl<'lua, T: 'static> UserDataRef<'lua, T> { - pub(crate) fn from_value(value: Value<'lua>) -> Result<Self> { - let ud = try_value_to_userdata::<T>(value)?; - // It's safe to lift lifetime of `Ref<T>` to `'lua` as long as we hold AnyUserData to it. - let this = unsafe { mem::transmute(ud.borrow::<T>()?) }; - Ok(UserDataRef(ud, this)) - } -} - -/// 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<'lua, T: 'static>(#[allow(unused)] AnyUserData<'lua>, RefMut<'lua, T>); - -impl<'lua, T: 'static> Deref for UserDataRefMut<'lua, T> { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.1 - } -} - -impl<'lua, T: 'static> DerefMut for UserDataRefMut<'lua, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.1 - } -} +pub(crate) struct WrappedUserdata<F: FnOnce(&Lua) -> Result<AnyUserData>>(F); -impl<'lua, T: 'static> UserDataRefMut<'lua, T> { - pub(crate) fn from_value(value: Value<'lua>) -> Result<Self> { - let ud = try_value_to_userdata::<T>(value)?; - // It's safe to lift lifetime of `RefMut<T>` to `'lua` as long as we hold AnyUserData to it. - let this = unsafe { mem::transmute(ud.borrow_mut::<T>()?) }; - Ok(UserDataRefMut(ud, this)) - } -} - -pub(crate) struct WrappedUserdata<F: for<'lua> FnOnce(&'lua Lua) -> Result<AnyUserData<'lua>>>(F); - -impl<'lua> AnyUserData<'lua> { +impl AnyUserData { /// Wraps any Rust type, returning an opaque type that implements [`IntoLua`] trait. /// /// This function uses [`Lua::create_any_userdata()`] under the hood. @@ -1429,31 +1174,16 @@ impl<'lua> AnyUserData<'lua> { impl<F> IntoLua for WrappedUserdata<F> where - F: for<'l> FnOnce(&'l Lua) -> Result<AnyUserData<'l>>, + F: for<'l> FnOnce(&'l Lua) -> Result<AnyUserData>, { - fn into_lua(self, lua: &Lua) -> Result<Value<'_>> { + fn into_lua(self, lua: &Lua) -> Result<Value> { (self.0)(lua).map(Value::UserData) } } -#[inline] -fn try_value_to_userdata<T>(value: Value) -> Result<AnyUserData> { - match value { - Value::UserData(ud) => Ok(ud), - _ => Err(Error::FromLuaConversionError { - from: value.type_name(), - to: "userdata", - message: Some(format!("expected userdata of type {}", type_name::<T>())), - }), - } -} +// #[cfg(test)] +// mod assertions { +// use super::*; -#[cfg(test)] -mod assertions { - use super::*; - - static_assertions::assert_not_impl_any!(AnyUserData: Send); - - #[cfg(all(feature = "unstable", not(feature = "send")))] - static_assertions::assert_not_impl_any!(OwnedAnyUserData: Send); -} +// static_assertions::assert_not_impl_any!(AnyUserData: Send); +// } diff --git a/src/userdata_cell.rs b/src/userdata_cell.rs new file mode 100644 index 0000000..59b4503 --- /dev/null +++ b/src/userdata_cell.rs @@ -0,0 +1,410 @@ +use std::any::{type_name, TypeId}; +use std::cell::{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::lua::{Lua, LuaGuard, LuaInner}; +use crate::userdata::AnyUserData; +use crate::util::get_userdata; +use crate::value::{FromLua, Value}; + +// 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>>), + #[cfg(feature = "serialize")] + Serializable(Rc<InnerRefCell<Box<dyn erased_serde::Serialize>>>), +} + +impl<T> Clone for UserDataVariant<T> { + #[inline] + fn clone(&self) -> Self { + match self { + Self::Default(inner) => Self::Default(Rc::clone(inner)), + #[cfg(feature = "serialize")] + Self::Serializable(inner) => UserDataVariant::Serializable(Rc::clone(inner)), + } + } +} + +impl<T> UserDataVariant<T> { + #[inline(always)] + pub(crate) fn new(data: T) -> Self { + Self::Default(Rc::new(InnerRefCell::new(data))) + } + + // Immutably borrows the wrapped value in-place. + #[inline(always)] + pub(crate) unsafe 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) + } + + // Mutably borrows the wrapped value in-place. + #[inline(always)] + pub(crate) unsafe 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) + } + + // 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())?; + Ok(match self { + Self::Default(inner) => Rc::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()); + *Box::from_raw(raw as *mut T) + }, + }) + } + + #[inline(always)] + fn flag(&self) -> &Cell<BorrowFlag> { + match self { + Self::Default(inner) => &inner.borrow, + #[cfg(feature = "serialize")] + Self::Serializable(inner) => &inner.borrow, + } + } + + #[inline(always)] + unsafe fn get_ref(&self) -> &T { + match self { + Self::Default(inner) => &*inner.value.get(), + #[cfg(feature = "serialize")] + Self::Serializable(inner) => &*(inner.value.get() as *mut Box<T>), + } + } + + #[inline(always)] + unsafe fn get_mut(&self) -> &mut T { + match self { + Self::Default(inner) => &mut *inner.value.get(), + #[cfg(feature = "serialize")] + Self::Serializable(inner) => &mut *(inner.value.get() as *mut Box<T>), + } + } +} + +#[cfg(feature = "serialize")] +impl<T: Serialize + '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))) + } +} + +#[cfg(feature = "serialize")] +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) + }, + } + } +} + +// +// Inspired by `std::cell::RefCell`` implementation +// + +pub(crate) struct InnerRefCell<T> { + borrow: Cell<BorrowFlag>, + value: UnsafeCell<T>, +} + +impl<T> InnerRefCell<T> { + #[inline(always)] + pub fn new(value: T) -> Self { + InnerRefCell { + borrow: Cell::new(UNUSED), + value: UnsafeCell::new(value), + } + } +} + +/// 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, +} + +impl<T> Deref for UserDataRef<T> { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + unsafe { self.variant.get_ref() } + } +} + +impl<T> Drop for UserDataRef<T> { + #[inline] + fn drop(&mut self) { + unset_reading(self.variant.flag()); + } +} + +impl<T: fmt::Debug> fmt::Debug for UserDataRef<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +impl<T: fmt::Display> fmt::Display for UserDataRef<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +impl<T> UserDataRef<T> { + #[inline] + fn try_from(variant: UserDataVariant<T>, guard: LuaGuard) -> Result<Self> { + set_reading(variant.flag())?; + Ok(UserDataRef { variant, guard }) + } +} + +impl<T: 'static> FromLua for UserDataRef<T> { + fn from_lua(value: Value, _: &Lua) -> Result<Self> { + try_value_to_userdata::<T>(value)?.borrow() + } + + unsafe fn from_stack(idx: c_int, lua: &LuaInner) -> Result<Self> { + let type_id = lua.get_userdata_type_id(idx)?; + match type_id { + Some(type_id) if type_id == TypeId::of::<T>() => lua.get_userdata_ref(idx), + _ => Err(Error::UserDataTypeMismatch), + } + } +} + +/// 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, +} + +impl<T> Deref for UserDataRefMut<T> { + type Target = T; + + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { self.variant.get_ref() } + } +} + +impl<T> DerefMut for UserDataRefMut<T> { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { self.variant.get_mut() } + } +} + +impl<T> Drop for UserDataRefMut<T> { + #[inline] + fn drop(&mut self) { + unset_writing(self.variant.flag()); + } +} + +impl<T: fmt::Debug> fmt::Debug for UserDataRefMut<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +impl<T: fmt::Display> fmt::Display for UserDataRefMut<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +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: 'static> FromLua for UserDataRefMut<T> { + fn from_lua(value: Value, _: &Lua) -> Result<Self> { + try_value_to_userdata::<T>(value)?.borrow_mut() + } + + unsafe fn from_stack(idx: c_int, lua: &LuaInner) -> Result<Self> { + 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) + } + _ => 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); +} + +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()); + } +} + +impl<'a, T> Deref for UserDataBorrowRef<'a, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + unsafe { self.0.get_ref() } + } +} + +impl<'a, T> UserDataBorrowRef<'a, T> { + #[inline(always)] + pub(crate) fn try_from(variant: &'a UserDataVariant<T>) -> Result<Self> { + set_reading(variant.flag())?; + Ok(UserDataBorrowRef(&variant)) + } +} + +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()); + } +} + +impl<'a, T> Deref for UserDataBorrowMut<'a, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + unsafe { self.0.get_ref() } + } +} + +impl<'a, T> DerefMut for UserDataBorrowMut<'a, T> { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { self.0.get_mut() } + } +} + +impl<'a, T> UserDataBorrowMut<'a, T> { + #[inline(always)] + pub(crate) fn try_from(variant: &'a UserDataVariant<T>) -> Result<Self> { + set_writing(variant.flag())?; + Ok(UserDataBorrowMut(&variant)) + } +} + +#[inline] +fn try_value_to_userdata<T>(value: Value) -> Result<AnyUserData> { + match value { + Value::UserData(ud) => Ok(ud), + _ => Err(Error::FromLuaConversionError { + from: value.type_name(), + to: "userdata", + message: Some(format!("expected userdata of type {}", type_name::<T>())), + }), + } +} + +#[cfg(test)] +mod assertions { + use super::*; + + static_assertions::assert_not_impl_all!(UserDataRef<()>: Sync, Send); + static_assertions::assert_not_impl_all!(UserDataRefMut<()>: Sync, Send); +} diff --git a/src/userdata_ext.rs b/src/userdata_ext.rs index 268324d..0863d9b 100644 --- a/src/userdata_ext.rs +++ b/src/userdata_ext.rs @@ -7,9 +7,9 @@ use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Value}; use futures_util::future::{self, LocalBoxFuture}; /// An extension trait for [`AnyUserData`] that provides a variety of convenient functionality. -pub trait AnyUserDataExt<'lua>: Sealed { +pub trait AnyUserDataExt: Sealed { /// Gets the value associated to `key` from the userdata, assuming it has `__index` metamethod. - fn get<K: IntoLua, V: FromLua<'lua>>(&self, key: K) -> Result<V>; + fn get<K: IntoLua, V: FromLua>(&self, key: K) -> Result<V>; /// Sets the value associated to `key` in the userdata, assuming it has `__newindex` metamethod. fn set<K: IntoLua, V: IntoLua>(&self, key: K, value: V) -> Result<()>; @@ -20,24 +20,24 @@ pub trait AnyUserDataExt<'lua>: Sealed { fn call<A, R>(&self, args: A) -> Result<R> where A: IntoLuaMulti, - R: FromLuaMulti<'lua>; + R: FromLuaMulti; /// Asynchronously calls the userdata as a function assuming it has `__call` metamethod. /// /// The metamethod is called with the userdata as its first argument, followed by the passed arguments. #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn call_async<A, R>(&self, args: A) -> LocalBoxFuture<'lua, Result<R>> + fn call_async<A, R>(&self, args: A) -> LocalBoxFuture<'static, Result<R>> where A: IntoLuaMulti, - R: FromLuaMulti<'lua> + 'lua; + R: FromLuaMulti + 'static; /// Calls the userdata method, assuming it has `__index` metamethod /// and a function associated to `name`. fn call_method<A, R>(&self, name: &str, args: A) -> Result<R> where A: IntoLuaMulti, - R: FromLuaMulti<'lua>; + R: FromLuaMulti; /// Gets the function associated to `key` from the table and asynchronously executes it, /// passing the table itself along with `args` as function arguments and returning Future. @@ -47,10 +47,10 @@ pub trait AnyUserDataExt<'lua>: Sealed { /// This might invoke the `__index` metamethod. #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn call_async_method<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'lua, Result<R>> + fn call_async_method<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'static, Result<R>> where A: IntoLuaMulti, - R: FromLuaMulti<'lua> + 'lua; + R: FromLuaMulti + 'static; /// Gets the function associated to `key` from the table and executes it, /// passing `args` as function arguments. @@ -62,7 +62,7 @@ pub trait AnyUserDataExt<'lua>: Sealed { fn call_function<A, R>(&self, name: &str, args: A) -> Result<R> where A: IntoLuaMulti, - R: FromLuaMulti<'lua>; + R: FromLuaMulti; /// Gets the function associated to `key` from the table and asynchronously executes it, /// passing `args` as function arguments and returning Future. @@ -72,14 +72,14 @@ pub trait AnyUserDataExt<'lua>: Sealed { /// This might invoke the `__index` metamethod. #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn call_async_function<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'lua, Result<R>> + fn call_async_function<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'static, Result<R>> where A: IntoLuaMulti, - R: FromLuaMulti<'lua> + 'lua; + R: FromLuaMulti + 'static; } -impl<'lua> AnyUserDataExt<'lua> for AnyUserData<'lua> { - fn get<K: IntoLua, V: FromLua<'lua>>(&self, key: K) -> Result<V> { +impl AnyUserDataExt for AnyUserData { + fn get<K: IntoLua, V: FromLua>(&self, key: K) -> Result<V> { let metatable = self.get_metatable()?; match metatable.get::<Value>(MetaMethod::Index)? { Value::Table(table) => table.raw_get(key), @@ -100,7 +100,7 @@ impl<'lua> AnyUserDataExt<'lua> for AnyUserData<'lua> { fn call<A, R>(&self, args: A) -> Result<R> where A: IntoLuaMulti, - R: FromLuaMulti<'lua>, + R: FromLuaMulti, { let metatable = self.get_metatable()?; match metatable.get::<Value>(MetaMethod::Call)? { @@ -110,10 +110,10 @@ impl<'lua> AnyUserDataExt<'lua> for AnyUserData<'lua> { } #[cfg(feature = "async")] - fn call_async<A, R>(&self, args: A) -> LocalBoxFuture<'lua, Result<R>> + fn call_async<A, R>(&self, args: A) -> LocalBoxFuture<'static, Result<R>> where A: IntoLuaMulti, - R: FromLuaMulti<'lua> + 'lua, + R: FromLuaMulti + 'static, { let metatable = match self.get_metatable() { Ok(metatable) => metatable, @@ -121,7 +121,8 @@ impl<'lua> AnyUserDataExt<'lua> for AnyUserData<'lua> { }; match metatable.get::<Value>(MetaMethod::Call) { Ok(Value::Function(func)) => { - let args = match (self, args).into_lua_multi(self.0.lua) { + let lua = self.0.lua.lock(); + let args = match (self, args).into_lua_multi(lua.lua()) { Ok(args) => args, Err(e) => return Box::pin(future::err(e)), }; @@ -137,16 +138,16 @@ impl<'lua> AnyUserDataExt<'lua> for AnyUserData<'lua> { fn call_method<A, R>(&self, name: &str, args: A) -> Result<R> where A: IntoLuaMulti, - R: FromLuaMulti<'lua>, + R: FromLuaMulti, { self.call_function(name, (self, args)) } #[cfg(feature = "async")] - fn call_async_method<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'lua, Result<R>> + fn call_async_method<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'static, Result<R>> where A: IntoLuaMulti, - R: FromLuaMulti<'lua> + 'lua, + R: FromLuaMulti + 'static, { self.call_async_function(name, (self, args)) } @@ -154,7 +155,7 @@ impl<'lua> AnyUserDataExt<'lua> for AnyUserData<'lua> { fn call_function<A, R>(&self, name: &str, args: A) -> Result<R> where A: IntoLuaMulti, - R: FromLuaMulti<'lua>, + R: FromLuaMulti, { match self.get(name)? { Value::Function(func) => func.call(args), @@ -166,14 +167,15 @@ impl<'lua> AnyUserDataExt<'lua> for AnyUserData<'lua> { } #[cfg(feature = "async")] - fn call_async_function<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'lua, Result<R>> + fn call_async_function<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'static, Result<R>> where A: IntoLuaMulti, - R: FromLuaMulti<'lua> + 'lua, + R: FromLuaMulti + 'static, { match self.get(name) { Ok(Value::Function(func)) => { - let args = match args.into_lua_multi(self.0.lua) { + let lua = self.0.lua.lock(); + let args = match args.into_lua_multi(lua.lua()) { Ok(args) => args, Err(e) => return Box::pin(future::err(e)), }; diff --git a/src/userdata_impl.rs b/src/userdata_impl.rs index b3acd48..b552778 100644 --- a/src/userdata_impl.rs +++ b/src/userdata_impl.rs @@ -1,7 +1,7 @@ #![allow(clippy::await_holding_refcell_ref, clippy::await_holding_lock)] use std::any::TypeId; -use std::cell::{Ref, RefCell, RefMut}; +use std::cell::RefCell; use std::marker::PhantomData; use std::os::raw::c_int; use std::string::String as StdString; @@ -10,9 +10,8 @@ use std::sync::{Arc, Mutex, RwLock}; use crate::error::{Error, Result}; use crate::lua::Lua; use crate::types::{Callback, MaybeSend}; -use crate::userdata::{ - AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods, -}; +use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataFields, UserDataMethods}; +use crate::userdata_cell::{UserDataBorrowMut, UserDataBorrowRef, UserDataVariant}; use crate::util::{get_userdata, short_type_name}; use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Value}; @@ -23,25 +22,25 @@ use std::rc::Rc; use {crate::types::AsyncCallback, futures_util::future, std::future::Future}; /// Handle to registry for userdata methods and metamethods. -pub struct UserDataRegistry<'lua, T: 'static> { +pub struct UserDataRegistry<'a, T: 'static> { // Fields - pub(crate) fields: Vec<(String, Callback<'lua, 'static>)>, - pub(crate) field_getters: Vec<(String, Callback<'lua, 'static>)>, - pub(crate) field_setters: Vec<(String, Callback<'lua, 'static>)>, - pub(crate) meta_fields: Vec<(String, Callback<'lua, 'static>)>, + 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>)>, // Methods - pub(crate) methods: Vec<(String, Callback<'lua, 'static>)>, + pub(crate) methods: Vec<(String, Callback<'a>)>, #[cfg(feature = "async")] - pub(crate) async_methods: Vec<(String, AsyncCallback<'lua, 'static>)>, - pub(crate) meta_methods: Vec<(String, Callback<'lua, 'static>)>, + pub(crate) async_methods: Vec<(String, AsyncCallback<'a>)>, + pub(crate) meta_methods: Vec<(String, Callback<'a>)>, #[cfg(feature = "async")] - pub(crate) async_meta_methods: Vec<(String, AsyncCallback<'lua, 'static>)>, + pub(crate) async_meta_methods: Vec<(String, AsyncCallback<'a>)>, _type: PhantomData<T>, } -impl<'lua, T: 'static> UserDataRegistry<'lua, T> { +impl<'a, T: 'static> UserDataRegistry<'a, T> { pub(crate) const fn new() -> Self { UserDataRegistry { fields: Vec::new(), @@ -58,10 +57,10 @@ impl<'lua, T: 'static> UserDataRegistry<'lua, T> { } } - fn box_method<M, A, R>(name: &str, method: M) -> Callback<'lua, 'static> + fn box_method<M, A, R>(name: &str, method: M) -> Callback<'a> where - M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + M: Fn(&'a Lua, &T, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti, { let name = get_function_name::<T>(name); @@ -87,57 +86,57 @@ impl<'lua, T: 'static> UserDataRegistry<'lua, T> { match try_self_arg!(lua.get_userdata_type_id(index)) { Some(id) if id == TypeId::of::<T>() => { - let ud = try_self_arg!(get_userdata_ref::<T>(state, index)); - method(lua, &ud, args?)?.push_into_stack_multi(lua) - } - #[cfg(not(feature = "send"))] - Some(id) if id == TypeId::of::<Rc<T>>() => { - let ud = try_self_arg!(get_userdata_ref::<Rc<T>>(state, index)); - method(lua, &ud, args?)?.push_into_stack_multi(lua) - } - #[cfg(not(feature = "send"))] - Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => { - let ud = try_self_arg!(get_userdata_ref::<Rc<RefCell<T>>>(state, index)); - let ud = try_self_arg!(ud.try_borrow(), Error::UserDataBorrowError); - method(lua, &ud, args?)?.push_into_stack_multi(lua) - } - Some(id) if id == TypeId::of::<Arc<T>>() => { - let ud = try_self_arg!(get_userdata_ref::<Arc<T>>(state, index)); - method(lua, &ud, args?)?.push_into_stack_multi(lua) - } - Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => { - let ud = try_self_arg!(get_userdata_ref::<Arc<Mutex<T>>>(state, index)); - let ud = try_self_arg!(ud.try_lock(), Error::UserDataBorrowError); - method(lua, &ud, args?)?.push_into_stack_multi(lua) - } - #[cfg(feature = "parking_lot")] - Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => { - let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(state, index); - let ud = try_self_arg!(ud); - let ud = try_self_arg!(ud.try_lock().ok_or(Error::UserDataBorrowError)); - method(lua, &ud, args?)?.push_into_stack_multi(lua) - } - Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => { - let ud = try_self_arg!(get_userdata_ref::<Arc<RwLock<T>>>(state, index)); - let ud = try_self_arg!(ud.try_read(), Error::UserDataBorrowError); - method(lua, &ud, args?)?.push_into_stack_multi(lua) - } - #[cfg(feature = "parking_lot")] - Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => { - let ud = get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(state, index); - let ud = try_self_arg!(ud); - let ud = try_self_arg!(ud.try_read().ok_or(Error::UserDataBorrowError)); - method(lua, &ud, args?)?.push_into_stack_multi(lua) + let ud = try_self_arg!(borrow_userdata_ref::<T>(state, index)); + method(lua.lua(), &ud, args?)?.push_into_stack_multi(lua) } + // #[cfg(not(feature = "send"))] + // Some(id) if id == TypeId::of::<Rc<T>>() => { + // let ud = try_self_arg!(get_userdata_ref::<Rc<T>>(state, index)); + // method(lua.lua(), ud, args?)?.push_into_stack_multi(lua) + // } + // #[cfg(not(feature = "send"))] + // Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => { + // let ud = try_self_arg!(get_userdata_ref::<Rc<RefCell<T>>>(state, index)); + // let ud = try_self_arg!(ud.try_borrow(), Error::UserDataBorrowError); + // method(lua.lua(), &ud, args?)?.push_into_stack_multi(lua) + // } + // Some(id) if id == TypeId::of::<Arc<T>>() => { + // let ud = try_self_arg!(get_userdata_ref::<Arc<T>>(state, index)); + // method(lua.lua(), &ud, args?)?.push_into_stack_multi(lua) + // } + // Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => { + // let ud = try_self_arg!(get_userdata_ref::<Arc<Mutex<T>>>(state, index)); + // let ud = try_self_arg!(ud.try_lock(), Error::UserDataBorrowError); + // method(lua.lua(), &ud, args?)?.push_into_stack_multi(lua) + // } + // #[cfg(feature = "parking_lot")] + // Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => { + // let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(state, index); + // let ud = try_self_arg!(ud); + // let ud = try_self_arg!(ud.try_lock().ok_or(Error::UserDataBorrowError)); + // method(lua.lua(), &ud, args?)?.push_into_stack_multi(lua) + // } + // Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => { + // let ud = try_self_arg!(get_userdata_ref::<Arc<RwLock<T>>>(state, index)); + // let ud = try_self_arg!(ud.try_read(), Error::UserDataBorrowError); + // method(lua.lua(), &ud, args?)?.push_into_stack_multi(lua) + // } + // #[cfg(feature = "parking_lot")] + // Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => { + // let ud = get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(state, index); + // let ud = try_self_arg!(ud); + // let ud = try_self_arg!(ud.try_read().ok_or(Error::UserDataBorrowError)); + // method(lua.lua(), &ud, args?)?.push_into_stack_multi(lua) + // } _ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)), } }) } - fn box_method_mut<M, A, R>(name: &str, method: M) -> Callback<'lua, 'static> + fn box_method_mut<M, A, R>(name: &str, method: M) -> Callback<'a> where - M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + M: FnMut(&'a Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti, { let name = get_function_name::<T>(name); @@ -167,61 +166,59 @@ impl<'lua, T: 'static> UserDataRegistry<'lua, T> { match try_self_arg!(lua.get_userdata_type_id(index)) { Some(id) if id == TypeId::of::<T>() => { - let mut ud = try_self_arg!(get_userdata_mut::<T>(state, index)); - method(lua, &mut ud, args?)?.push_into_stack_multi(lua) - } - #[cfg(not(feature = "send"))] - Some(id) if id == TypeId::of::<Rc<T>>() => Err(Error::UserDataBorrowMutError), - #[cfg(not(feature = "send"))] - Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => { - let ud = try_self_arg!(get_userdata_mut::<Rc<RefCell<T>>>(state, index)); - let mut ud = try_self_arg!(ud.try_borrow_mut(), Error::UserDataBorrowMutError); - method(lua, &mut ud, args?)?.push_into_stack_multi(lua) - } - Some(id) if id == TypeId::of::<Arc<T>>() => Err(Error::UserDataBorrowMutError), - Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => { - let ud = try_self_arg!(get_userdata_mut::<Arc<Mutex<T>>>(state, index)); - let mut ud = try_self_arg!(ud.try_lock(), Error::UserDataBorrowMutError); - method(lua, &mut ud, args?)?.push_into_stack_multi(lua) - } - #[cfg(feature = "parking_lot")] - Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => { - let ud = get_userdata_mut::<Arc<parking_lot::Mutex<T>>>(state, index); - let ud = try_self_arg!(ud); - let mut ud = try_self_arg!(ud.try_lock().ok_or(Error::UserDataBorrowMutError)); - method(lua, &mut ud, args?)?.push_into_stack_multi(lua) - } - Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => { - let ud = try_self_arg!(get_userdata_mut::<Arc<RwLock<T>>>(state, index)); - let mut ud = try_self_arg!(ud.try_write(), Error::UserDataBorrowMutError); - method(lua, &mut ud, args?)?.push_into_stack_multi(lua) - } - #[cfg(feature = "parking_lot")] - Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => { - let ud = get_userdata_mut::<Arc<parking_lot::RwLock<T>>>(state, index); - let ud = try_self_arg!(ud); - let mut ud = try_self_arg!(ud.try_write().ok_or(Error::UserDataBorrowMutError)); - method(lua, &mut ud, args?)?.push_into_stack_multi(lua) + let mut ud = try_self_arg!(borrow_userdata_mut::<T>(state, index)); + method(lua.lua(), &mut ud, args?)?.push_into_stack_multi(lua) } + // #[cfg(not(feature = "send"))] + // Some(id) if id == TypeId::of::<Rc<T>>() => Err(Error::UserDataBorrowMutError), + // #[cfg(not(feature = "send"))] + // Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => { + // let ud = try_self_arg!(get_userdata_mut::<Rc<RefCell<T>>>(state, index)); + // let mut ud = try_self_arg!(ud.try_borrow_mut(), Error::UserDataBorrowMutError); + // method(lua.lua(), &mut ud, args?)?.push_into_stack_multi(lua) + // } + // Some(id) if id == TypeId::of::<Arc<T>>() => Err(Error::UserDataBorrowMutError), + // Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => { + // let ud = try_self_arg!(get_userdata_mut::<Arc<Mutex<T>>>(state, index)); + // let mut ud = try_self_arg!(ud.try_lock(), Error::UserDataBorrowMutError); + // method(lua.lua(), &mut ud, args?)?.push_into_stack_multi(lua) + // } + // #[cfg(feature = "parking_lot")] + // Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => { + // let ud = get_userdata_mut::<Arc<parking_lot::Mutex<T>>>(state, index); + // let ud = try_self_arg!(ud); + // let mut ud = try_self_arg!(ud.try_lock().ok_or(Error::UserDataBorrowMutError)); + // method(lua.lua(), &mut ud, args?)?.push_into_stack_multi(lua) + // } + // Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => { + // let ud = try_self_arg!(get_userdata_mut::<Arc<RwLock<T>>>(state, index)); + // let mut ud = try_self_arg!(ud.try_write(), Error::UserDataBorrowMutError); + // method(lua.lua(), &mut ud, args?)?.push_into_stack_multi(lua) + // } + // #[cfg(feature = "parking_lot")] + // Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => { + // let ud = get_userdata_mut::<Arc<parking_lot::RwLock<T>>>(state, index); + // let ud = try_self_arg!(ud); + // let mut ud = try_self_arg!(ud.try_write().ok_or(Error::UserDataBorrowMutError)); + // method(lua.lua(), &mut ud, args?)?.push_into_stack_multi(lua) + // } _ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)), } }) } #[cfg(feature = "async")] - fn box_async_method<'s, M, A, MR, R>(name: &str, method: M) -> AsyncCallback<'lua, 'static> + fn box_async_method<M, A, MR, R>(name: String, method: M) -> AsyncCallback<'a> where - 'lua: 's, - T: 'static, - M: Fn(&'lua Lua, &'s T, A) -> MR + MaybeSend + 'static, - A: FromLuaMulti<'lua>, - MR: Future<Output = Result<R>> + 's, + M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static, + A: FromLuaMulti, + MR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti, { - let name = Arc::new(get_function_name::<T>(name)); + let name = Arc::new(get_function_name::<T>(&name)); let method = Arc::new(method); - Box::new(move |lua, mut args| unsafe { + Box::new(move |rawlua, mut args| unsafe { let name = name.clone(); let method = method.clone(); macro_rules! try_self_arg { @@ -237,65 +234,63 @@ impl<'lua, T: 'static> UserDataRegistry<'lua, T> { let this = args.pop_front().ok_or_else(|| { Error::from_lua_conversion("missing argument", "userdata", None) }); + let lua = rawlua.lua(); 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.ref_thread(), this.0.index); + let (ref_thread, index) = (rawlua.ref_thread(), this.0.index); match try_self_arg!(this.type_id()) { Some(id) if id == TypeId::of::<T>() => { - let ud = try_self_arg!(get_userdata_ref::<T>(ref_thread, index)); - let ud = std::mem::transmute::<&T, &T>(&ud); - method(lua, ud, args?).await?.push_into_stack_multi(lua) - } - #[cfg(not(feature = "send"))] - Some(id) if id == TypeId::of::<Rc<T>>() => { - let ud = try_self_arg!(get_userdata_ref::<Rc<T>>(ref_thread, index)); - let ud = std::mem::transmute::<&T, &T>(&ud); - method(lua, ud, args?).await?.push_into_stack_multi(lua) - } - #[cfg(not(feature = "send"))] - Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => { - let ud = - try_self_arg!(get_userdata_ref::<Rc<RefCell<T>>>(ref_thread, index)); - let ud = try_self_arg!(ud.try_borrow(), Error::UserDataBorrowError); - let ud = std::mem::transmute::<&T, &T>(&ud); - method(lua, ud, args?).await?.push_into_stack_multi(lua) - } - Some(id) if id == TypeId::of::<Arc<T>>() => { - let ud = try_self_arg!(get_userdata_ref::<Arc<T>>(ref_thread, index)); - let ud = std::mem::transmute::<&T, &T>(&ud); - method(lua, ud, args?).await?.push_into_stack_multi(lua) - } - Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => { - let ud = - try_self_arg!(get_userdata_ref::<Arc<Mutex<T>>>(ref_thread, index)); - let ud = try_self_arg!(ud.try_lock(), Error::UserDataBorrowError); - let ud = std::mem::transmute::<&T, &T>(&ud); - method(lua, ud, args?).await?.push_into_stack_multi(lua) - } - #[cfg(feature = "parking_lot")] - Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => { - let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(ref_thread, index); - let ud = try_self_arg!(ud); - let ud = try_self_arg!(ud.try_lock().ok_or(Error::UserDataBorrowError)); - let ud = std::mem::transmute::<&T, &T>(&ud); - method(lua, ud, args?).await?.push_into_stack_multi(lua) - } - Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => { - let ud = - try_self_arg!(get_userdata_ref::<Arc<RwLock<T>>>(ref_thread, index)); - let ud = try_self_arg!(ud.try_read(), Error::UserDataBorrowError); - let ud = std::mem::transmute::<&T, &T>(&ud); - method(lua, ud, args?).await?.push_into_stack_multi(lua) - } - #[cfg(feature = "parking_lot")] - Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => { - let ud = get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(ref_thread, index); - let ud = try_self_arg!(ud); - let ud = try_self_arg!(ud.try_read().ok_or(Error::UserDataBorrowError)); + let ud = try_self_arg!(borrow_userdata_ref::<T>(ref_thread, index)); let ud = std::mem::transmute::<&T, &T>(&ud); - method(lua, ud, args?).await?.push_into_stack_multi(lua) + method(lua, ud, args?).await?.push_into_stack_multi(&rawlua) } + // #[cfg(not(feature = "send"))] + // Some(id) if id == TypeId::of::<Rc<T>>() => { + // let ud = try_self_arg!(rawlua.get_userdata_ref::<Rc<T>>(&this)); + // let ud = std::mem::transmute::<&T, &T>(&ud); + // method(lua, ud, args?).await?.push_into_stack_multi(&rawlua) + // } + // #[cfg(not(feature = "send"))] + // Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => { + // let ud = try_self_arg!(rawlua.get_userdata_ref::<Rc<RefCell<T>>>(&this)); + // let ud = try_self_arg!(ud.try_borrow(), Error::UserDataBorrowError); + // let ud = std::mem::transmute::<&T, &T>(&ud); + // method(lua, ud, args?).await?.push_into_stack_multi(&rawlua) + // } + // Some(id) if id == TypeId::of::<Arc<T>>() => { + // let ud = try_self_arg!(rawlua.get_userdata_ref::<Arc<T>>(&this)); + // let ud = std::mem::transmute::<&T, &T>(&ud); + // method(lua, ud, args?).await?.push_into_stack_multi(&rawlua) + // } + // Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => { + // let ud = try_self_arg!(rawlua.get_userdata_ref::<Arc<Mutex<T>>>(&this)); + // let ud = try_self_arg!(ud.try_lock(), Error::UserDataBorrowError); + // let ud = std::mem::transmute::<&T, &T>(&ud); + // method(lua, ud, args?).await?.push_into_stack_multi(&rawlua) + // } + // #[cfg(feature = "parking_lot")] + // Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => { + // let ud = rawlua.get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(&this); + // let ud = try_self_arg!(ud); + // let ud = try_self_arg!(ud.try_lock().ok_or(Error::UserDataBorrowError)); + // let ud = std::mem::transmute::<&T, &T>(&ud); + // method(lua, ud, args?).await?.push_into_stack_multi(lua) + // } + // Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => { + // let ud = try_self_arg!(rawlua.get_userdata_ref::<Arc<RwLock<T>>>(&this)); + // let ud = try_self_arg!(ud.try_read(), Error::UserDataBorrowError); + // let ud = std::mem::transmute::<&T, &T>(&ud); + // method(lua, ud, args?).await?.push_into_stack_multi(&rawlua) + // } + // #[cfg(feature = "parking_lot")] + // Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => { + // let ud = get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(ref_thread, index); + // let ud = try_self_arg!(ud); + // let ud = try_self_arg!(ud.try_read().ok_or(Error::UserDataBorrowError)); + // let ud = std::mem::transmute::<&T, &T>(&ud); + // method(lua, ud, args?).await?.push_into_stack_multi(lua) + // } _ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)), } }) @@ -303,19 +298,17 @@ impl<'lua, T: 'static> UserDataRegistry<'lua, T> { } #[cfg(feature = "async")] - fn box_async_method_mut<'s, M, A, MR, R>(name: &str, method: M) -> AsyncCallback<'lua, 'static> + fn box_async_method_mut<M, A, MR, R>(name: String, method: M) -> AsyncCallback<'a> where - 'lua: 's, - T: 'static, - M: Fn(&'lua Lua, &'s mut T, A) -> MR + MaybeSend + 'static, - A: FromLuaMulti<'lua>, - MR: Future<Output = Result<R>> + 's, + M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static, + A: FromLuaMulti, + MR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti, { - let name = Arc::new(get_function_name::<T>(name)); + let name = Arc::new(get_function_name::<T>(&name)); let method = Arc::new(method); - Box::new(move |lua, mut args| unsafe { + Box::new(move |rawlua, mut args| unsafe { let name = name.clone(); let method = method.clone(); macro_rules! try_self_arg { @@ -331,86 +324,87 @@ impl<'lua, T: 'static> UserDataRegistry<'lua, T> { let this = args.pop_front().ok_or_else(|| { Error::from_lua_conversion("missing argument", "userdata", None) }); + let lua = rawlua.lua(); 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.ref_thread(), this.0.index); + let (ref_thread, index) = (rawlua.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!(get_userdata_mut::<T>(ref_thread, index)); + let mut ud = try_self_arg!(borrow_userdata_mut::<T>(ref_thread, index)); let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud); - method(lua, ud, args?).await?.push_into_stack_multi(lua) - } - #[cfg(not(feature = "send"))] - Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => { - Err(Error::UserDataBorrowMutError) - } - #[cfg(not(feature = "send"))] - Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => { - let ud = - try_self_arg!(get_userdata_mut::<Rc<RefCell<T>>>(ref_thread, index)); - let mut ud = - try_self_arg!(ud.try_borrow_mut(), Error::UserDataBorrowMutError); - let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud); - method(lua, ud, args?).await?.push_into_stack_multi(lua) - } - #[cfg(not(feature = "send"))] - Some(id) if id == TypeId::of::<Arc<T>>() => Err(Error::UserDataBorrowMutError), - Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => { - let ud = - try_self_arg!(get_userdata_mut::<Arc<Mutex<T>>>(ref_thread, index)); - let mut ud = try_self_arg!(ud.try_lock(), Error::UserDataBorrowMutError); - let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud); - method(lua, ud, args?).await?.push_into_stack_multi(lua) - } - #[cfg(feature = "parking_lot")] - Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => { - let ud = get_userdata_mut::<Arc<parking_lot::Mutex<T>>>(ref_thread, index); - let ud = try_self_arg!(ud); - let mut ud = - try_self_arg!(ud.try_lock().ok_or(Error::UserDataBorrowMutError)); - let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud); - method(lua, ud, args?).await?.push_into_stack_multi(lua) - } - Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => { - let ud = - try_self_arg!(get_userdata_mut::<Arc<RwLock<T>>>(ref_thread, index)); - let mut ud = try_self_arg!(ud.try_write(), Error::UserDataBorrowMutError); - let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud); - method(lua, ud, args?).await?.push_into_stack_multi(lua) - } - #[cfg(feature = "parking_lot")] - Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => { - let ud = get_userdata_mut::<Arc<parking_lot::RwLock<T>>>(ref_thread, index); - let ud = try_self_arg!(ud); - let mut ud = - try_self_arg!(ud.try_write().ok_or(Error::UserDataBorrowMutError)); - let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud); - method(lua, ud, args?).await?.push_into_stack_multi(lua) + method(lua, ud, args?).await?.push_into_stack_multi(&rawlua) } + // #[cfg(not(feature = "send"))] + // Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => { + // Err(Error::UserDataBorrowMutError) + // } + // #[cfg(not(feature = "send"))] + // Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => { + // let ud = + // try_self_arg!(get_userdata_mut::<Rc<RefCell<T>>>(ref_thread, index)); + // let mut ud = + // try_self_arg!(ud.try_borrow_mut(), Error::UserDataBorrowMutError); + // let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud); + // method(lua, ud, args?).await?.push_into_stack_multi(&rawlua) + // } + // #[cfg(not(feature = "send"))] + // Some(id) if id == TypeId::of::<Arc<T>>() => Err(Error::UserDataBorrowMutError), + // Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => { + // let ud = + // try_self_arg!(get_userdata_mut::<Arc<Mutex<T>>>(ref_thread, index)); + // let mut ud = try_self_arg!(ud.try_lock(), Error::UserDataBorrowMutError); + // let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud); + // method(lua, ud, args?).await?.push_into_stack_multi(&rawlua) + // } + // #[cfg(feature = "parking_lot")] + // Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => { + // let ud = get_userdata_mut::<Arc<parking_lot::Mutex<T>>>(ref_thread, index); + // let ud = try_self_arg!(ud); + // let mut ud = + // try_self_arg!(ud.try_lock().ok_or(Error::UserDataBorrowMutError)); + // let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud); + // method(lua, ud, args?).await?.push_into_stack_multi(&rawlua) + // } + // Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => { + // let ud = + // try_self_arg!(get_userdata_mut::<Arc<RwLock<T>>>(ref_thread, index)); + // let mut ud = try_self_arg!(ud.try_write(), Error::UserDataBorrowMutError); + // let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud); + // method(lua, ud, args?).await?.push_into_stack_multi(&rawlua) + // } + // #[cfg(feature = "parking_lot")] + // Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => { + // let ud = get_userdata_mut::<Arc<parking_lot::RwLock<T>>>(ref_thread, index); + // let ud = try_self_arg!(ud); + // let mut ud = + // try_self_arg!(ud.try_write().ok_or(Error::UserDataBorrowMutError)); + // let ud = std::mem::transmute::<&mut T, &mut T>(&mut ud); + // method(lua, ud, args?).await?.push_into_stack_multi(lua) + // } _ => Err(Error::bad_self_argument(&name, Error::UserDataTypeMismatch)), } }) }) } - fn box_function<F, A, R>(name: &str, function: F) -> Callback<'lua, 'static> + fn box_function<F, A, R>(name: &str, function: F) -> Callback<'a> where - F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + F: Fn(&'a Lua, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti, { let name = get_function_name::<T>(name); Box::new(move |lua, nargs| unsafe { let args = A::from_stack_args(nargs, 1, Some(&name), lua)?; - function(lua, args)?.push_into_stack_multi(lua) + function(lua.lua(), args)?.push_into_stack_multi(lua) }) } - fn box_function_mut<F, A, R>(name: &str, function: F) -> Callback<'lua, 'static> + fn box_function_mut<F, A, R>(name: &str, function: F) -> Callback<'a> where - F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + F: FnMut(&'a Lua, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti, { let name = get_function_name::<T>(name); @@ -420,30 +414,32 @@ impl<'lua, T: 'static> UserDataRegistry<'lua, T> { .try_borrow_mut() .map_err(|_| Error::RecursiveMutCallback)?; let args = A::from_stack_args(nargs, 1, Some(&name), lua)?; - function(lua, args)?.push_into_stack_multi(lua) + function(lua.lua(), args)?.push_into_stack_multi(lua) }) } #[cfg(feature = "async")] - fn box_async_function<F, A, FR, R>(name: &str, function: F) -> AsyncCallback<'lua, 'static> + fn box_async_function<F, A, FR, R>(name: String, function: F) -> AsyncCallback<'a> where - F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static, - A: FromLuaMulti<'lua>, - FR: Future<Output = Result<R>> + 'lua, + F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static, + A: FromLuaMulti, + FR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti, { - let name = get_function_name::<T>(name); - Box::new(move |lua, args| unsafe { + let name = get_function_name::<T>(&name); + Box::new(move |rawlua, args| unsafe { + let lua = rawlua.lua(); let args = match A::from_lua_args(args, 1, Some(&name), lua) { Ok(args) => args, Err(e) => return Box::pin(future::err(e)), }; let fut = function(lua, args); - Box::pin(async move { fut.await?.push_into_stack_multi(lua) }) + let weak = rawlua.weak().clone(); + Box::pin(async move { fut.await?.push_into_stack_multi(&weak.lock()) }) }) } - pub(crate) fn check_meta_field<V>(lua: &'lua Lua, name: &str, value: V) -> Result<Value<'lua>> + pub(crate) fn check_meta_field<V>(lua: &Lua, name: &str, value: V) -> Result<Value> where V: IntoLua, { @@ -469,310 +465,296 @@ fn get_function_name<T>(name: &str) -> StdString { format!("{}.{name}", short_type_name::<T>()) } -impl<'lua, T: 'static> UserDataFields<'lua, T> for UserDataRegistry<'lua, T> { - fn add_field<V>(&mut self, name: impl AsRef<str>, value: V) +impl<'a, T: 'static> UserDataFields<'a, T> for UserDataRegistry<'a, T> { + fn add_field<V>(&mut self, name: impl ToString, value: V) where V: IntoLua + Clone + 'static, { - let name = name.as_ref().to_string(); - self.fields.push(( - name, - Box::new(move |lua, _| unsafe { value.clone().push_into_stack_multi(lua) }), - )); + let name = name.to_string(); + let 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 AsRef<str>, method: M) + fn add_field_method_get<M, R>(&mut self, name: impl ToString, method: M) where - M: Fn(&'lua Lua, &T) -> Result<R> + MaybeSend + 'static, + M: Fn(&'a Lua, &T) -> Result<R> + MaybeSend + 'static, R: IntoLua, { - let name = name.as_ref(); - let method = Self::box_method(name, move |lua, data, ()| method(lua, data)); - self.field_getters.push((name.into(), method)); + let name = name.to_string(); + let callback = Self::box_method(&name, move |lua, data, ()| method(lua, &data)); + self.field_getters.push((name.into(), callback)); } - fn add_field_method_set<M, A>(&mut self, name: impl AsRef<str>, method: M) + fn add_field_method_set<M, A>(&mut self, name: impl ToString, method: M) where - M: FnMut(&'lua Lua, &mut T, A) -> Result<()> + MaybeSend + 'static, - A: FromLua<'lua>, + M: FnMut(&'a Lua, &mut T, A) -> Result<()> + MaybeSend + 'static, + A: FromLua, { - let name = name.as_ref(); - let method = Self::box_method_mut(name, method); - self.field_setters.push((name.into(), method)); + let name = name.to_string(); + let callback = Self::box_method_mut(&name, method); + self.field_setters.push((name, callback)); } - fn add_field_function_get<F, R>(&mut self, name: impl AsRef<str>, function: F) + fn add_field_function_get<F, R>(&mut self, name: impl ToString, function: F) where - F: Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R> + MaybeSend + 'static, + F: Fn(&'a Lua, AnyUserData) -> Result<R> + MaybeSend + 'static, R: IntoLua, { - let name = name.as_ref(); - let func = Self::box_function(name, function); - self.field_getters.push((name.into(), func)); + let name = name.to_string(); + let callback = Self::box_function(&name, function); + self.field_getters.push((name, callback)); } - fn add_field_function_set<F, A>(&mut self, name: impl AsRef<str>, mut function: F) + fn add_field_function_set<F, A>(&mut self, name: impl ToString, mut function: F) where - F: FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()> + MaybeSend + 'static, - A: FromLua<'lua>, + F: FnMut(&'a Lua, AnyUserData, A) -> Result<()> + MaybeSend + 'static, + A: FromLua, { - let name = name.as_ref(); - let func = Self::box_function_mut(name, move |lua, (data, val)| function(lua, data, val)); - self.field_setters.push((name.into(), func)); + let name = name.to_string(); + let callback = + Self::box_function_mut(&name, move |lua, (data, val)| function(lua, data, val)); + self.field_setters.push((name, callback)); } - fn add_meta_field<V>(&mut self, name: impl AsRef<str>, value: V) + fn add_meta_field<V>(&mut self, name: impl ToString, value: V) where V: IntoLua + Clone + 'static, { - let name = name.as_ref().to_string(); + let name = name.to_string(); let name2 = name.clone(); self.meta_fields.push(( name, Box::new(move |lua, _| unsafe { - Self::check_meta_field(lua, &name2, value.clone())?.push_into_stack_multi(lua) + Self::check_meta_field(lua.lua(), &name2, value.clone())?.push_into_stack_multi(lua) }), )); } - fn add_meta_field_with<F, R>(&mut self, name: impl AsRef<str>, f: F) + fn add_meta_field_with<F, R>(&mut self, name: impl ToString, f: F) where - F: Fn(&'lua Lua) -> Result<R> + MaybeSend + 'static, + F: Fn(&'a Lua) -> Result<R> + MaybeSend + 'static, R: IntoLua, { - let name = name.as_ref().to_string(); + let name = name.to_string(); let name2 = name.clone(); self.meta_fields.push(( name, - Box::new(move |lua, _| unsafe { - Self::check_meta_field(lua, &name2, f(lua)?)?.push_into_stack_multi(lua) + Box::new(move |rawlua, _| unsafe { + let lua = rawlua.lua(); + Self::check_meta_field(lua, &name2, f(lua)?)?.push_into_stack_multi(rawlua) }), )); } - - // Below are internal methods - - fn append_fields_from<S>(&mut self, other: UserDataRegistry<'lua, S>) { - self.fields.extend(other.fields); - self.field_getters.extend(other.field_getters); - self.field_setters.extend(other.field_setters); - self.meta_fields.extend(other.meta_fields); - } } -impl<'lua, T: 'static> UserDataMethods<'lua, T> for UserDataRegistry<'lua, T> { - fn add_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M) +impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> { + fn add_method<M, A, R>(&mut self, name: impl ToString, method: M) where - M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + M: Fn(&'a Lua, &T, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti, { - let name = name.as_ref(); - self.methods - .push((name.into(), Self::box_method(name, method))); + let name = name.to_string(); + let callback = Self::box_method(&name, method); + self.methods.push((name, callback)); } - fn add_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, method: M) + fn add_method_mut<M, A, R>(&mut self, name: impl ToString, method: M) where - M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + M: FnMut(&'a Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti, { - let name = name.as_ref(); - self.methods - .push((name.into(), Self::box_method_mut(name, method))); + let name = name.to_string(); + let callback = Self::box_method_mut(&name, method); + self.methods.push((name, callback)); } #[cfg(feature = "async")] - fn add_async_method<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M) + fn add_async_method<M, A, MR, R>(&mut self, name: impl ToString, method: M) where - 'lua: 's, - T: 'static, - M: Fn(&'lua Lua, &'s T, A) -> MR + MaybeSend + 'static, - A: FromLuaMulti<'lua>, - MR: Future<Output = Result<R>> + 's, + M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static, + A: FromLuaMulti, + MR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti, { - let name = name.as_ref(); - self.async_methods - .push((name.into(), Self::box_async_method(name, method))); + let name = name.to_string(); + let callback = Self::box_async_method(name.clone(), method); + self.async_methods.push((name, callback)); } #[cfg(feature = "async")] - fn add_async_method_mut<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M) + fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl ToString, method: M) where - 'lua: 's, - T: 'static, - M: Fn(&'lua Lua, &'s mut T, A) -> MR + MaybeSend + 'static, - A: FromLuaMulti<'lua>, - MR: Future<Output = Result<R>> + 's, + M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static, + A: FromLuaMulti, + MR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti, { - let name = name.as_ref(); - self.async_methods - .push((name.into(), Self::box_async_method_mut(name, method))); + let name = name.to_string(); + let callback = Self::box_async_method_mut(name.clone(), method); + self.async_methods.push((name, callback)); } - fn add_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F) + fn add_function<F, A, R>(&mut self, name: impl ToString, function: F) where - F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + F: Fn(&'a Lua, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti, { - let name = name.as_ref(); - self.methods - .push((name.into(), Self::box_function(name, function))); + let name = name.to_string(); + let callback = Self::box_function(&name, function); + self.methods.push((name, callback)); } - fn add_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, function: F) + fn add_function_mut<F, A, R>(&mut self, name: impl ToString, function: F) where - F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + F: FnMut(&'a Lua, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti, { - let name = name.as_ref(); - self.methods - .push((name.into(), Self::box_function_mut(name, function))); + let name = name.to_string(); + let callback = Self::box_function_mut(&name, function); + self.methods.push((name, callback)); } #[cfg(feature = "async")] - fn add_async_function<F, A, FR, R>(&mut self, name: impl AsRef<str>, function: F) + fn add_async_function<F, A, FR, R>(&mut self, name: impl ToString, function: F) where - F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static, - A: FromLuaMulti<'lua>, - FR: Future<Output = Result<R>> + 'lua, + F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static, + A: FromLuaMulti, + FR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti, { - let name = name.as_ref(); - self.async_methods - .push((name.into(), Self::box_async_function(name, function))); + let name = name.to_string(); + let callback = Self::box_async_function(name.clone(), function); + self.async_methods.push((name, callback)); } - fn add_meta_method<M, A, R>(&mut self, name: impl AsRef<str>, method: M) + fn add_meta_method<M, A, R>(&mut self, name: impl ToString, method: M) where - M: Fn(&'lua Lua, &T, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + M: Fn(&'a Lua, &T, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti, { - let name = name.as_ref(); - self.meta_methods - .push((name.into(), Self::box_method(name, method))); + let name = name.to_string(); + let callback = Self::box_method(&name, method); + self.meta_methods.push((name, callback)); } - fn add_meta_method_mut<M, A, R>(&mut self, name: impl AsRef<str>, method: M) + fn add_meta_method_mut<M, A, R>(&mut self, name: impl ToString, method: M) where - M: FnMut(&'lua Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + M: FnMut(&'a Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti, { - let name = name.as_ref(); - self.meta_methods - .push((name.into(), Self::box_method_mut(name, method))); + let name = name.to_string(); + let callback = Self::box_method_mut(&name, method); + self.meta_methods.push((name, callback)); } #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] - fn add_async_meta_method<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M) + fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl ToString, method: M) where - 'lua: 's, - T: 'static, - M: Fn(&'lua Lua, &'s T, A) -> MR + MaybeSend + 'static, - A: FromLuaMulti<'lua>, - MR: Future<Output = Result<R>> + 's, + M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static, + A: FromLuaMulti, + MR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti, { - let name = name.as_ref(); - self.async_meta_methods - .push((name.into(), Self::box_async_method(name, method))); + let name = name.to_string(); + let callback = Self::box_async_method(name.clone(), method); + self.async_meta_methods.push((name, callback)); } #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] - fn add_async_meta_method_mut<'s, M, A, MR, R>(&mut self, name: impl AsRef<str>, method: M) + fn add_async_meta_method_mut<M, A, MR, R>(&mut self, name: impl ToString, method: M) where - 'lua: 's, - T: 'static, - M: Fn(&'lua Lua, &'s mut T, A) -> MR + MaybeSend + 'static, - A: FromLuaMulti<'lua>, - MR: Future<Output = Result<R>> + 's, + M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static, + A: FromLuaMulti, + MR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti, { - let name = name.as_ref(); - self.async_meta_methods - .push((name.into(), Self::box_async_method_mut(name, method))); + let name = name.to_string(); + let callback = Self::box_async_method_mut(name.clone(), method); + self.async_meta_methods.push((name, callback)); } - fn add_meta_function<F, A, R>(&mut self, name: impl AsRef<str>, function: F) + fn add_meta_function<F, A, R>(&mut self, name: impl ToString, function: F) where - F: Fn(&'lua Lua, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + F: Fn(&'a Lua, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti, { - let name = name.as_ref(); - self.meta_methods - .push((name.into(), Self::box_function(name, function))); + let name = name.to_string(); + let callback = Self::box_function(&name, function); + self.meta_methods.push((name, callback)); } - fn add_meta_function_mut<F, A, R>(&mut self, name: impl AsRef<str>, function: F) + fn add_meta_function_mut<F, A, R>(&mut self, name: impl ToString, function: F) where - F: FnMut(&'lua Lua, A) -> Result<R> + MaybeSend + 'static, - A: FromLuaMulti<'lua>, + F: FnMut(&'a Lua, A) -> Result<R> + MaybeSend + 'static, + A: FromLuaMulti, R: IntoLuaMulti, { - let name = name.as_ref(); - self.meta_methods - .push((name.into(), Self::box_function_mut(name, function))); + let name = name.to_string(); + let callback = Self::box_function_mut(&name, function); + self.meta_methods.push((name, callback)); } #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] - fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl AsRef<str>, function: F) + fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl ToString, function: F) where - F: Fn(&'lua Lua, A) -> FR + MaybeSend + 'static, - A: FromLuaMulti<'lua>, - FR: Future<Output = Result<R>> + 'lua, + F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static, + A: FromLuaMulti, + FR: Future<Output = Result<R>> + 'a, R: IntoLuaMulti, { - let name = name.as_ref(); - self.async_meta_methods - .push((name.into(), Self::box_async_function(name, function))); - } - - // Below are internal methods used in generated code - - fn append_methods_from<S>(&mut self, other: UserDataRegistry<'lua, S>) { - self.methods.extend(other.methods); - #[cfg(feature = "async")] - self.async_methods.extend(other.async_methods); - self.meta_methods.extend(other.meta_methods); - #[cfg(feature = "async")] - self.async_meta_methods.extend(other.async_meta_methods); + let name = name.to_string(); + let callback = Self::box_async_function(name.clone(), function); + self.async_meta_methods.push((name, callback)); } } +// Borrow the userdata in-place from the Lua stack #[inline] -unsafe fn get_userdata_ref<'a, T>(state: *mut ffi::lua_State, index: c_int) -> Result<Ref<'a, T>> { - (*get_userdata::<UserDataCell<T>>(state, index)).try_borrow() +unsafe fn borrow_userdata_ref<'a, T>( + state: *mut ffi::lua_State, + index: c_int, +) -> Result<UserDataBorrowRef<'a, T>> { + let ud = get_userdata::<UserDataVariant<T>>(state, index); + (*ud).try_borrow() } +// Borrow the userdata mutably in-place from the Lua stack #[inline] -unsafe fn get_userdata_mut<'a, T>( +unsafe fn borrow_userdata_mut<'a, T>( state: *mut ffi::lua_State, index: c_int, -) -> Result<RefMut<'a, T>> { - (*get_userdata::<UserDataCell<T>>(state, index)).try_borrow_mut() +) -> Result<UserDataBorrowMut<'a, T>> { + let ud = get_userdata::<UserDataVariant<T>>(state, index); + (*ud).try_borrow_mut() } macro_rules! lua_userdata_impl { ($type:ty) => { impl<T: UserData + 'static> UserData for $type { - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { - let mut orig_fields = UserDataRegistry::new(); - T::add_fields(&mut orig_fields); - fields.append_fields_from(orig_fields); - } - - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { - let mut orig_methods = UserDataRegistry::new(); - T::add_methods(&mut orig_methods); - methods.append_methods_from(orig_methods); + fn register(registry: &mut UserDataRegistry<Self>) { + let mut orig_registry = UserDataRegistry::new(); + T::register(&mut orig_registry); + + // Copy all fields, methods, etc. from the original registry + registry.fields.extend(orig_registry.fields); + registry.field_getters.extend(orig_registry.field_getters); + registry.field_setters.extend(orig_registry.field_setters); + registry.meta_fields.extend(orig_registry.meta_fields); + registry.methods.extend(orig_registry.methods); + #[cfg(feature = "async")] + registry.async_methods.extend(orig_registry.async_methods); + registry.meta_methods.extend(orig_registry.meta_methods); + #[cfg(feature = "async")] + registry + .async_meta_methods + .extend(orig_registry.async_meta_methods); } } }; diff --git a/src/value.rs b/src/value.rs index 2e5f2d9..e589d8c 100644 --- a/src/value.rs +++ b/src/value.rs @@ -19,7 +19,7 @@ use { use crate::error::{Error, Result}; use crate::function::Function; -use crate::lua::Lua; +use crate::lua::{Lua, LuaInner}; use crate::string::String; use crate::table::Table; use crate::thread::Thread; @@ -31,7 +31,7 @@ use crate::util::{check_stack, StackGuard}; /// variants contain handle types into the internal Lua state. It is a logic error to mix handle /// types between separate `Lua` instances, and doing so will result in a panic. #[derive(Clone)] -pub enum Value<'lua> { +pub enum Value { /// The Lua value `nil`. Nil, /// The Lua value `true` or `false`. @@ -51,27 +51,27 @@ pub enum Value<'lua> { /// An interned string, managed by Lua. /// /// Unlike Rust strings, Lua strings may not be valid UTF-8. - String(String<'lua>), + String(String), /// Reference to a Lua table. - Table(Table<'lua>), + Table(Table), /// Reference to a Lua function (or closure). - Function(Function<'lua>), + Function(Function), /// Reference to a Lua thread (or coroutine). - Thread(Thread<'lua>), + Thread(Thread), /// Reference to a userdata object that holds a custom type which implements `UserData`. /// Special builtin userdata types will be represented as other `Value` variants. - UserData(AnyUserData<'lua>), + UserData(AnyUserData), /// `Error` is a special builtin userdata type. When received from Lua it is implicitly cloned. Error(Box<Error>), } pub use self::Value::Nil; -impl<'lua> Value<'lua> { +impl Value { /// A special value (lightuserdata) to represent null value. /// /// It can be used in Lua tables without downsides of `nil`. - pub const NULL: Value<'static> = Value::LightUserData(LightUserData(ptr::null_mut())); + pub const NULL: Value = Value::LightUserData(LightUserData(ptr::null_mut())); /// Returns type name of this value. pub const fn type_name(&self) -> &'static str { @@ -152,15 +152,16 @@ impl<'lua> Value<'lua> { | Value::Function(Function(r)) | Value::Thread(Thread(r, ..)) | Value::UserData(AnyUserData(r, ..)) => unsafe { - let state = r.lua.state(); + let lua = r.lua.lock(); + let state = lua.state(); let _guard = StackGuard::new(state); check_stack(state, 3)?; - r.lua.push_ref(r); + lua.push_ref(r); protect_lua!(state, 1, 1, fn(state) { ffi::luaL_tolstring(state, -1, ptr::null_mut()); })?; - Ok(String(r.lua.pop_ref()).to_str()?.to_string()) + Ok(String(lua.pop_ref()).to_str()?.to_string()) }, Value::Error(err) => Ok(err.to_string()), } @@ -440,7 +441,7 @@ impl<'lua> Value<'lua> { #[cfg(feature = "serialize")] #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))] #[doc(hidden)] - pub fn to_serializable(&self) -> SerializableValue<'_, 'lua> { + pub fn to_serializable(&self) -> SerializableValue { SerializableValue::new(self, Default::default(), None) } @@ -522,7 +523,7 @@ impl<'lua> Value<'lua> { } } -impl fmt::Debug for Value<'_> { +impl fmt::Debug for Value { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { if fmt.alternate() { return self.fmt_pretty(fmt, true, 0, &mut HashSet::new()); @@ -545,7 +546,7 @@ impl fmt::Debug for Value<'_> { } } -impl<'lua> PartialEq for Value<'lua> { +impl PartialEq for Value { fn eq(&self, other: &Self) -> bool { match (self, other) { (Value::Nil, Value::Nil) => true, @@ -567,7 +568,7 @@ impl<'lua> PartialEq for Value<'lua> { } } -impl<'lua> AsRef<Value<'lua>> for Value<'lua> { +impl AsRef<Value> for Value { #[inline] fn as_ref(&self) -> &Self { self @@ -577,15 +578,15 @@ impl<'lua> AsRef<Value<'lua>> for Value<'lua> { /// A wrapped [`Value`] with customized serialization behavior. #[cfg(feature = "serialize")] #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))] -pub struct SerializableValue<'a, 'lua> { - value: &'a Value<'lua>, +pub struct SerializableValue<'a> { + value: &'a Value, options: crate::serde::de::Options, // In many cases we don't need `visited` map, so don't allocate memory by default visited: Option<Rc<RefCell<FxHashSet<*const c_void>>>>, } #[cfg(feature = "serialize")] -impl<'lua> Serialize for Value<'lua> { +impl Serialize for Value { #[inline] fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> { SerializableValue::new(self, Default::default(), None).serialize(serializer) @@ -593,10 +594,10 @@ impl<'lua> Serialize for Value<'lua> { } #[cfg(feature = "serialize")] -impl<'a, 'lua> SerializableValue<'a, 'lua> { +impl<'a> SerializableValue<'a> { #[inline] pub(crate) fn new( - value: &'a Value<'lua>, + value: &'a Value, options: crate::serde::de::Options, visited: Option<&Rc<RefCell<FxHashSet<*const c_void>>>>, ) -> Self { @@ -648,7 +649,7 @@ impl<'a, 'lua> SerializableValue<'a, 'lua> { } #[cfg(feature = "serialize")] -impl<'a, 'lua> Serialize for SerializableValue<'a, 'lua> { +impl<'a> Serialize for SerializableValue<'a> { fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error> where S: Serializer, @@ -689,7 +690,7 @@ impl<'a, 'lua> Serialize for SerializableValue<'a, 'lua> { /// Trait for types convertible to `Value`. pub trait IntoLua: Sized { /// Performs the conversion. - fn into_lua(self, lua: &Lua) -> Result<Value<'_>>; + fn into_lua(self, lua: &Lua) -> Result<Value>; /// Pushes the value into the Lua stack. /// @@ -697,15 +698,15 @@ pub trait IntoLua: Sized { /// This method does not check Lua stack space. #[doc(hidden)] #[inline] - unsafe fn push_into_stack(self, lua: &Lua) -> Result<()> { - lua.push_value(&self.into_lua(lua)?) + unsafe fn push_into_stack(self, lua: &LuaInner) -> Result<()> { + lua.push_value(&self.into_lua(lua.lua())?) } } /// Trait for types convertible from `Value`. -pub trait FromLua<'lua>: Sized { +pub trait FromLua: Sized { /// Performs the conversion. - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self>; + fn from_lua(value: Value, lua: &Lua) -> Result<Self>; /// Performs the conversion for an argument (eg. function argument). /// @@ -713,7 +714,7 @@ pub trait FromLua<'lua>: Sized { /// `to` is a function name that received the argument. #[doc(hidden)] #[inline] - fn from_lua_arg(arg: Value<'lua>, i: usize, to: Option<&str>, lua: &'lua Lua) -> Result<Self> { + fn from_lua_arg(arg: Value, i: usize, to: Option<&str>, lua: &Lua) -> Result<Self> { Self::from_lua(arg, lua).map_err(|err| Error::BadArgument { to: to.map(|s| s.to_string()), pos: i, @@ -725,8 +726,8 @@ pub trait FromLua<'lua>: Sized { /// Performs the conversion for a value in the Lua stack at index `idx`. #[doc(hidden)] #[inline] - unsafe fn from_stack(idx: c_int, lua: &'lua Lua) -> Result<Self> { - Self::from_lua(lua.stack_value(idx), lua) + unsafe fn from_stack(idx: c_int, lua: &LuaInner) -> Result<Self> { + Self::from_lua(lua.stack_value(idx), lua.lua()) } /// Same as `from_lua_arg` but for a value in the Lua stack at index `idx`. @@ -736,7 +737,7 @@ pub trait FromLua<'lua>: Sized { idx: c_int, i: usize, to: Option<&str>, - lua: &'lua Lua, + lua: &LuaInner, ) -> Result<Self> { Self::from_stack(idx, lua).map_err(|err| Error::BadArgument { to: to.map(|s| s.to_string()), @@ -749,29 +750,31 @@ pub trait FromLua<'lua>: Sized { /// Multiple Lua values used for both argument passing and also for multiple return values. #[derive(Debug, Clone)] -pub struct MultiValue<'lua> { - deque: VecDeque<Value<'lua>>, - lua: Option<&'lua Lua>, +pub struct MultiValue { + deque: VecDeque<Value>, + // FIXME + // lua: Option<&'static Lua>, } -impl Drop for MultiValue<'_> { +impl Drop for MultiValue { fn drop(&mut self) { - if let Some(lua) = self.lua { - let vec = mem::take(&mut self.deque); - lua.push_multivalue_to_pool(vec); - } + // FIXME + // if let Some(lua) = self.lua { + // let vec = mem::take(&mut self.deque); + // lua.push_multivalue_to_pool(vec); + // } } } -impl<'lua> Default for MultiValue<'lua> { +impl Default for MultiValue { #[inline] - fn default() -> MultiValue<'lua> { + fn default() -> MultiValue { MultiValue::new() } } -impl<'lua> Deref for MultiValue<'lua> { - type Target = VecDeque<Value<'lua>>; +impl Deref for MultiValue { + type Target = VecDeque<Value>; #[inline] fn deref(&self) -> &Self::Target { @@ -779,44 +782,46 @@ impl<'lua> Deref for MultiValue<'lua> { } } -impl<'lua> DerefMut for MultiValue<'lua> { +impl DerefMut for MultiValue { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.deque } } -impl<'lua> MultiValue<'lua> { +impl MultiValue { /// Creates an empty `MultiValue` containing no values. - pub const fn new() -> MultiValue<'lua> { + pub const fn new() -> MultiValue { MultiValue { deque: VecDeque::new(), - lua: None, + // lua: None, } } /// Similar to `new` but can reuse previously used container with allocated capacity. #[inline] - pub(crate) fn with_lua_and_capacity(lua: &'lua Lua, capacity: usize) -> MultiValue<'lua> { - let deque = lua - .pop_multivalue_from_pool() - .map(|mut deque| { - if capacity > 0 { - deque.reserve(capacity); - } - deque - }) - .unwrap_or_else(|| VecDeque::with_capacity(capacity)); + pub(crate) fn with_lua_and_capacity(_lua: &Lua, capacity: usize) -> MultiValue { + // FIXME + // let deque = lua + // .pop_multivalue_from_pool() + // .map(|mut deque| { + // if capacity > 0 { + // deque.reserve(capacity); + // } + // deque + // }) + // .unwrap_or_else(|| VecDeque::with_capacity(capacity)); + let deque = VecDeque::with_capacity(capacity); MultiValue { deque, - lua: Some(lua), + // lua: Some(lua), } } #[inline] pub(crate) fn extend_from_values( &mut self, - iter: impl IntoIterator<Item = Result<Value<'lua>>>, + iter: impl IntoIterator<Item = Result<Value>>, ) -> Result<()> { for value in iter { self.push_back(value?); @@ -825,17 +830,20 @@ impl<'lua> MultiValue<'lua> { } } -impl<'lua> FromIterator<Value<'lua>> for MultiValue<'lua> { +impl FromIterator<Value> for MultiValue { #[inline] - fn from_iter<I: IntoIterator<Item = Value<'lua>>>(iter: I) -> Self { + fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self { let deque = VecDeque::from_iter(iter); - MultiValue { deque, lua: None } + MultiValue { + deque, + // lua: None, + } } } -impl<'lua> IntoIterator for MultiValue<'lua> { - type Item = Value<'lua>; - type IntoIter = vec_deque::IntoIter<Value<'lua>>; +impl IntoIterator for MultiValue { + type Item = Value; + type IntoIter = vec_deque::IntoIter<Value>; #[inline] fn into_iter(mut self) -> Self::IntoIter { @@ -845,9 +853,9 @@ impl<'lua> IntoIterator for MultiValue<'lua> { } } -impl<'a, 'lua> IntoIterator for &'a MultiValue<'lua> { - type Item = &'a Value<'lua>; - type IntoIter = vec_deque::Iter<'a, Value<'lua>>; +impl<'a> IntoIterator for &'a MultiValue { + type Item = &'a Value; + type IntoIter = vec_deque::Iter<'a, Value>; #[inline] fn into_iter(self) -> Self::IntoIter { @@ -861,15 +869,15 @@ impl<'a, 'lua> IntoIterator for &'a MultiValue<'lua> { /// one. Any type that implements `IntoLua` will automatically implement this trait. pub trait IntoLuaMulti: Sized { /// Performs the conversion. - fn into_lua_multi(self, lua: &Lua) -> Result<MultiValue<'_>>; + fn into_lua_multi(self, lua: &Lua) -> Result<MultiValue>; /// Pushes the values into the Lua stack. /// /// Returns number of pushed values. #[doc(hidden)] #[inline] - unsafe fn push_into_stack_multi(self, lua: &Lua) -> Result<c_int> { - let values = self.into_lua_multi(lua)?; + unsafe fn push_into_stack_multi(self, lua: &LuaInner) -> Result<c_int> { + let values = self.into_lua_multi(lua.lua())?; let len: c_int = values.len().try_into().unwrap(); unsafe { check_stack(lua.state(), len + 1)?; @@ -885,14 +893,14 @@ pub trait IntoLuaMulti: Sized { /// /// This is a generalization of `FromLua`, allowing an arbitrary number of Lua values to participate /// in the conversion. Any type that implements `FromLua` will automatically implement this trait. -pub trait FromLuaMulti<'lua>: Sized { +pub trait FromLuaMulti: Sized { /// Performs the conversion. /// /// In case `values` contains more values than needed to perform the conversion, the excess /// values should be ignored. This reflects the semantics of Lua when calling a function or /// assigning values. Similarly, if not enough values are given, conversions should assume that /// any missing values are nil. - fn from_lua_multi(values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self>; + fn from_lua_multi(values: MultiValue, lua: &Lua) -> Result<Self>; /// Performs the conversion for a list of arguments. /// @@ -900,12 +908,7 @@ pub trait FromLuaMulti<'lua>: Sized { /// `to` is a function name that received the arguments. #[doc(hidden)] #[inline] - fn from_lua_args( - args: MultiValue<'lua>, - i: usize, - to: Option<&str>, - lua: &'lua Lua, - ) -> Result<Self> { + fn from_lua_args(args: MultiValue, i: usize, to: Option<&str>, lua: &Lua) -> Result<Self> { let _ = (i, to); Self::from_lua_multi(args, lua) } @@ -913,8 +916,8 @@ pub trait FromLuaMulti<'lua>: Sized { /// Performs the conversion for a number of values in the Lua stack. #[doc(hidden)] #[inline] - unsafe fn from_stack_multi(nvals: c_int, lua: &'lua Lua) -> Result<Self> { - let mut values = MultiValue::with_lua_and_capacity(lua, nvals as usize); + unsafe fn from_stack_multi(nvals: c_int, lua: &LuaInner) -> Result<Self> { + let mut values = MultiValue::with_lua_and_capacity(lua.lua(), nvals as usize); for idx in 0..nvals { values.push_back(lua.stack_value(-nvals + idx)); } @@ -922,7 +925,7 @@ pub trait FromLuaMulti<'lua>: Sized { // It's safe to clear the stack as all references moved to ref thread ffi::lua_pop(lua.state(), nvals); } - Self::from_lua_multi(values, lua) + Self::from_lua_multi(values, lua.lua()) } /// Same as `from_lua_args` but for a number of values in the Lua stack. @@ -932,7 +935,7 @@ pub trait FromLuaMulti<'lua>: Sized { nargs: c_int, i: usize, to: Option<&str>, - lua: &'lua Lua, + lua: &LuaInner, ) -> Result<Self> { let _ = (i, to); Self::from_stack_multi(nargs, lua) diff --git a/tests/async.rs b/tests/async.rs index 9c4c865..0fda52f 100644 --- a/tests/async.rs +++ b/tests/async.rs @@ -386,7 +386,7 @@ async fn test_async_userdata() -> Result<()> { struct MyUserData(u64); impl UserData for MyUserData { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { methods.add_async_method("get_value", |_, data, ()| async move { sleep_ms(10).await; Ok(data.0) @@ -488,7 +488,7 @@ async fn test_async_thread_error() -> Result<()> { struct MyUserData; impl UserData for MyUserData { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { methods.add_meta_method("__tostring", |_, _this, ()| Ok("myuserdata error")) } } @@ -507,24 +507,6 @@ async fn test_async_thread_error() -> Result<()> { Ok(()) } -#[cfg(all(feature = "unstable", not(feature = "send")))] -#[tokio::test] -async fn test_owned_async_call() -> Result<()> { - let lua = Lua::new(); - - let hello = lua - .create_async_function(|_, name: String| async move { - sleep_ms(10).await; - Ok(format!("hello, {}!", name)) - })? - .into_owned(); - drop(lua); - - assert_eq!(hello.call_async::<_, String>("alex").await?, "hello, alex!"); - - Ok(()) -} - #[tokio::test] async fn test_async_terminate() -> Result<()> { let lua = Lua::new(); diff --git a/tests/conversion.rs b/tests/conversion.rs index 5897d75..a0e0b38 100644 --- a/tests/conversion.rs +++ b/tests/conversion.rs @@ -43,35 +43,6 @@ fn test_string_into_lua() -> Result<()> { Ok(()) } -#[cfg(all(feature = "unstable", not(feature = "send")))] -#[test] -fn test_owned_string_into_lua() -> Result<()> { - let lua = Lua::new(); - - // Direct conversion - let s = lua.create_string("hello, world")?.into_owned(); - let s2 = (&s).into_lua(&lua)?; - assert_eq!(s.to_ref(), *s2.as_string().unwrap()); - - // Push into stack - let table = lua.create_table()?; - table.set("s", &s)?; - assert_eq!(s.to_ref(), table.get::<_, String>("s")?); - - Ok(()) -} - -#[cfg(all(feature = "unstable", not(feature = "send")))] -#[test] -fn test_owned_string_from_lua() -> Result<()> { - let lua = Lua::new(); - - let s = lua.unpack::<mlua::OwnedString>(lua.pack("hello, world")?)?; - assert_eq!(s.to_ref(), "hello, world"); - - Ok(()) -} - #[test] fn test_table_into_lua() -> Result<()> { let lua = Lua::new(); @@ -89,24 +60,6 @@ fn test_table_into_lua() -> Result<()> { Ok(()) } -#[cfg(all(feature = "unstable", not(feature = "send")))] -#[test] -fn test_owned_table_into_lua() -> Result<()> { - let lua = Lua::new(); - - // Direct conversion - let t = lua.create_table()?.into_owned(); - let t2 = (&t).into_lua(&lua)?; - assert_eq!(t.to_ref(), *t2.as_table().unwrap()); - - // Push into stack - let f = lua.create_function(|_, (t, s): (Table, String)| t.set("s", s))?; - f.call((&t, "hello"))?; - assert_eq!("hello", t.to_ref().get::<_, String>("s")?); - - Ok(()) -} - #[test] fn test_function_into_lua() -> Result<()> { let lua = Lua::new(); @@ -124,26 +77,6 @@ fn test_function_into_lua() -> Result<()> { Ok(()) } -#[cfg(all(feature = "unstable", not(feature = "send")))] -#[test] -fn test_owned_function_into_lua() -> Result<()> { - let lua = Lua::new(); - - // Direct conversion - let f = lua - .create_function(|_, ()| Ok::<_, Error>(()))? - .into_owned(); - let f2 = (&f).into_lua(&lua)?; - assert_eq!(f.to_ref(), *f2.as_function().unwrap()); - - // Push into stack - let table = lua.create_table()?; - table.set("f", &f)?; - assert_eq!(f.to_ref(), table.get::<_, Function>("f")?); - - Ok(()) -} - #[test] fn test_thread_into_lua() -> Result<()> { let lua = Lua::new(); @@ -162,36 +95,6 @@ fn test_thread_into_lua() -> Result<()> { Ok(()) } -#[cfg(all(feature = "unstable", not(feature = "send")))] -#[test] -fn test_owned_thread_into_lua() -> Result<()> { - let lua = Lua::new(); - - // Direct conversion - let f = lua.create_function(|_, ()| Ok::<_, Error>(()))?; - let th = lua.create_thread(f)?.into_owned(); - let th2 = (&th).into_lua(&lua)?; - assert_eq!(&th.to_ref(), th2.as_thread().unwrap()); - - // Push into stack - let table = lua.create_table()?; - table.set("th", &th)?; - assert_eq!(th.to_ref(), table.get::<_, Thread>("th")?); - - Ok(()) -} - -#[cfg(all(feature = "unstable", not(feature = "send")))] -#[test] -fn test_owned_thread_from_lua() -> Result<()> { - let lua = Lua::new(); - - let th = lua.unpack::<mlua::OwnedThread>(Value::Thread(lua.current_thread()))?; - assert_eq!(th.to_ref(), lua.current_thread()); - - Ok(()) -} - #[test] fn test_anyuserdata_into_lua() -> Result<()> { let lua = Lua::new(); @@ -210,25 +113,6 @@ fn test_anyuserdata_into_lua() -> Result<()> { Ok(()) } -#[cfg(all(feature = "unstable", not(feature = "send")))] -#[test] -fn test_owned_anyuserdata_into_lua() -> Result<()> { - let lua = Lua::new(); - - // Direct conversion - let ud = lua.create_any_userdata(String::from("hello"))?.into_owned(); - let ud2 = (&ud).into_lua(&lua)?; - assert_eq!(ud.to_ref(), *ud2.as_userdata().unwrap()); - - // Push into stack - let table = lua.create_table()?; - table.set("ud", &ud)?; - assert_eq!(ud.to_ref(), table.get::<_, AnyUserData>("ud")?); - assert_eq!("hello", *table.get::<_, UserDataRef<String>>("ud")?); - - Ok(()) -} - #[test] fn test_registry_value_into_lua() -> Result<()> { let lua = Lua::new(); diff --git a/tests/function.rs b/tests/function.rs index c95b012..c7596be 100644 --- a/tests/function.rs +++ b/tests/function.rs @@ -296,45 +296,3 @@ fn test_function_wrap() -> Result<()> { Ok(()) } - -#[cfg(all(feature = "unstable", not(feature = "send")))] -#[test] -fn test_owned_function() -> Result<()> { - let lua = Lua::new(); - - let f = lua - .create_function(|_, ()| Ok("hello, world!"))? - .into_owned(); - drop(lua); - - // We still should be able to call the function despite Lua is dropped - let s = f.call::<_, String>(())?; - assert_eq!(s.to_string_lossy(), "hello, world!"); - - Ok(()) -} - -#[cfg(all(feature = "unstable", not(feature = "send")))] -#[test] -fn test_owned_function_drop() -> Result<()> { - let rc = std::sync::Arc::new(()); - - { - let lua = Lua::new(); - - lua.set_app_data(rc.clone()); - - let f1 = lua - .create_function(|_, ()| Ok("hello, world!"))? - .into_owned(); - let f2 = - lua.create_function(move |_, ()| f1.to_ref().call::<_, std::string::String>(()))?; - assert_eq!(f2.call::<_, String>(())?.to_string_lossy(), "hello, world!"); - } - - // Check that Lua is properly destroyed - // It works because we collect garbage when Lua goes out of scope - assert_eq!(std::sync::Arc::strong_count(&rc), 1); - - Ok(()) -} diff --git a/tests/scope.rs b/tests/scope.rs.1 index b04b7b5..b04b7b5 100644 --- a/tests/scope.rs +++ b/tests/scope.rs.1 diff --git a/tests/serde.rs b/tests/serde.rs index 11c1d71..5dc4bd8 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -71,49 +71,49 @@ fn test_serialize() -> Result<(), Box<dyn StdError>> { Ok(()) } -#[test] -fn test_serialize_in_scope() -> LuaResult<()> { - #[derive(Serialize, Clone)] - struct MyUserData(i64, String); - - impl UserData for MyUserData {} - - let lua = Lua::new(); - lua.scope(|scope| { - let ud = scope.create_ser_userdata(MyUserData(-5, "test userdata".into()))?; - assert_eq!( - serde_json::to_value(&ud).unwrap(), - serde_json::json!((-5, "test userdata")) - ); - Ok(()) - })?; - - lua.scope(|scope| { - let ud = scope.create_ser_userdata(MyUserData(-5, "test userdata".into()))?; - lua.globals().set("ud", ud) - })?; - let val = lua.load("ud").eval::<Value>()?; - match serde_json::to_value(&val) { - Ok(v) => panic!("expected destructed error, got {}", v), - Err(e) if e.to_string().contains("destructed") => {} - Err(e) => panic!("expected destructed error, got {}", e), - } - - struct MyUserDataRef<'a>(#[allow(unused)] &'a ()); - - impl<'a> UserData for MyUserDataRef<'a> {} - - lua.scope(|scope| { - let ud = scope.create_nonstatic_userdata(MyUserDataRef(&()))?; - match serde_json::to_value(&ud) { - Ok(v) => panic!("expected serialization error, got {}", v), - Err(serde_json::Error { .. }) => {} - }; - Ok(()) - })?; - - Ok(()) -} +// #[test] +// fn test_serialize_in_scope() -> LuaResult<()> { +// #[derive(Serialize, Clone)] +// struct MyUserData(i64, String); + +// impl UserData for MyUserData {} + +// let lua = Lua::new(); +// lua.scope(|scope| { +// let ud = scope.create_ser_userdata(MyUserData(-5, "test userdata".into()))?; +// assert_eq!( +// serde_json::to_value(&ud).unwrap(), +// serde_json::json!((-5, "test userdata")) +// ); +// Ok(()) +// })?; + +// lua.scope(|scope| { +// let ud = scope.create_ser_userdata(MyUserData(-5, "test userdata".into()))?; +// lua.globals().set("ud", ud) +// })?; +// let val = lua.load("ud").eval::<Value>()?; +// match serde_json::to_value(&val) { +// Ok(v) => panic!("expected destructed error, got {}", v), +// Err(e) if e.to_string().contains("destructed") => {} +// Err(e) => panic!("expected destructed error, got {}", e), +// } + +// struct MyUserDataRef<'a>(#[allow(unused)] &'a ()); + +// impl<'a> UserData for MyUserDataRef<'a> {} + +// lua.scope(|scope| { +// let ud = scope.create_nonstatic_userdata(MyUserDataRef(&()))?; +// match serde_json::to_value(&ud) { +// Ok(v) => panic!("expected serialization error, got {}", v), +// Err(serde_json::Error { .. }) => {} +// }; +// Ok(()) +// })?; + +// Ok(()) +// } #[test] fn test_serialize_any_userdata() -> Result<(), Box<dyn StdError>> { diff --git a/tests/static.rs b/tests/static.rs index 92164d7..7f6e028 100644 --- a/tests/static.rs +++ b/tests/static.rs @@ -7,7 +7,7 @@ fn test_static_lua() -> Result<()> { let lua = Lua::new().into_static(); thread_local! { - static TABLE: RefCell<Option<Table<'static>>> = RefCell::new(None); + static TABLE: RefCell<Option<Table>> = RefCell::new(None); } let f = lua.create_function(|_, table: Table| { @@ -38,7 +38,7 @@ fn test_static_lua_coroutine() -> Result<()> { let lua = Lua::new().into_static(); thread_local! { - static TABLE: RefCell<Option<Table<'static>>> = RefCell::new(None); + static TABLE: RefCell<Option<Table>> = RefCell::new(None); } let f = lua.create_function(|_, table: Table| { diff --git a/tests/string.rs b/tests/string.rs index ad06c5f..289e3ea 100644 --- a/tests/string.rs +++ b/tests/string.rs @@ -111,22 +111,3 @@ fn test_string_pointer() -> Result<()> { Ok(()) } - -#[cfg(all(feature = "unstable", not(feature = "send")))] -#[test] -fn test_owned_string() -> Result<()> { - let lua = Lua::new(); - - let s = lua.create_string("hello, world!")?.into_owned(); - drop(lua); - - // Shortcuts - assert_eq!(s.as_bytes(), b"hello, world!"); - assert_eq!(s.to_str()?, "hello, world!"); - assert_eq!(format!("{s:?}"), "\"hello, world!\""); - - // Access via reference - assert_eq!(s.to_ref().to_string_lossy(), "hello, world!"); - - Ok(()) -} diff --git a/tests/table.rs b/tests/table.rs index 04885fc..cdbb122 100644 --- a/tests/table.rs +++ b/tests/table.rs @@ -455,17 +455,3 @@ fn test_table_call() -> Result<()> { Ok(()) } - -#[cfg(all(feature = "unstable", not(feature = "send")))] -#[test] -fn test_owned_table() -> Result<()> { - let lua = Lua::new(); - - let table = lua.create_table()?.into_owned(); - drop(lua); - - table.to_ref().set("abc", 123)?; - assert_eq!(table.to_ref().get::<_, i64>("abc")?, 123); - - Ok(()) -} diff --git a/tests/thread.rs b/tests/thread.rs index 2bc1988..81f14e0 100644 --- a/tests/thread.rs +++ b/tests/thread.rs @@ -231,34 +231,3 @@ fn test_thread_pointer() -> Result<()> { Ok(()) } - -#[cfg(all(feature = "unstable", not(feature = "send")))] -#[test] -fn test_owned_thread() -> Result<()> { - let lua = Lua::new(); - - let accumulate = lua - .create_thread( - lua.load( - r#" - function (sum) - while true do - sum = sum + coroutine.yield(sum) - end - end - "#, - ) - .eval::<Function>()?, - )? - .into_owned(); - - for i in 0..4 { - accumulate.resume::<_, ()>(i)?; - } - assert_eq!(accumulate.resume::<_, i64>(4)?, 10); - assert_eq!(accumulate.status(), ThreadStatus::Resumable); - assert!(accumulate.resume::<_, ()>("error").is_err()); - assert_eq!(accumulate.status(), ThreadStatus::Error); - - Ok(()) -} diff --git a/tests/userdata.rs b/tests/userdata.rs index 7d5b623..fd22ec3 100644 --- a/tests/userdata.rs +++ b/tests/userdata.rs @@ -47,7 +47,7 @@ fn test_methods() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { methods.add_method("get_value", |_, data, ()| Ok(data.0)); methods.add_method_mut("set_value", |_, data, args| { data.0 = args; @@ -97,7 +97,7 @@ fn test_method_variadic() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { methods.add_method("get", |_, data, ()| Ok(data.0)); methods.add_method_mut("add", |_, data, vals: Variadic<i64>| { data.0 += vals.into_iter().sum::<i64>(); @@ -122,7 +122,7 @@ fn test_metamethods() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { methods.add_method("get", |_, data, ()| Ok(data.0)); methods.add_meta_function( MetaMethod::Add, @@ -241,7 +241,7 @@ fn test_metamethod_close() -> Result<()> { struct MyUserData(Arc<AtomicI64>); impl UserData for MyUserData { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: UserDataMethods<'a, Self>>(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); @@ -287,7 +287,7 @@ fn test_gc_userdata() -> Result<()> { } impl UserData for MyUserdata { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { methods.add_method("access", |_, this, ()| { assert!(this.id == 123); Ok(()) @@ -326,7 +326,7 @@ fn test_userdata_take() -> Result<()> { struct MyUserdata(Arc<i64>); impl UserData for MyUserdata { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { methods.add_method("num", |_, this, ()| Ok(*this.0)) } } @@ -461,7 +461,7 @@ fn test_functions() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { methods.add_function("get_value", |_, ud: AnyUserData| { Ok(ud.borrow::<MyUserData>()?.0) }); @@ -515,7 +515,7 @@ fn test_fields() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + fn add_fields<'a, F: UserDataFields<'a, Self>>(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| { @@ -562,12 +562,12 @@ fn test_fields() -> Result<()> { struct MyUserData2(i64); impl UserData for MyUserData2 { - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) { fields.add_field("z", 0); fields.add_field_method_get("x", |_, data| Ok(data.0)); } - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { methods.add_meta_method(MetaMethod::Index, |_, _, name: StdString| match &*name { "y" => Ok(Some(-1)), _ => Ok(None), @@ -594,7 +594,7 @@ fn test_metatable() -> Result<()> { struct MyUserData; impl UserData for MyUserData { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { methods.add_function("my_type_name", |_, data: AnyUserData| { let metatable = data.get_metatable()?; metatable.get::<String>(MetaMethod::Type) @@ -640,7 +640,7 @@ fn test_metatable() -> Result<()> { struct MyUserData2; impl UserData for MyUserData2 { - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) { fields.add_meta_field_with("__index", |_| Ok(1)); } } @@ -655,7 +655,7 @@ fn test_metatable() -> Result<()> { struct MyUserData3; impl UserData for MyUserData3 { - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) { fields.add_meta_field_with(MetaMethod::Type, |_| Ok("CustomName")); } } @@ -671,11 +671,12 @@ fn test_metatable() -> Result<()> { } #[test] +#[ignore = "this functionality is deprecated"] fn test_userdata_wrapped() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) { fields.add_field("static", "constant"); fields.add_field_method_get("data", |_, this| Ok(this.0)); fields.add_field_method_set("data", |_, this, val| { @@ -794,12 +795,12 @@ fn test_userdata_proxy() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) { fields.add_field("static_field", 123); fields.add_field_method_get("n", |_, this| Ok(this.0)); } - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { methods.add_function("new", |_, n| Ok(Self(n))); methods.add_method("plus", |_, this, n: i64| Ok(this.0 + n)); @@ -888,7 +889,7 @@ fn test_userdata_ext() -> Result<()> { struct MyUserData(u32); impl UserData for MyUserData { - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + fn add_fields<'a, F: UserDataFields<'a, Self>>(fields: &mut F) { fields.add_field_method_get("n", |_, this| Ok(this.0)); fields.add_field_method_set("n", |_, this, val| { this.0 = val; @@ -896,7 +897,7 @@ fn test_userdata_ext() -> Result<()> { }); } - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { methods.add_meta_method(MetaMethod::Call, |_, _this, ()| Ok("called")); methods.add_method_mut("add", |_, this, x: u32| { this.0 += x; @@ -929,7 +930,7 @@ fn test_userdata_method_errors() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'a, M: UserDataMethods<'a, Self>>(methods: &mut M) { methods.add_method("get_value", |_, data, ()| Ok(data.0)); } } @@ -967,25 +968,6 @@ fn test_userdata_pointer() -> Result<()> { Ok(()) } -#[cfg(all(feature = "unstable", not(feature = "send")))] -#[test] -fn test_owned_userdata() -> Result<()> { - let lua = Lua::new(); - - let ud = lua.create_any_userdata("abc")?.into_owned(); - drop(lua); - - assert_eq!(*ud.borrow::<&str>()?, "abc"); - *ud.borrow_mut()? = "cba"; - assert!(matches!( - ud.borrow::<i64>(), - Err(Error::UserDataTypeMismatch) - )); - assert_eq!(ud.take::<&str>()?, "cba"); - - Ok(()) -} - #[cfg(feature = "macros")] #[test] fn test_userdata_derive() -> Result<()> { |