Add Send capability to Lua

This commit is contained in:
Alex Orlenko 2020-05-06 02:32:05 +01:00
parent 6e2bb73cff
commit 7b0e4b4280
12 changed files with 107 additions and 111 deletions

View File

@ -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())));

View File

@ -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(())
});
}

View File

@ -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)?))
}

View File

@ -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)

View File

@ -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| {

View File

@ -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);
}

View File

@ -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.

View File

@ -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);

View File

@ -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(

View File

@ -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(())
}

View File

@ -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(())
}

View File

@ -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(())
}