Merge branch 'dev'
This commit is contained in:
commit
204eedde3c
|
@ -33,6 +33,7 @@ lua53 = []
|
|||
lua52 = []
|
||||
lua51 = []
|
||||
luajit = []
|
||||
luajit52 = ["luajit"]
|
||||
vendored = ["lua-src", "luajit-src"]
|
||||
module = ["mlua_derive"]
|
||||
async = ["futures-core", "futures-task", "futures-util"]
|
||||
|
@ -45,6 +46,7 @@ mlua_derive = { version = "=0.6.0", optional = true, path = "mlua_derive" }
|
|||
bstr = { version = "0.2", features = ["std"], default_features = false }
|
||||
once_cell = { version = "1.0" }
|
||||
num-traits = { version = "0.2.14" }
|
||||
rustc-hash = "1.0"
|
||||
futures-core = { version = "0.3.5", optional = true }
|
||||
futures-task = { version = "0.3.5", optional = true }
|
||||
futures-util = { version = "0.3.5", optional = true }
|
||||
|
@ -55,7 +57,7 @@ erased-serde = { version = "0.3", optional = true }
|
|||
cc = { version = "1.0" }
|
||||
pkg-config = { version = "0.3.17" }
|
||||
lua-src = { version = ">= 540.0.0, < 550.0.0", optional = true }
|
||||
luajit-src = { version = ">= 210.1.2, < 220.0.0", optional = true }
|
||||
luajit-src = { version = ">= 210.3.1, < 220.0.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rustyline = "8.0"
|
||||
|
|
|
@ -33,6 +33,7 @@ Below is a list of the available feature flags. By default `mlua` does not enabl
|
|||
* `lua52`: activate Lua [5.2] support
|
||||
* `lua51`: activate Lua [5.1] support
|
||||
* `luajit`: activate [LuaJIT] support
|
||||
* `luajit52`: activate [LuaJIT] support with partial compatibility with Lua 5.2
|
||||
* `vendored`: build static Lua(JIT) library from sources during `mlua` compilation using [lua-src] or [luajit-src] crates
|
||||
* `module`: enable module mode (building loadable `cdylib` library for Lua)
|
||||
* `async`: enable async/await support (any executor can be used, eg. [tokio] or [async-std])
|
||||
|
|
|
@ -10,7 +10,13 @@ pub fn probe_lua() -> PathBuf {
|
|||
#[cfg(feature = "lua51")]
|
||||
let artifacts = lua_src::Build::new().build(lua_src::Lua51);
|
||||
#[cfg(feature = "luajit")]
|
||||
let artifacts = luajit_src::Build::new().build();
|
||||
let artifacts = {
|
||||
let mut builder = luajit_src::Build::new();
|
||||
if cfg!(feature = "luajit52") {
|
||||
builder.lua52compat(true);
|
||||
}
|
||||
builder.build()
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "module"))]
|
||||
artifacts.print_cargo_metadata();
|
||||
|
|
|
@ -201,7 +201,9 @@ fn main() {
|
|||
feature = "lua51",
|
||||
feature = "luajit"
|
||||
)))]
|
||||
compile_error!("You must enable one of the features: lua54, lua53, lua52, lua51, luajit");
|
||||
compile_error!(
|
||||
"You must enable one of the features: lua54, lua53, lua52, lua51, luajit, luajit52"
|
||||
);
|
||||
|
||||
#[cfg(all(
|
||||
feature = "lua54",
|
||||
|
@ -212,19 +214,27 @@ fn main() {
|
|||
feature = "luajit"
|
||||
)
|
||||
))]
|
||||
compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit");
|
||||
compile_error!(
|
||||
"You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52"
|
||||
);
|
||||
|
||||
#[cfg(all(
|
||||
feature = "lua53",
|
||||
any(feature = "lua52", feature = "lua51", feature = "luajit")
|
||||
))]
|
||||
compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit");
|
||||
compile_error!(
|
||||
"You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52"
|
||||
);
|
||||
|
||||
#[cfg(all(feature = "lua52", any(feature = "lua51", feature = "luajit")))]
|
||||
compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit");
|
||||
compile_error!(
|
||||
"You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52"
|
||||
);
|
||||
|
||||
#[cfg(all(feature = "lua51", feature = "luajit"))]
|
||||
compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit");
|
||||
compile_error!(
|
||||
"You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52"
|
||||
);
|
||||
|
||||
// We don't support "vendored module" mode on windows
|
||||
#[cfg(all(feature = "vendored", feature = "module", target_os = "windows"))]
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::hash::{BuildHasher, Hash};
|
||||
use std::string::String as StdString;
|
||||
|
@ -348,18 +349,15 @@ macro_rules! lua_convert_int {
|
|||
($x:ty) => {
|
||||
impl<'lua> ToLua<'lua> for $x {
|
||||
fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
|
||||
if let Some(i) = cast(self) {
|
||||
Ok(Value::Integer(i))
|
||||
} else {
|
||||
// TODO: Remove conversion to Number in v0.7
|
||||
cast(self)
|
||||
.ok_or_else(|| Error::ToLuaConversionError {
|
||||
from: stringify!($x),
|
||||
to: "number",
|
||||
message: Some("out of range".to_owned()),
|
||||
})
|
||||
.map(Value::Number)
|
||||
}
|
||||
cast(self)
|
||||
.map(Value::Integer)
|
||||
.or_else(|| cast(self).map(Value::Number))
|
||||
// This is impossible error because conversion to Number never fails
|
||||
.ok_or_else(|| Error::ToLuaConversionError {
|
||||
from: stringify!($x),
|
||||
to: "number",
|
||||
message: Some("out of range".to_owned()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -451,37 +449,36 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! lua_convert_array {
|
||||
($($N:literal)+) => {
|
||||
$(
|
||||
impl<'lua, T> ToLua<'lua> for [T; $N]
|
||||
where
|
||||
T: Clone + ToLua<'lua>,
|
||||
{
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
(&self).to_lua(lua)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T> ToLua<'lua> for &[T; $N]
|
||||
where
|
||||
T: Clone + ToLua<'lua>,
|
||||
{
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Table(
|
||||
lua.create_sequence_from(self.iter().cloned())?,
|
||||
))
|
||||
}
|
||||
}
|
||||
)+
|
||||
impl<'lua, T, const N: usize> ToLua<'lua> for [T; N]
|
||||
where
|
||||
T: ToLua<'lua>,
|
||||
{
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Table(lua.create_sequence_from(self)?))
|
||||
}
|
||||
}
|
||||
|
||||
lua_convert_array! {
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
10 11 12 13 14 15 16 17 18 19
|
||||
20 21 22 23 24 25 26 27 28 29
|
||||
30 31 32
|
||||
impl<'lua, T, const N: usize> FromLua<'lua> for [T; N]
|
||||
where
|
||||
T: FromLua<'lua>,
|
||||
{
|
||||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||
if let Value::Table(table) = value {
|
||||
let vec = table.sequence_values().collect::<Result<Vec<_>>>()?;
|
||||
vec.try_into()
|
||||
.map_err(|vec: Vec<T>| Error::FromLuaConversionError {
|
||||
from: "Table",
|
||||
to: "Array",
|
||||
message: Some(format!("expected table of length {}, got {}", N, vec.len())),
|
||||
})
|
||||
} else {
|
||||
Err(Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "Array",
|
||||
message: Some("expected table".to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: ToLua<'lua>> ToLua<'lua> for Box<[T]> {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
//! Contains definitions from `lua.h`.
|
||||
|
||||
use std::marker::{PhantomData, PhantomPinned};
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
use std::os::raw::c_uchar;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
|
@ -81,7 +82,11 @@ pub const LUA_ERRERR: c_int = 5;
|
|||
pub const LUA_ERRERR: c_int = 6;
|
||||
|
||||
/// A raw Lua state associated with a thread.
|
||||
pub type lua_State = c_void;
|
||||
#[repr(C)]
|
||||
pub struct lua_State {
|
||||
_data: [u8; 0],
|
||||
_marker: PhantomData<(*mut u8, PhantomPinned)>,
|
||||
}
|
||||
|
||||
// basic types
|
||||
pub const LUA_TNONE: c_int = -1;
|
||||
|
@ -621,7 +626,7 @@ extern "C" {
|
|||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
|
||||
L.offset(-super::glue::LUA_EXTRASPACE as isize) as *mut c_void
|
||||
(L as *mut c_char).offset(-super::glue::LUA_EXTRASPACE as isize) as *mut c_void
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
|
|
141
src/lua.rs
141
src/lua.rs
|
@ -1,4 +1,4 @@
|
|||
use std::any::TypeId;
|
||||
use std::any::{Any, TypeId};
|
||||
use std::cell::{Ref, RefCell, RefMut, UnsafeCell};
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CString;
|
||||
|
@ -9,6 +9,8 @@ use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe, Location};
|
|||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::{mem, ptr, str};
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::function::Function;
|
||||
|
@ -63,10 +65,12 @@ pub struct Lua {
|
|||
|
||||
// Data associated with the Lua.
|
||||
struct ExtraData {
|
||||
registered_userdata: HashMap<TypeId, c_int>,
|
||||
registered_userdata_mt: HashMap<*const c_void, Option<TypeId>>,
|
||||
registered_userdata: FxHashMap<TypeId, c_int>,
|
||||
registered_userdata_mt: FxHashMap<*const c_void, Option<TypeId>>,
|
||||
registry_unref_list: Arc<Mutex<Option<Vec<c_int>>>>,
|
||||
|
||||
app_data: RefCell<HashMap<TypeId, Box<dyn Any>>>,
|
||||
|
||||
libs: StdLib,
|
||||
mem_info: Option<Box<MemoryInfo>>,
|
||||
safe: bool, // Same as in the Lua struct
|
||||
|
@ -456,9 +460,10 @@ impl Lua {
|
|||
// Create ExtraData
|
||||
|
||||
let extra = Arc::new(UnsafeCell::new(ExtraData {
|
||||
registered_userdata: HashMap::new(),
|
||||
registered_userdata_mt: HashMap::new(),
|
||||
registered_userdata: FxHashMap::default(),
|
||||
registered_userdata_mt: FxHashMap::default(),
|
||||
registry_unref_list: Arc::new(Mutex::new(Some(Vec::new()))),
|
||||
app_data: RefCell::new(HashMap::new()),
|
||||
ref_thread,
|
||||
libs: StdLib::NONE,
|
||||
mem_info: None,
|
||||
|
@ -1577,6 +1582,74 @@ impl Lua {
|
|||
}
|
||||
}
|
||||
|
||||
/// Sets or replaces an application data object of type `T`.
|
||||
///
|
||||
/// Application data could be accessed at any time by using [`Lua::app_data_ref()`] or [`Lua::app_data_mut()`]
|
||||
/// methods where `T` is the data type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use mlua::{Lua, Result};
|
||||
///
|
||||
/// fn hello(lua: &Lua, _: ()) -> Result<()> {
|
||||
/// let mut s = lua.app_data_mut::<&str>().unwrap();
|
||||
/// assert_eq!(*s, "hello");
|
||||
/// *s = "world";
|
||||
/// Ok(())
|
||||
/// }
|
||||
///
|
||||
/// fn main() -> Result<()> {
|
||||
/// let lua = Lua::new();
|
||||
/// lua.set_app_data("hello");
|
||||
/// lua.create_function(hello)?.call(())?;
|
||||
/// let s = lua.app_data_ref::<&str>().unwrap();
|
||||
/// assert_eq!(*s, "world");
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub fn set_app_data<T: 'static + MaybeSend>(&self, data: T) {
|
||||
let extra = unsafe { &mut (*self.extra.get()) };
|
||||
extra
|
||||
.app_data
|
||||
.try_borrow_mut()
|
||||
.expect("cannot borrow mutably app data container")
|
||||
.insert(TypeId::of::<T>(), Box::new(data));
|
||||
}
|
||||
|
||||
/// Gets a reference to an application data object stored by [`Lua::set_app_data()`] of type `T`.
|
||||
pub fn app_data_ref<T: 'static>(&self) -> Option<Ref<T>> {
|
||||
let extra = unsafe { &(*self.extra.get()) };
|
||||
let app_data = extra
|
||||
.app_data
|
||||
.try_borrow()
|
||||
.expect("cannot borrow app data container");
|
||||
let value = app_data.get(&TypeId::of::<T>())?.downcast_ref::<T>()? as *const _;
|
||||
Some(Ref::map(app_data, |_| unsafe { &*value }))
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to an application data object stored by [`Lua::set_app_data()`] of type `T`.
|
||||
pub fn app_data_mut<T: 'static>(&self) -> Option<RefMut<T>> {
|
||||
let extra = unsafe { &(*self.extra.get()) };
|
||||
let mut app_data = extra
|
||||
.app_data
|
||||
.try_borrow_mut()
|
||||
.expect("cannot mutably borrow app data container");
|
||||
let value = app_data.get_mut(&TypeId::of::<T>())?.downcast_mut::<T>()? as *mut _;
|
||||
Some(RefMut::map(app_data, |_| unsafe { &mut *value }))
|
||||
}
|
||||
|
||||
/// Removes an application data of type `T`.
|
||||
pub fn remove_app_data<T: 'static>(&self) -> Option<T> {
|
||||
let extra = unsafe { &mut (*self.extra.get()) };
|
||||
extra
|
||||
.app_data
|
||||
.try_borrow_mut()
|
||||
.expect("cannot mutably borrow app data container")
|
||||
.remove(&TypeId::of::<T>())
|
||||
.and_then(|data| data.downcast().ok().map(|data| *data))
|
||||
}
|
||||
|
||||
// Uses 2 stack spaces, does not call checkstack
|
||||
pub(crate) unsafe fn push_value(&self, value: Value) -> Result<()> {
|
||||
match value {
|
||||
|
@ -1769,11 +1842,18 @@ impl Lua {
|
|||
|
||||
// Prepare metatable, add meta methods first and then meta fields
|
||||
let metatable_nrec = methods.meta_methods.len() + fields.meta_fields.len();
|
||||
#[cfg(feature = "async")]
|
||||
let metatable_nrec = metatable_nrec + methods.async_meta_methods.len();
|
||||
push_table(self.state, 0, metatable_nrec as c_int)?;
|
||||
for (k, m) in methods.meta_methods {
|
||||
self.push_value(Value::Function(self.create_callback(m)?))?;
|
||||
rawset_field(self.state, -2, k.validate()?.name())?;
|
||||
}
|
||||
#[cfg(feature = "async")]
|
||||
for (k, m) in methods.async_meta_methods {
|
||||
self.push_value(Value::Function(self.create_async_callback(m)?))?;
|
||||
rawset_field(self.state, -2, k.validate()?.name())?;
|
||||
}
|
||||
for (k, f) in fields.meta_fields {
|
||||
self.push_value(f(self)?)?;
|
||||
rawset_field(self.state, -2, k.validate()?.name())?;
|
||||
|
@ -1807,10 +1887,9 @@ impl Lua {
|
|||
}
|
||||
|
||||
let mut methods_index = None;
|
||||
#[cfg(feature = "async")]
|
||||
let methods_nrec = methods.methods.len() + methods.async_methods.len();
|
||||
#[cfg(not(feature = "async"))]
|
||||
let methods_nrec = methods.methods.len();
|
||||
#[cfg(feature = "async")]
|
||||
let methods_nrec = methods_nrec + methods.async_methods.len();
|
||||
if methods_nrec > 0 {
|
||||
push_table(self.state, 0, methods_nrec as c_int)?;
|
||||
for (k, m) in methods.methods {
|
||||
|
@ -2425,7 +2504,7 @@ impl<'lua, T: AsRef<[u8]> + ?Sized> AsChunk<'lua> for T {
|
|||
}
|
||||
|
||||
// Creates required entries in the metatable cache (see `util::METATABLE_CACHE`)
|
||||
pub(crate) fn init_metatable_cache(cache: &mut HashMap<TypeId, u8>) {
|
||||
pub(crate) fn init_metatable_cache(cache: &mut FxHashMap<TypeId, u8>) {
|
||||
cache.insert(TypeId::of::<Arc<UnsafeCell<ExtraData>>>(), 0);
|
||||
cache.insert(TypeId::of::<Callback>(), 0);
|
||||
cache.insert(TypeId::of::<CallbackUpvalue>(), 0);
|
||||
|
@ -2712,6 +2791,8 @@ struct StaticUserDataMethods<'lua, T: 'static + UserData> {
|
|||
#[cfg(feature = "async")]
|
||||
async_methods: Vec<(Vec<u8>, AsyncCallback<'lua, 'static>)>,
|
||||
meta_methods: Vec<(MetaMethod, Callback<'lua, 'static>)>,
|
||||
#[cfg(feature = "async")]
|
||||
async_meta_methods: Vec<(MetaMethod, AsyncCallback<'lua, 'static>)>,
|
||||
_type: PhantomData<T>,
|
||||
}
|
||||
|
||||
|
@ -2722,6 +2803,8 @@ impl<'lua, T: 'static + UserData> Default for StaticUserDataMethods<'lua, T> {
|
|||
#[cfg(feature = "async")]
|
||||
async_methods: Vec::new(),
|
||||
meta_methods: Vec::new(),
|
||||
#[cfg(feature = "async")]
|
||||
async_meta_methods: Vec::new(),
|
||||
_type: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -2821,6 +2904,20 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
|
|||
.push((meta.into(), Self::box_method_mut(method)));
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "async", not(feature = "lua51")))]
|
||||
fn add_async_meta_method<S, A, R, M, MR>(&mut self, meta: S, method: M)
|
||||
where
|
||||
T: Clone,
|
||||
S: Into<MetaMethod>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
|
||||
MR: 'lua + Future<Output = Result<R>>,
|
||||
{
|
||||
self.async_meta_methods
|
||||
.push((meta.into(), Self::box_async_method(method)));
|
||||
}
|
||||
|
||||
fn add_meta_function<S, A, R, F>(&mut self, meta: S, function: F)
|
||||
where
|
||||
S: Into<MetaMethod>,
|
||||
|
@ -2843,6 +2940,19 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
|
|||
.push((meta.into(), Self::box_function_mut(function)));
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "async", not(feature = "lua51")))]
|
||||
fn add_async_meta_function<S, A, R, F, FR>(&mut self, meta: S, function: F)
|
||||
where
|
||||
S: Into<MetaMethod>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
|
||||
FR: 'lua + Future<Output = Result<R>>,
|
||||
{
|
||||
self.async_meta_methods
|
||||
.push((meta.into(), Self::box_async_function(function)));
|
||||
}
|
||||
|
||||
// Below are internal methods used in generated code
|
||||
|
||||
fn add_callback(&mut self, name: Vec<u8>, callback: Callback<'lua, 'static>) {
|
||||
|
@ -2857,6 +2967,15 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
|
|||
fn add_meta_callback(&mut self, meta: MetaMethod, callback: Callback<'lua, 'static>) {
|
||||
self.meta_methods.push((meta, callback));
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
fn add_async_meta_callback(
|
||||
&mut self,
|
||||
meta: MetaMethod,
|
||||
callback: AsyncCallback<'lua, 'static>,
|
||||
) {
|
||||
self.async_meta_methods.push((meta, callback))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
|
||||
|
@ -3202,6 +3321,10 @@ macro_rules! lua_userdata_impl {
|
|||
for (meta, callback) in orig_methods.meta_methods {
|
||||
methods.add_meta_callback(meta, callback);
|
||||
}
|
||||
#[cfg(feature = "async")]
|
||||
for (meta, callback) in orig_methods.async_meta_methods {
|
||||
methods.add_async_meta_callback(meta, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
29
src/scope.rs
29
src/scope.rs
|
@ -693,6 +693,21 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
|
|||
));
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "async", not(feature = "lua51")))]
|
||||
fn add_async_meta_method<S, A, R, M, MR>(&mut self, _meta: S, _method: M)
|
||||
where
|
||||
T: Clone,
|
||||
S: Into<MetaMethod>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
|
||||
MR: 'lua + Future<Output = Result<R>>,
|
||||
{
|
||||
// The panic should never happen as async non-static code wouldn't compile
|
||||
// Non-static lifetime must be bounded to 'lua lifetime
|
||||
mlua_panic!("asynchronous meta methods are not supported for non-static userdata")
|
||||
}
|
||||
|
||||
fn add_meta_function<S, A, R, F>(&mut self, meta: S, function: F)
|
||||
where
|
||||
S: Into<MetaMethod>,
|
||||
|
@ -722,6 +737,20 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
|
|||
})),
|
||||
));
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "async", not(feature = "lua51")))]
|
||||
fn add_async_meta_function<S, A, R, F, FR>(&mut self, _meta: S, _function: F)
|
||||
where
|
||||
S: Into<MetaMethod>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
|
||||
FR: 'lua + Future<Output = Result<R>>,
|
||||
{
|
||||
// The panic should never happen as async non-static code wouldn't compile
|
||||
// Non-static lifetime must be bounded to 'lua lifetime
|
||||
mlua_panic!("asynchronous meta functions are not supported for non-static userdata")
|
||||
}
|
||||
}
|
||||
|
||||
struct NonStaticUserDataFields<'lua, T: UserData> {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::HashSet;
|
||||
use std::os::raw::c_void;
|
||||
use std::rc::Rc;
|
||||
use std::string::String as StdString;
|
||||
|
||||
use rustc_hash::FxHashSet;
|
||||
use serde::de::{self, IntoDeserializer};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
|
@ -16,7 +16,7 @@ use crate::value::Value;
|
|||
pub struct Deserializer<'lua> {
|
||||
value: Value<'lua>,
|
||||
options: Options,
|
||||
visited: Rc<RefCell<HashSet<*const c_void>>>,
|
||||
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
|
||||
}
|
||||
|
||||
/// A struct with options to change default deserializer behavior.
|
||||
|
@ -45,23 +45,23 @@ pub struct Options {
|
|||
|
||||
impl Default for Options {
|
||||
fn default() -> Self {
|
||||
Options {
|
||||
deny_unsupported_types: true,
|
||||
deny_recursive_tables: true,
|
||||
}
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Options {
|
||||
/// Returns a new instance of `Options` with default parameters.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
pub const fn new() -> Self {
|
||||
Options {
|
||||
deny_unsupported_types: true,
|
||||
deny_recursive_tables: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets [`deny_unsupported_types`] option.
|
||||
///
|
||||
/// [`deny_unsupported_types`]: #structfield.deny_unsupported_types
|
||||
pub fn deny_unsupported_types(mut self, enabled: bool) -> Self {
|
||||
pub const fn deny_unsupported_types(mut self, enabled: bool) -> Self {
|
||||
self.deny_unsupported_types = enabled;
|
||||
self
|
||||
}
|
||||
|
@ -86,14 +86,14 @@ impl<'lua> Deserializer<'lua> {
|
|||
Deserializer {
|
||||
value,
|
||||
options,
|
||||
visited: Rc::new(RefCell::new(HashSet::new())),
|
||||
visited: Rc::new(RefCell::new(FxHashSet::default())),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_parts(
|
||||
value: Value<'lua>,
|
||||
options: Options,
|
||||
visited: Rc<RefCell<HashSet<*const c_void>>>,
|
||||
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
|
||||
) -> Self {
|
||||
Deserializer {
|
||||
value,
|
||||
|
@ -313,7 +313,7 @@ impl<'lua, 'de> serde::Deserializer<'de> for Deserializer<'lua> {
|
|||
struct SeqDeserializer<'lua> {
|
||||
seq: TableSequence<'lua, Value<'lua>>,
|
||||
options: Options,
|
||||
visited: Rc<RefCell<HashSet<*const c_void>>>,
|
||||
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
|
||||
}
|
||||
|
||||
impl<'lua, 'de> de::SeqAccess<'de> for SeqDeserializer<'lua> {
|
||||
|
@ -351,7 +351,7 @@ struct MapDeserializer<'lua> {
|
|||
pairs: TablePairs<'lua, Value<'lua>, Value<'lua>>,
|
||||
value: Option<Value<'lua>>,
|
||||
options: Options,
|
||||
visited: Rc<RefCell<HashSet<*const c_void>>>,
|
||||
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
|
||||
processed: usize,
|
||||
}
|
||||
|
||||
|
@ -407,7 +407,7 @@ struct EnumDeserializer<'lua> {
|
|||
variant: StdString,
|
||||
value: Option<Value<'lua>>,
|
||||
options: Options,
|
||||
visited: Rc<RefCell<HashSet<*const c_void>>>,
|
||||
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
|
||||
}
|
||||
|
||||
impl<'lua, 'de> de::EnumAccess<'de> for EnumDeserializer<'lua> {
|
||||
|
@ -431,7 +431,7 @@ impl<'lua, 'de> de::EnumAccess<'de> for EnumDeserializer<'lua> {
|
|||
struct VariantDeserializer<'lua> {
|
||||
value: Option<Value<'lua>>,
|
||||
options: Options,
|
||||
visited: Rc<RefCell<HashSet<*const c_void>>>,
|
||||
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
|
||||
}
|
||||
|
||||
impl<'lua, 'de> de::VariantAccess<'de> for VariantDeserializer<'lua> {
|
||||
|
@ -499,12 +499,12 @@ impl<'lua, 'de> de::VariantAccess<'de> for VariantDeserializer<'lua> {
|
|||
// Used to track recursive tables but allow to traverse same tables multiple times
|
||||
struct RecursionGuard {
|
||||
ptr: *const c_void,
|
||||
visited: Rc<RefCell<HashSet<*const c_void>>>,
|
||||
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
|
||||
}
|
||||
|
||||
impl RecursionGuard {
|
||||
#[inline]
|
||||
fn new(table: &Table, visited: &Rc<RefCell<HashSet<*const c_void>>>) -> Self {
|
||||
fn new(table: &Table, visited: &Rc<RefCell<FxHashSet<*const c_void>>>) -> Self {
|
||||
let visited = Rc::clone(visited);
|
||||
let lua = table.0.lua;
|
||||
let ptr =
|
||||
|
@ -524,7 +524,7 @@ impl Drop for RecursionGuard {
|
|||
fn check_value_if_skip(
|
||||
value: &Value,
|
||||
options: Options,
|
||||
visited: &RefCell<HashSet<*const c_void>>,
|
||||
visited: &RefCell<FxHashSet<*const c_void>>,
|
||||
) -> Result<bool> {
|
||||
match value {
|
||||
Value::Table(table) => {
|
||||
|
|
|
@ -52,24 +52,24 @@ pub struct Options {
|
|||
|
||||
impl Default for Options {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Options {
|
||||
/// Returns a new instance of [`Options`] with default parameters.
|
||||
pub const fn new() -> Self {
|
||||
Options {
|
||||
set_array_metatable: true,
|
||||
serialize_none_to_null: true,
|
||||
serialize_unit_to_null: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Options {
|
||||
/// Returns a new instance of [`Options`] with default parameters.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Sets [`set_array_metatable`] option.
|
||||
///
|
||||
/// [`set_array_metatable`]: #structfield.set_array_metatable
|
||||
pub fn set_array_metatable(mut self, enabled: bool) -> Self {
|
||||
pub const fn set_array_metatable(mut self, enabled: bool) -> Self {
|
||||
self.set_array_metatable = enabled;
|
||||
self
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ impl Options {
|
|||
/// Sets [`serialize_none_to_null`] option.
|
||||
///
|
||||
/// [`serialize_none_to_null`]: #structfield.serialize_none_to_null
|
||||
pub fn serialize_none_to_null(mut self, enabled: bool) -> Self {
|
||||
pub const fn serialize_none_to_null(mut self, enabled: bool) -> Self {
|
||||
self.serialize_none_to_null = enabled;
|
||||
self
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ impl Options {
|
|||
/// Sets [`serialize_unit_to_null`] option.
|
||||
///
|
||||
/// [`serialize_unit_to_null`]: #structfield.serialize_unit_to_null
|
||||
pub fn serialize_unit_to_null(mut self, enabled: bool) -> Self {
|
||||
pub const fn serialize_unit_to_null(mut self, enabled: bool) -> Self {
|
||||
self.serialize_unit_to_null = enabled;
|
||||
self
|
||||
}
|
||||
|
|
|
@ -102,7 +102,13 @@ pub enum MetaMethod {
|
|||
/// This is not an operator, but it will be called by the built-in `pairs` function.
|
||||
///
|
||||
/// Requires `feature = "lua54/lua53/lua52"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", doc))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luajit52",
|
||||
doc
|
||||
))]
|
||||
Pairs,
|
||||
/// The `__ipairs` metamethod.
|
||||
///
|
||||
|
@ -111,7 +117,7 @@ pub enum MetaMethod {
|
|||
/// Requires `feature = "lua52"`
|
||||
///
|
||||
/// [`ipairs`]: https://www.lua.org/manual/5.2/manual.html#pdf-ipairs
|
||||
#[cfg(any(feature = "lua52", doc))]
|
||||
#[cfg(any(feature = "lua52", feature = "luajit52", doc))]
|
||||
IPairs,
|
||||
/// The `__close` metamethod.
|
||||
///
|
||||
|
@ -188,9 +194,14 @@ impl MetaMethod {
|
|||
MetaMethod::Call => "__call",
|
||||
MetaMethod::ToString => "__tostring",
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luajit52"
|
||||
))]
|
||||
MetaMethod::Pairs => "__pairs",
|
||||
#[cfg(feature = "lua52")]
|
||||
#[cfg(any(feature = "lua52", feature = "luajit52"))]
|
||||
MetaMethod::IPairs => "__ipairs",
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
|
@ -250,9 +261,14 @@ impl From<StdString> for MetaMethod {
|
|||
"__call" => MetaMethod::Call,
|
||||
"__tostring" => MetaMethod::ToString,
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luajit52"
|
||||
))]
|
||||
"__pairs" => MetaMethod::Pairs,
|
||||
#[cfg(feature = "lua52")]
|
||||
#[cfg(any(feature = "lua52", feature = "luajit52"))]
|
||||
"__ipairs" => MetaMethod::IPairs,
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
|
@ -395,6 +411,25 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
|
||||
|
||||
/// Add an async metamethod which accepts a `T` as the first parameter and returns Future.
|
||||
/// The passed `T` is cloned from the original value.
|
||||
///
|
||||
/// This is an async version of [`add_meta_method`].
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`add_meta_method`]: #method.add_meta_method
|
||||
#[cfg(all(feature = "async", not(feature = "lua51")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
fn add_async_meta_method<S, A, R, M, MR>(&mut self, name: S, method: M)
|
||||
where
|
||||
T: Clone,
|
||||
S: Into<MetaMethod>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
|
||||
MR: 'lua + Future<Output = Result<R>>;
|
||||
|
||||
/// Add a metamethod which accepts generic arguments.
|
||||
///
|
||||
/// Metamethods for binary operators can be triggered if either the left or right argument to
|
||||
|
@ -419,6 +454,23 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>;
|
||||
|
||||
/// Add a metamethod which accepts generic arguments and returns Future.
|
||||
///
|
||||
/// This is an async version of [`add_meta_function`].
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`add_meta_function`]: #method.add_meta_function
|
||||
#[cfg(all(feature = "async", not(feature = "lua51")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
fn add_async_meta_function<S, A, R, F, FR>(&mut self, name: S, function: F)
|
||||
where
|
||||
S: Into<MetaMethod>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
|
||||
FR: 'lua + Future<Output = Result<R>>;
|
||||
|
||||
//
|
||||
// Below are internal methods used in generated code
|
||||
//
|
||||
|
@ -432,6 +484,15 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||
|
||||
#[doc(hidden)]
|
||||
fn add_meta_callback(&mut self, _meta: MetaMethod, _callback: Callback<'lua, 'static>) {}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "async")]
|
||||
fn add_async_meta_callback(
|
||||
&mut self,
|
||||
_meta: MetaMethod,
|
||||
_callback: AsyncCallback<'lua, 'static>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Field registry for [`UserData`] implementors.
|
||||
|
@ -758,7 +819,6 @@ impl<'lua> AnyUserData<'lua> {
|
|||
|
||||
/// Takes out the value of `UserData` and sets the special "destructed" metatable that prevents
|
||||
/// any further operations with this userdata.
|
||||
#[doc(hidden)]
|
||||
pub fn take<T: 'static + UserData>(&self) -> Result<T> {
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
|
|
15
src/util.rs
15
src/util.rs
|
@ -1,5 +1,4 @@
|
|||
use std::any::{Any, TypeId};
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt::Write;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
|
@ -8,12 +7,13 @@ use std::sync::Arc;
|
|||
use std::{mem, ptr, slice};
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
|
||||
static METATABLE_CACHE: Lazy<HashMap<TypeId, u8>> = Lazy::new(|| {
|
||||
let mut map = HashMap::with_capacity(32);
|
||||
static METATABLE_CACHE: Lazy<FxHashMap<TypeId, u8>> = Lazy::new(|| {
|
||||
let mut map = FxHashMap::with_capacity_and_hasher(32, Default::default());
|
||||
crate::lua::init_metatable_cache(&mut map);
|
||||
map.insert(TypeId::of::<WrappedFailure>(), 0);
|
||||
map.insert(TypeId::of::<String>(), 0);
|
||||
|
@ -842,9 +842,14 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
|||
"__newindex",
|
||||
"__call",
|
||||
"__tostring",
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luajit52"
|
||||
))]
|
||||
"__pairs",
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
#[cfg(any(feature = "lua53", feature = "lua52", feature = "luajit52"))]
|
||||
"__ipairs",
|
||||
#[cfg(feature = "lua54")]
|
||||
"__close",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{
|
||||
atomic::{AtomicI64, Ordering},
|
||||
atomic::{AtomicI64, AtomicU64, Ordering},
|
||||
Arc,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
@ -12,7 +12,8 @@ use futures_timer::Delay;
|
|||
use futures_util::stream::TryStreamExt;
|
||||
|
||||
use mlua::{
|
||||
Error, Function, Lua, Result, Table, TableExt, Thread, UserData, UserDataMethods, Value,
|
||||
Error, Function, Lua, MetaMethod, Result, Table, TableExt, Thread, UserData, UserDataMethods,
|
||||
Value,
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -276,7 +277,7 @@ async fn test_async_table() -> Result<()> {
|
|||
#[tokio::test]
|
||||
async fn test_async_userdata() -> Result<()> {
|
||||
#[derive(Clone)]
|
||||
struct MyUserData(Arc<AtomicI64>);
|
||||
struct MyUserData(Arc<AtomicU64>);
|
||||
|
||||
impl UserData for MyUserData {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
|
@ -295,13 +296,20 @@ async fn test_async_userdata() -> Result<()> {
|
|||
Delay::new(Duration::from_millis(n)).await;
|
||||
Ok(format!("elapsed:{}ms", n))
|
||||
});
|
||||
|
||||
#[cfg(not(feature = "lua51"))]
|
||||
methods.add_async_meta_method(MetaMethod::Call, |_, data, ()| async move {
|
||||
let n = data.0.load(Ordering::Relaxed);
|
||||
Delay::new(Duration::from_millis(n)).await;
|
||||
Ok(format!("elapsed:{}ms", n))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let lua = Lua::new();
|
||||
let globals = lua.globals();
|
||||
|
||||
let userdata = lua.create_userdata(MyUserData(Arc::new(AtomicI64::new(11))))?;
|
||||
let userdata = lua.create_userdata(MyUserData(Arc::new(AtomicU64::new(11))))?;
|
||||
globals.set("userdata", userdata.clone())?;
|
||||
|
||||
lua.load(
|
||||
|
@ -315,6 +323,16 @@ async fn test_async_userdata() -> Result<()> {
|
|||
.exec_async()
|
||||
.await?;
|
||||
|
||||
#[cfg(not(feature = "lua51"))]
|
||||
lua.load(
|
||||
r#"
|
||||
userdata:set_value(15)
|
||||
assert(userdata() == "elapsed:15ms")
|
||||
"#,
|
||||
)
|
||||
.exec_async()
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
|||
use std::ffi::{CStr, CString};
|
||||
|
||||
use maplit::{btreemap, btreeset, hashmap, hashset};
|
||||
use mlua::{Lua, Result};
|
||||
use mlua::{Error, Lua, Result};
|
||||
|
||||
#[test]
|
||||
fn test_conv_vec() -> Result<()> {
|
||||
|
@ -123,3 +123,18 @@ fn test_conv_boxed_slice() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conv_array() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let v = [1, 2, 3];
|
||||
lua.globals().set("v", v)?;
|
||||
let v2: [i32; 3] = lua.globals().get("v")?;
|
||||
assert_eq!(v, v2);
|
||||
|
||||
let v2 = lua.globals().get::<_, [i32; 4]>("v");
|
||||
assert!(matches!(v2, Err(Error::FromLuaConversionError { .. })));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -139,14 +139,6 @@ fn test_table_sequence_from() -> Result<()> {
|
|||
vec![1, 2, 3]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
get_table
|
||||
.call::<_, Table>(&[1, 2, 3])?
|
||||
.sequence_values()
|
||||
.collect::<Result<Vec<i64>>>()?,
|
||||
vec![1, 2, 3]
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -847,6 +847,37 @@ fn test_mismatched_registry_key() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_application_data() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
lua.set_app_data("test1");
|
||||
lua.set_app_data(vec!["test2"]);
|
||||
|
||||
let f = lua.create_function(|lua, ()| {
|
||||
{
|
||||
let data1 = lua.app_data_ref::<&str>().unwrap();
|
||||
assert_eq!(*data1, "test1");
|
||||
}
|
||||
let mut data2 = lua.app_data_mut::<Vec<&str>>().unwrap();
|
||||
assert_eq!(*data2, vec!["test2"]);
|
||||
data2.push("test3");
|
||||
Ok(())
|
||||
})?;
|
||||
f.call(())?;
|
||||
|
||||
assert_eq!(*lua.app_data_ref::<&str>().unwrap(), "test1");
|
||||
assert_eq!(
|
||||
*lua.app_data_ref::<Vec<&str>>().unwrap(),
|
||||
vec!["test2", "test3"]
|
||||
);
|
||||
|
||||
lua.remove_app_data::<Vec<&str>>();
|
||||
assert!(matches!(lua.app_data_ref::<Vec<&str>>(), None));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_recursion() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
@ -1046,17 +1077,22 @@ fn test_context_thread() -> Result<()> {
|
|||
)
|
||||
.into_function()?;
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luajit52"
|
||||
))]
|
||||
f.call::<_, ()>(lua.current_thread())?;
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[cfg(any(feature = "lua51", all(feature = "luajit", not(feature = "luajit52"))))]
|
||||
f.call::<_, ()>(Nil)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[cfg(any(feature = "lua51", all(feature = "luajit", not(feature = "luajit52"))))]
|
||||
fn test_context_thread_51() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
|
|
|
@ -111,7 +111,12 @@ fn test_metamethods() -> Result<()> {
|
|||
Err("no such custom index".to_lua_err())
|
||||
}
|
||||
});
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luajit52"
|
||||
))]
|
||||
methods.add_meta_method(MetaMethod::Pairs, |lua, data, ()| {
|
||||
use std::iter::FromIterator;
|
||||
let stateless_iter = lua.create_function(|_, (data, i): (MyUserData, i64)| {
|
||||
|
@ -136,11 +141,16 @@ fn test_metamethods() -> Result<()> {
|
|||
10
|
||||
);
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
let pairs_it = {
|
||||
lua.load(
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luajit52"
|
||||
))]
|
||||
let pairs_it = lua
|
||||
.load(
|
||||
r#"
|
||||
function pairs_it()
|
||||
function()
|
||||
local r = 0
|
||||
for i, v in pairs(userdata1) do
|
||||
r = r + v
|
||||
|
@ -149,17 +159,21 @@ fn test_metamethods() -> Result<()> {
|
|||
end
|
||||
"#,
|
||||
)
|
||||
.exec()?;
|
||||
globals.get::<_, Function>("pairs_it")?
|
||||
};
|
||||
.eval::<Function>()?;
|
||||
|
||||
assert_eq!(lua.load("userdata1 - userdata2").eval::<MyUserData>()?.0, 4);
|
||||
assert_eq!(lua.load("userdata1:get()").eval::<i64>()?, 7);
|
||||
assert_eq!(lua.load("userdata2.inner").eval::<i64>()?, 3);
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
assert_eq!(pairs_it.call::<_, i64>(())?, 28);
|
||||
assert!(lua.load("userdata2.nonexist_field").eval::<()>().is_err());
|
||||
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luajit52"
|
||||
))]
|
||||
assert_eq!(pairs_it.call::<_, i64>(())?, 28);
|
||||
|
||||
let userdata2: Value = globals.get("userdata2")?;
|
||||
let userdata3: Value = globals.get("userdata3")?;
|
||||
|
||||
|
|
Loading…
Reference in New Issue