Add Send capability to Lua
This commit is contained in:
parent
6e2bb73cff
commit
7b0e4b4280
|
@ -1,26 +1,25 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use bstr::BString;
|
||||
use hyper::{body::Body as HyperBody, Client as HyperClient};
|
||||
use tokio::stream::StreamExt;
|
||||
use tokio::{stream::StreamExt, sync::Mutex};
|
||||
|
||||
use mlua::{Error, Lua, Result, UserData, UserDataMethods};
|
||||
|
||||
#[derive(Clone)]
|
||||
struct BodyReader(Rc<RefCell<HyperBody>>);
|
||||
struct BodyReader(Arc<Mutex<HyperBody>>);
|
||||
|
||||
impl BodyReader {
|
||||
fn new(body: HyperBody) -> Self {
|
||||
BodyReader(Rc::new(RefCell::new(body)))
|
||||
BodyReader(Arc::new(Mutex::new(body)))
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for BodyReader {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_async_method("read", |_, reader, ()| async move {
|
||||
let mut reader = reader.0.borrow_mut();
|
||||
let mut reader = reader.0.lock().await;
|
||||
let bytes = reader.try_next().await.map_err(Error::external)?;
|
||||
if let Some(bytes) = bytes {
|
||||
return Ok(Some(BString::from(bytes.as_ref())));
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use std::cell::RefCell;
|
||||
use std::net::Shutdown;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use bstr::BString;
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::prelude::*;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::task;
|
||||
|
||||
use mlua::{Function, Lua, Result, UserData, UserDataMethods};
|
||||
|
@ -13,16 +13,16 @@ use mlua::{Function, Lua, Result, UserData, UserDataMethods};
|
|||
struct LuaTcp;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct LuaTcpListener(Rc<RefCell<TcpListener>>);
|
||||
struct LuaTcpListener(Arc<Mutex<TcpListener>>);
|
||||
|
||||
#[derive(Clone)]
|
||||
struct LuaTcpStream(Rc<RefCell<TcpStream>>);
|
||||
struct LuaTcpStream(Arc<Mutex<TcpStream>>);
|
||||
|
||||
impl UserData for LuaTcp {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_async_function("bind", |_, addr: String| async move {
|
||||
let listener = TcpListener::bind(addr).await?;
|
||||
Ok(LuaTcpListener(Rc::new(RefCell::new(listener))))
|
||||
Ok(LuaTcpListener(Arc::new(Mutex::new(listener))))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -30,8 +30,8 @@ impl UserData for LuaTcp {
|
|||
impl UserData for LuaTcpListener {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_async_method("accept", |_, listener, ()| async move {
|
||||
let (stream, _) = listener.0.borrow_mut().accept().await?;
|
||||
Ok(LuaTcpStream(Rc::new(RefCell::new(stream))))
|
||||
let (stream, _) = listener.0.lock().await.accept().await?;
|
||||
Ok(LuaTcpStream(Arc::new(Mutex::new(stream))))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -39,23 +39,23 @@ impl UserData for LuaTcpListener {
|
|||
impl UserData for LuaTcpStream {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_async_method("peer_addr", |_, stream, ()| async move {
|
||||
Ok(stream.0.borrow().peer_addr()?.to_string())
|
||||
Ok(stream.0.lock().await.peer_addr()?.to_string())
|
||||
});
|
||||
|
||||
methods.add_async_method("read", |_, stream, size: usize| async move {
|
||||
let mut buf = vec![0; size];
|
||||
let n = stream.0.borrow_mut().read(&mut buf).await?;
|
||||
let n = stream.0.lock().await.read(&mut buf).await?;
|
||||
buf.truncate(n);
|
||||
Ok(BString::from(buf))
|
||||
});
|
||||
|
||||
methods.add_async_method("write", |_, stream, data: BString| async move {
|
||||
let n = stream.0.borrow_mut().write(&data).await?;
|
||||
let n = stream.0.lock().await.write(&data).await?;
|
||||
Ok(n)
|
||||
});
|
||||
|
||||
methods.add_method("close", |_, stream, ()| {
|
||||
stream.0.borrow().shutdown(Shutdown::Both)?;
|
||||
methods.add_async_method("close", |_, stream, ()| async move {
|
||||
stream.0.lock().await.shutdown(Shutdown::Both)?;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ impl<'lua> FromLua<'lua> for AnyUserData<'lua> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: 'static + UserData> ToLua<'lua> for T {
|
||||
impl<'lua, T: 'static + Send + UserData> ToLua<'lua> for T {
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::UserData(lua.create_userdata(self)?))
|
||||
}
|
||||
|
|
10
src/error.rs
10
src/error.rs
|
@ -2,10 +2,10 @@ use std::error::Error as StdError;
|
|||
use std::fmt;
|
||||
use std::io::Error as IoError;
|
||||
use std::net::AddrParseError;
|
||||
use std::rc::Rc;
|
||||
use std::result::Result as StdResult;
|
||||
use std::str::Utf8Error;
|
||||
use std::string::String as StdString;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Error type returned by `mlua` methods.
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -118,7 +118,7 @@ pub enum Error {
|
|||
/// Lua call stack backtrace.
|
||||
traceback: StdString,
|
||||
/// Original error returned by the Rust code.
|
||||
cause: Rc<Error>,
|
||||
cause: Arc<Error>,
|
||||
},
|
||||
/// A custom error.
|
||||
///
|
||||
|
@ -127,7 +127,7 @@ pub enum Error {
|
|||
/// Returning `Err(ExternalError(...))` from a Rust callback will raise the error as a Lua
|
||||
/// error. The Rust code that originally invoked the Lua code then receives a `CallbackError`,
|
||||
/// from which the original error (and a stack traceback) can be recovered.
|
||||
ExternalError(Rc<dyn StdError>),
|
||||
ExternalError(Arc<dyn StdError + Send + Sync>),
|
||||
}
|
||||
|
||||
/// A specialized `Result` type used by `mlua`'s API.
|
||||
|
@ -206,7 +206,7 @@ impl StdError for Error {
|
|||
}
|
||||
|
||||
impl Error {
|
||||
pub fn external<T: Into<Box<dyn StdError>>>(err: T) -> Error {
|
||||
pub fn external<T: Into<Box<dyn StdError + Send + Sync>>>(err: T) -> Error {
|
||||
Error::ExternalError(err.into().into())
|
||||
}
|
||||
}
|
||||
|
@ -217,7 +217,7 @@ pub trait ExternalError {
|
|||
|
||||
impl<E> ExternalError for E
|
||||
where
|
||||
E: Into<Box<dyn StdError>>,
|
||||
E: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
fn to_lua_err(self) -> Error {
|
||||
Error::external(self)
|
||||
|
|
89
src/lua.rs
89
src/lua.rs
|
@ -4,7 +4,7 @@ use std::collections::HashMap;
|
|||
use std::ffi::CString;
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::{c_char, c_int};
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{mem, ptr, str};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
|
@ -39,7 +39,7 @@ use {
|
|||
pub struct Lua {
|
||||
pub(crate) state: *mut ffi::lua_State,
|
||||
main_state: *mut ffi::lua_State,
|
||||
extra: Rc<RefCell<ExtraData>>,
|
||||
extra: Arc<Mutex<ExtraData>>,
|
||||
ephemeral: bool,
|
||||
// Lua has lots of interior mutability, should not be RefUnwindSafe
|
||||
_no_ref_unwind_safe: PhantomData<UnsafeCell<()>>,
|
||||
|
@ -48,7 +48,7 @@ pub struct Lua {
|
|||
// Data associated with the lua_State.
|
||||
struct ExtraData {
|
||||
registered_userdata: HashMap<TypeId, c_int>,
|
||||
registry_unref_list: Rc<RefCell<Option<Vec<c_int>>>>,
|
||||
registry_unref_list: Arc<Mutex<Option<Vec<c_int>>>>,
|
||||
|
||||
ref_thread: *mut ffi::lua_State,
|
||||
ref_stack_size: c_int,
|
||||
|
@ -56,6 +56,8 @@ struct ExtraData {
|
|||
ref_free: Vec<c_int>,
|
||||
}
|
||||
|
||||
unsafe impl Send for Lua {}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub(crate) struct AsyncPollPending;
|
||||
#[cfg(feature = "async")]
|
||||
|
@ -65,16 +67,13 @@ impl Drop for Lua {
|
|||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if !self.ephemeral {
|
||||
let mut extra = self.extra.borrow_mut();
|
||||
let mut extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
|
||||
mlua_debug_assert!(
|
||||
ffi::lua_gettop(extra.ref_thread) == extra.ref_stack_max
|
||||
&& extra.ref_stack_max as usize == extra.ref_free.len(),
|
||||
"reference leak detected"
|
||||
);
|
||||
*mlua_expect!(
|
||||
extra.registry_unref_list.try_borrow_mut(),
|
||||
"unref list borrowed"
|
||||
) = None;
|
||||
*mlua_expect!(extra.registry_unref_list.lock(), "unref list poisoned") = None;
|
||||
ffi::lua_close(self.main_state);
|
||||
}
|
||||
}
|
||||
|
@ -184,9 +183,9 @@ impl Lua {
|
|||
|
||||
// Create ExtraData
|
||||
|
||||
let extra = Rc::new(RefCell::new(ExtraData {
|
||||
let extra = Arc::new(Mutex::new(ExtraData {
|
||||
registered_userdata: HashMap::new(),
|
||||
registry_unref_list: Rc::new(RefCell::new(Some(Vec::new()))),
|
||||
registry_unref_list: Arc::new(Mutex::new(Some(Vec::new()))),
|
||||
ref_thread,
|
||||
// We need 1 extra stack space to move values in and out of the ref stack.
|
||||
ref_stack_size: ffi::LUA_MINSTACK - 1,
|
||||
|
@ -216,7 +215,7 @@ impl Lua {
|
|||
where
|
||||
'lua: 'callback,
|
||||
R: ToLua<'callback>,
|
||||
F: 'static + Fn(&'callback Lua) -> Result<R>,
|
||||
F: 'static + Send + Fn(&'callback Lua) -> Result<R>,
|
||||
{
|
||||
let cb = self.create_callback(Box::new(move |lua, _| func(lua)?.to_lua_multi(lua)))?;
|
||||
unsafe { self.push_value(cb.call(())?).map(|_| 1) }
|
||||
|
@ -474,7 +473,7 @@ impl Lua {
|
|||
'lua: 'callback,
|
||||
A: FromLuaMulti<'callback>,
|
||||
R: ToLuaMulti<'callback>,
|
||||
F: 'static + Fn(&'callback Lua, A) -> Result<R>,
|
||||
F: 'static + Send + Fn(&'callback Lua, A) -> Result<R>,
|
||||
{
|
||||
self.create_callback(Box::new(move |lua, args| {
|
||||
func(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
|
@ -495,7 +494,7 @@ impl Lua {
|
|||
'lua: 'callback,
|
||||
A: FromLuaMulti<'callback>,
|
||||
R: ToLuaMulti<'callback>,
|
||||
F: 'static + FnMut(&'callback Lua, A) -> Result<R>,
|
||||
F: 'static + Send + FnMut(&'callback Lua, A) -> Result<R>,
|
||||
{
|
||||
let func = RefCell::new(func);
|
||||
self.create_function(move |lua, args| {
|
||||
|
@ -552,7 +551,7 @@ impl Lua {
|
|||
'lua: 'callback,
|
||||
A: FromLuaMulti<'callback>,
|
||||
R: ToLuaMulti<'callback>,
|
||||
F: 'static + Fn(&'callback Lua, A) -> FR,
|
||||
F: 'static + Send + Fn(&'callback Lua, A) -> FR,
|
||||
FR: 'lua + Future<Output = Result<R>>,
|
||||
{
|
||||
self.create_async_callback(Box::new(move |lua, args| {
|
||||
|
@ -584,7 +583,7 @@ impl Lua {
|
|||
/// Create a Lua userdata object from a custom userdata type.
|
||||
pub fn create_userdata<T>(&self, data: T) -> Result<AnyUserData>
|
||||
where
|
||||
T: 'static + UserData,
|
||||
T: 'static + Send + UserData,
|
||||
{
|
||||
unsafe { self.make_userdata(data) }
|
||||
}
|
||||
|
@ -791,9 +790,11 @@ impl Lua {
|
|||
ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
|
||||
})?;
|
||||
|
||||
let extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
|
||||
|
||||
Ok(RegistryKey {
|
||||
registry_id,
|
||||
unref_list: self.extra.borrow().registry_unref_list.clone(),
|
||||
unref_list: extra.registry_unref_list.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -850,7 +851,8 @@ 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 {
|
||||
Rc::ptr_eq(&key.unref_list, &self.extra.borrow().registry_unref_list)
|
||||
let extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
|
||||
Arc::ptr_eq(&key.unref_list, &extra.registry_unref_list)
|
||||
}
|
||||
|
||||
/// Remove any registry values whose `RegistryKey`s have all been dropped.
|
||||
|
@ -860,11 +862,9 @@ impl Lua {
|
|||
/// by `Lua::remove_registry_value`.
|
||||
pub fn expire_registry_values(&self) {
|
||||
unsafe {
|
||||
let mut extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
|
||||
let unref_list = mem::replace(
|
||||
&mut *mlua_expect!(
|
||||
self.extra.borrow().registry_unref_list.try_borrow_mut(),
|
||||
"unref list borrowed"
|
||||
),
|
||||
&mut *mlua_expect!(extra.registry_unref_list.lock(), "unref list poisoned"),
|
||||
Some(Vec::new()),
|
||||
);
|
||||
for id in mlua_expect!(unref_list, "unref list not set") {
|
||||
|
@ -986,7 +986,7 @@ impl Lua {
|
|||
lref.lua.main_state == self.main_state,
|
||||
"Lua instance passed Value created from a different main Lua state"
|
||||
);
|
||||
let extra = self.extra.borrow();
|
||||
let extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
|
||||
ffi::lua_pushvalue(extra.ref_thread, lref.index);
|
||||
ffi::lua_xmove(extra.ref_thread, self.state, 1);
|
||||
}
|
||||
|
@ -1001,7 +1001,7 @@ impl Lua {
|
|||
// number of short term references being created, and `RegistryKey` being used for long term
|
||||
// references.
|
||||
pub(crate) unsafe fn pop_ref<'lua>(&'lua self) -> LuaRef<'lua> {
|
||||
let mut extra = self.extra.borrow_mut();
|
||||
let mut extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
|
||||
ffi::lua_xmove(self.state, extra.ref_thread, 1);
|
||||
let index = ref_stack_pop(&mut extra);
|
||||
LuaRef { lua: self, index }
|
||||
|
@ -1009,7 +1009,7 @@ impl Lua {
|
|||
|
||||
pub(crate) fn clone_ref<'lua>(&'lua self, lref: &LuaRef<'lua>) -> LuaRef<'lua> {
|
||||
unsafe {
|
||||
let mut extra = self.extra.borrow_mut();
|
||||
let mut extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
|
||||
ffi::lua_pushvalue(extra.ref_thread, lref.index);
|
||||
let index = ref_stack_pop(&mut extra);
|
||||
LuaRef { lua: self, index }
|
||||
|
@ -1018,7 +1018,7 @@ impl Lua {
|
|||
|
||||
pub(crate) fn drop_ref<'lua>(&'lua self, lref: &mut LuaRef<'lua>) {
|
||||
unsafe {
|
||||
let mut extra = self.extra.borrow_mut();
|
||||
let mut extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
|
||||
ffi::lua_pushnil(extra.ref_thread);
|
||||
ffi::lua_replace(extra.ref_thread, lref.index);
|
||||
extra.ref_free.push(lref.index);
|
||||
|
@ -1026,9 +1026,7 @@ impl Lua {
|
|||
}
|
||||
|
||||
pub(crate) unsafe fn userdata_metatable<T: 'static + UserData>(&self) -> Result<c_int> {
|
||||
if let Some(table_id) = self
|
||||
.extra
|
||||
.borrow()
|
||||
if let Some(table_id) = mlua_expect!(self.extra.lock(), "extra is poisoned")
|
||||
.registered_userdata
|
||||
.get(&TypeId::of::<T>())
|
||||
{
|
||||
|
@ -1088,8 +1086,7 @@ impl Lua {
|
|||
ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX)
|
||||
})?;
|
||||
|
||||
self.extra
|
||||
.borrow_mut()
|
||||
mlua_expect!(self.extra.lock(), "extra is poisoned")
|
||||
.registered_userdata
|
||||
.insert(TypeId::of::<T>(), id);
|
||||
|
||||
|
@ -1613,7 +1610,7 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
|
|||
S: ?Sized + AsRef<[u8]>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + Fn(&'lua Lua, &T, A) -> Result<R>,
|
||||
M: 'static + Send + Fn(&'lua Lua, &T, A) -> Result<R>,
|
||||
{
|
||||
self.methods
|
||||
.push((name.as_ref().to_vec(), Self::box_method(method)));
|
||||
|
@ -1624,7 +1621,7 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
|
|||
S: ?Sized + AsRef<[u8]>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
||||
M: 'static + Send + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
||||
{
|
||||
self.methods
|
||||
.push((name.as_ref().to_vec(), Self::box_method_mut(method)));
|
||||
|
@ -1637,7 +1634,7 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
|
|||
S: ?Sized + AsRef<[u8]>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + Fn(&'lua Lua, T, A) -> MR,
|
||||
M: 'static + Send + Fn(&'lua Lua, T, A) -> MR,
|
||||
MR: 'lua + Future<Output = Result<R>>,
|
||||
{
|
||||
self.async_methods
|
||||
|
@ -1649,7 +1646,7 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
|
|||
S: ?Sized + AsRef<[u8]>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + Fn(&'lua Lua, A) -> Result<R>,
|
||||
F: 'static + Send + Fn(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
self.methods
|
||||
.push((name.as_ref().to_vec(), Self::box_function(function)));
|
||||
|
@ -1660,7 +1657,7 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
|
|||
S: ?Sized + AsRef<[u8]>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + FnMut(&'lua Lua, A) -> Result<R>,
|
||||
F: 'static + Send + FnMut(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
self.methods
|
||||
.push((name.as_ref().to_vec(), Self::box_function_mut(function)));
|
||||
|
@ -1673,7 +1670,7 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
|
|||
S: ?Sized + AsRef<[u8]>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + Fn(&'lua Lua, A) -> FR,
|
||||
F: 'static + Send + Fn(&'lua Lua, A) -> FR,
|
||||
FR: 'lua + Future<Output = Result<R>>,
|
||||
{
|
||||
self.async_methods
|
||||
|
@ -1684,7 +1681,7 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
|
|||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + Fn(&'lua Lua, &T, A) -> Result<R>,
|
||||
M: 'static + Send + Fn(&'lua Lua, &T, A) -> Result<R>,
|
||||
{
|
||||
self.meta_methods.push((meta, Self::box_method(method)));
|
||||
}
|
||||
|
@ -1693,7 +1690,7 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
|
|||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
||||
M: 'static + Send + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
||||
{
|
||||
self.meta_methods.push((meta, Self::box_method_mut(method)));
|
||||
}
|
||||
|
@ -1702,7 +1699,7 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
|
|||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + Fn(&'lua Lua, A) -> Result<R>,
|
||||
F: 'static + Send + Fn(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
self.meta_methods.push((meta, Self::box_function(function)));
|
||||
}
|
||||
|
@ -1711,7 +1708,7 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
|
|||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + FnMut(&'lua Lua, A) -> Result<R>,
|
||||
F: 'static + Send + FnMut(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
self.meta_methods
|
||||
.push((meta, Self::box_function_mut(function)));
|
||||
|
@ -1723,7 +1720,7 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
|
|||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + Fn(&'lua Lua, &T, A) -> Result<R>,
|
||||
M: 'static + Send + Fn(&'lua Lua, &T, A) -> Result<R>,
|
||||
{
|
||||
Box::new(move |lua, mut args| {
|
||||
if let Some(front) = args.pop_front() {
|
||||
|
@ -1744,7 +1741,7 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
|
|||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
||||
M: 'static + Send + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
||||
{
|
||||
let method = RefCell::new(method);
|
||||
Box::new(move |lua, mut args| {
|
||||
|
@ -1771,7 +1768,7 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
|
|||
T: Clone,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + Fn(&'lua Lua, T, A) -> MR,
|
||||
M: 'static + Send + Fn(&'lua Lua, T, A) -> MR,
|
||||
MR: 'lua + Future<Output = Result<R>>,
|
||||
{
|
||||
Box::new(move |lua, mut args| {
|
||||
|
@ -1799,7 +1796,7 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
|
|||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + Fn(&'lua Lua, A) -> Result<R>,
|
||||
F: 'static + Send + Fn(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
Box::new(move |lua, args| function(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua))
|
||||
}
|
||||
|
@ -1808,7 +1805,7 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
|
|||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + FnMut(&'lua Lua, A) -> Result<R>,
|
||||
F: 'static + Send + FnMut(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
let function = RefCell::new(function);
|
||||
Box::new(move |lua, args| {
|
||||
|
@ -1824,7 +1821,7 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
|
|||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + Fn(&'lua Lua, A) -> FR,
|
||||
F: 'static + Send + Fn(&'lua Lua, A) -> FR,
|
||||
FR: 'lua + Future<Output = Result<R>>,
|
||||
{
|
||||
Box::new(move |lua, args| {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::cell::RefCell;
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{fmt, mem, ptr};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
|
@ -45,7 +44,7 @@ pub(crate) type AsyncCallback<'lua, 'a> =
|
|||
/// [`UserData::get_user_value`]: struct.UserData.html#method.get_user_value
|
||||
pub struct RegistryKey {
|
||||
pub(crate) registry_id: c_int,
|
||||
pub(crate) unref_list: Rc<RefCell<Option<Vec<c_int>>>>,
|
||||
pub(crate) unref_list: Arc<Mutex<Option<Vec<c_int>>>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for RegistryKey {
|
||||
|
@ -56,7 +55,7 @@ impl fmt::Debug for RegistryKey {
|
|||
|
||||
impl Drop for RegistryKey {
|
||||
fn drop(&mut self) {
|
||||
let mut unref_list = mlua_expect!(self.unref_list.try_borrow_mut(), "unref list borrowed");
|
||||
let mut unref_list = mlua_expect!(self.unref_list.lock(), "unref list poisoned");
|
||||
if let Some(list) = unref_list.as_mut() {
|
||||
list.push(self.registry_id);
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||
S: ?Sized + AsRef<[u8]>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + Fn(&'lua Lua, &T, A) -> Result<R>;
|
||||
M: 'static + Send + Fn(&'lua Lua, &T, A) -> Result<R>;
|
||||
|
||||
/// Add a regular method which accepts a `&mut T` as the first parameter.
|
||||
///
|
||||
|
@ -149,7 +149,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||
S: ?Sized + AsRef<[u8]>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
|
||||
M: 'static + Send + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
|
||||
|
||||
/// Add an async method which accepts a `T` as the first parameter and returns Future.
|
||||
/// The passed `T` is cloned from the original value.
|
||||
|
@ -164,7 +164,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||
S: ?Sized + AsRef<[u8]>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + Fn(&'lua Lua, T, A) -> MR,
|
||||
M: 'static + Send + Fn(&'lua Lua, T, A) -> MR,
|
||||
MR: 'lua + Future<Output = Result<R>>;
|
||||
|
||||
/// Add a regular method as a function which accepts generic arguments, the first argument will
|
||||
|
@ -181,7 +181,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||
S: ?Sized + AsRef<[u8]>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + Fn(&'lua Lua, A) -> Result<R>;
|
||||
F: 'static + Send + Fn(&'lua Lua, A) -> Result<R>;
|
||||
|
||||
/// Add a regular method as a mutable function which accepts generic arguments.
|
||||
///
|
||||
|
@ -193,7 +193,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||
S: ?Sized + AsRef<[u8]>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + FnMut(&'lua Lua, A) -> Result<R>;
|
||||
F: 'static + Send + FnMut(&'lua Lua, A) -> Result<R>;
|
||||
|
||||
/// Add a regular method as an async function which accepts generic arguments
|
||||
/// and returns Future.
|
||||
|
@ -208,7 +208,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||
S: ?Sized + AsRef<[u8]>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + Fn(&'lua Lua, A) -> FR,
|
||||
F: 'static + Send + Fn(&'lua Lua, A) -> FR,
|
||||
FR: 'lua + Future<Output = Result<R>>;
|
||||
|
||||
/// Add a metamethod which accepts a `&T` as the first parameter.
|
||||
|
@ -223,7 +223,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + Fn(&'lua Lua, &T, A) -> Result<R>;
|
||||
M: 'static + Send + Fn(&'lua Lua, &T, A) -> Result<R>;
|
||||
|
||||
/// Add a metamethod as a function which accepts a `&mut T` as the first parameter.
|
||||
///
|
||||
|
@ -237,7 +237,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
|
||||
M: 'static + Send + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
|
||||
|
||||
/// Add a metamethod which accepts generic arguments.
|
||||
///
|
||||
|
@ -248,7 +248,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + Fn(&'lua Lua, A) -> Result<R>;
|
||||
F: 'static + Send + Fn(&'lua Lua, A) -> Result<R>;
|
||||
|
||||
/// Add a metamethod as a mutable function which accepts generic arguments.
|
||||
///
|
||||
|
@ -259,7 +259,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + FnMut(&'lua Lua, A) -> Result<R>;
|
||||
F: 'static + Send + FnMut(&'lua Lua, A) -> Result<R>;
|
||||
}
|
||||
|
||||
/// Trait for custom userdata types.
|
||||
|
|
|
@ -4,8 +4,7 @@ use std::collections::HashMap;
|
|||
use std::fmt::Write;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{mem, ptr, slice};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
|
@ -469,7 +468,7 @@ pub unsafe extern "C" fn error_traceback(state: *mut ffi::lua_State) -> c_int {
|
|||
ud,
|
||||
WrappedError(Error::CallbackError {
|
||||
traceback,
|
||||
cause: Rc::new(error),
|
||||
cause: Arc::new(error),
|
||||
}),
|
||||
);
|
||||
get_gc_metatable_for::<WrappedError>(state);
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#![cfg(feature = "async")]
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{
|
||||
atomic::{AtomicI64, Ordering},
|
||||
Arc,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
use futures_timer::Delay;
|
||||
|
@ -180,7 +182,7 @@ async fn test_async_thread_stream() -> Result<()> {
|
|||
async fn test_async_thread() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let cnt = Rc::new(10); // sleep 10ms
|
||||
let cnt = Arc::new(10); // sleep 10ms
|
||||
let cnt2 = cnt.clone();
|
||||
let f = lua.create_async_function(move |_lua, ()| {
|
||||
let cnt3 = cnt2.clone();
|
||||
|
@ -194,9 +196,9 @@ async fn test_async_thread() -> Result<()> {
|
|||
|
||||
assert_eq!(res, "done");
|
||||
|
||||
assert_eq!(Rc::strong_count(&cnt), 2);
|
||||
assert_eq!(Arc::strong_count(&cnt), 2);
|
||||
lua.gc_collect()?; // thread_s is non-resumable and subject to garbage collection
|
||||
assert_eq!(Rc::strong_count(&cnt), 1);
|
||||
assert_eq!(Arc::strong_count(&cnt), 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -252,18 +254,18 @@ async fn test_async_table() -> Result<()> {
|
|||
#[tokio::test]
|
||||
async fn test_async_userdata() -> Result<()> {
|
||||
#[derive(Clone)]
|
||||
struct MyUserData(Rc<Cell<i64>>);
|
||||
struct MyUserData(Arc<AtomicI64>);
|
||||
|
||||
impl UserData for MyUserData {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_async_method("get_value", |_, data, ()| async move {
|
||||
Delay::new(Duration::from_millis(10)).await;
|
||||
Ok(data.0.get())
|
||||
Ok(data.0.load(Ordering::Relaxed))
|
||||
});
|
||||
|
||||
methods.add_async_method("set_value", |_, data, n| async move {
|
||||
Delay::new(Duration::from_millis(10)).await;
|
||||
data.0.set(n);
|
||||
data.0.store(n, Ordering::Relaxed);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
|
@ -277,7 +279,7 @@ async fn test_async_userdata() -> Result<()> {
|
|||
let lua = Lua::new();
|
||||
let globals = lua.globals();
|
||||
|
||||
let userdata = lua.create_userdata(MyUserData(Rc::new(Cell::new(11))))?;
|
||||
let userdata = lua.create_userdata(MyUserData(Arc::new(AtomicI64::new(11))))?;
|
||||
globals.set("userdata", userdata.clone())?;
|
||||
|
||||
lua.load(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use mlua::{Lua, Result, UserData};
|
||||
|
||||
|
@ -16,17 +16,17 @@ fn test_gc_control() -> Result<()> {
|
|||
assert!(lua.gc_is_running());
|
||||
}
|
||||
|
||||
struct MyUserdata(Rc<()>);
|
||||
struct MyUserdata(Arc<()>);
|
||||
impl UserData for MyUserdata {}
|
||||
|
||||
let rc = Rc::new(());
|
||||
let rc = Arc::new(());
|
||||
globals.set("userdata", lua.create_userdata(MyUserdata(rc.clone()))?)?;
|
||||
globals.raw_remove("userdata")?;
|
||||
|
||||
assert_eq!(Rc::strong_count(&rc), 2);
|
||||
assert_eq!(Arc::strong_count(&rc), 2);
|
||||
lua.gc_collect()?;
|
||||
lua.gc_collect()?;
|
||||
assert_eq!(Rc::strong_count(&rc), 1);
|
||||
assert_eq!(Arc::strong_count(&rc), 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::iter::FromIterator;
|
||||
use std::panic::catch_unwind;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::{error, f32, f64, fmt};
|
||||
|
||||
use mlua::{
|
||||
|
@ -584,22 +584,22 @@ fn test_registry_value() -> Result<()> {
|
|||
|
||||
#[test]
|
||||
fn test_drop_registry_value() -> Result<()> {
|
||||
struct MyUserdata(Rc<()>);
|
||||
struct MyUserdata(Arc<()>);
|
||||
|
||||
impl UserData for MyUserdata {}
|
||||
|
||||
let lua = Lua::new();
|
||||
let rc = Rc::new(());
|
||||
let rc = Arc::new(());
|
||||
|
||||
let r = lua.create_registry_value(MyUserdata(rc.clone()))?;
|
||||
assert_eq!(Rc::strong_count(&rc), 2);
|
||||
assert_eq!(Arc::strong_count(&rc), 2);
|
||||
|
||||
drop(r);
|
||||
lua.expire_registry_values();
|
||||
|
||||
lua.load(r#"collectgarbage("collect")"#).exec()?;
|
||||
|
||||
assert_eq!(Rc::strong_count(&rc), 1);
|
||||
assert_eq!(Arc::strong_count(&rc), 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use mlua::{
|
||||
AnyUserData, ExternalError, Function, Lua, MetaMethod, Result, String, UserData,
|
||||
|
@ -196,22 +196,22 @@ fn test_gc_userdata() -> Result<()> {
|
|||
|
||||
#[test]
|
||||
fn detroys_userdata() -> Result<()> {
|
||||
struct MyUserdata(Rc<()>);
|
||||
struct MyUserdata(Arc<()>);
|
||||
|
||||
impl UserData for MyUserdata {}
|
||||
|
||||
let rc = Rc::new(());
|
||||
let rc = Arc::new(());
|
||||
|
||||
let lua = Lua::new();
|
||||
lua.globals().set("userdata", MyUserdata(rc.clone()))?;
|
||||
|
||||
assert_eq!(Rc::strong_count(&rc), 2);
|
||||
assert_eq!(Arc::strong_count(&rc), 2);
|
||||
|
||||
// should destroy all objects
|
||||
let _ = lua.globals().raw_remove("userdata")?;
|
||||
lua.gc_collect()?;
|
||||
|
||||
assert_eq!(Rc::strong_count(&rc), 1);
|
||||
assert_eq!(Arc::strong_count(&rc), 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue