Compare commits

..

12 Commits

Author SHA1 Message Date
Alex Orlenko 4f06f614a9 v0.8.0-beta.5 2022-05-25 01:47:38 +01:00
Alex Orlenko 30ba616a8a Correctly deserialize newtype struct (#168) 2022-05-24 23:26:17 +01:00
Alex Orlenko 0076aa735a Add Function::coverage for Luau to obtain coverage report 2022-05-24 02:01:46 +01:00
Alex Orlenko bcf2cbea37 Add Value::to_pointer() function.
Closes #165 and #166.
2022-05-18 13:15:08 +01:00
Alex Orlenko 8cd594c609 Fix typo 2022-05-18 12:15:39 +01:00
Alex Orlenko 8d71ea79aa Cache bytecode for internal Lua chunks 2022-05-16 20:29:02 +01:00
Alex Orlenko 2a8c5c7f82 Refactor Function::bind implementation.
Make it possible to bind async function arguments.
Fixes #161
2022-05-15 01:15:31 +01:00
Alex Orlenko 6b2ceb60c4 Fix Send impl 2022-05-12 19:24:12 +01:00
Alex Orlenko 3aac7131ee Add Iter metamethod for Luau (available from 0.526) 2022-05-09 14:34:10 +01:00
Alex Orlenko 1807fa789c Don't require Lua sources for modules in build system 2022-05-07 22:16:54 +01:00
Alex Orlenko 7db7526a08 Update to Luau 0.526 2022-05-07 02:08:50 +01:00
Alex Orlenko bea9b0f8b5 Assert stack for Luau in callback_error_ext when operating on a cached wrapped failure.
Should solve #153.
2022-04-27 00:20:25 +01:00
29 changed files with 432 additions and 99 deletions
+5 -5
View File
@@ -39,7 +39,7 @@ jobs:
build_aarch64_cross_macos:
name: Cross-compile to aarch64-apple-darwin
runs-on: macos-11.0
runs-on: macos-latest
needs: build
strategy:
matrix:
@@ -186,8 +186,8 @@ jobs:
- uses: Swatinem/rust-cache@v1
- name: Run ${{ matrix.lua }} module tests
run: |
(cd examples/module && cargo build --release --features "${{ matrix.lua }},vendored")
(cd tests/module && cargo test --release --features "${{ matrix.lua }},vendored")
(cd tests/module && cargo build --release --features "${{ matrix.lua }}")
(cd tests/module/loader && cargo test --release --features "${{ matrix.lua }},vendored")
shell: bash
test_modules_windows:
@@ -208,8 +208,8 @@ jobs:
pacman -S --noconfirm mingw-w64-x86_64-rust mingw-w64-x86_64-lua mingw-w64-x86_64-luajit mingw-w64-x86_64-pkg-config
- name: Run ${{ matrix.lua }} module tests
run: |
(cd examples/module && cargo build --release --features "${{ matrix.lua }}")
(cd tests/module && cargo test --release --features "${{ matrix.lua }}")
(cd tests/module && cargo build --release --features "${{ matrix.lua }}")
(cd tests/module/loader && cargo test --release --features "${{ matrix.lua }}")
rustfmt:
name: Rustfmt
+8
View File
@@ -1,3 +1,11 @@
## v0.8.0-beta.5
- Lua sources no longer needed to build modules
- Added `__iter` metamethod for Luau
- Added `Value::to_pointer()` function
- Added `Function::coverage` for Luau to obtain coverage report
- Bugfixes and improvements (#153 #161 #168)
## v0.8.0-beta.4
- Removed `&Lua` from `Lua::set_interrupt` as it's not safe (introduced in v0.8.0-beta.3)
+2 -4
View File
@@ -1,6 +1,6 @@
[package]
name = "mlua"
version = "0.8.0-beta.4" # remember to update html_root_url and mlua_derive
version = "0.8.0-beta.5" # remember to update html_root_url and mlua_derive
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@chucklefish.org>"]
edition = "2018"
repository = "https://github.com/khvzak/mlua"
@@ -23,8 +23,6 @@ rustdoc-args = ["--cfg", "docsrs"]
[workspace]
members = [
"mlua_derive",
"examples/module",
"tests/module",
]
[features]
@@ -60,7 +58,7 @@ cc = { version = "1.0" }
pkg-config = { version = "0.3.17" }
lua-src = { version = ">= 544.0.0, < 550.0.0", optional = true }
luajit-src = { version = ">= 210.3.1, < 220.0.0", optional = true }
luau0-src = { version = "0.2.2", optional = true }
luau0-src = { version = "0.3", optional = true }
[dev-dependencies]
rustyline = "9.0"
+2 -2
View File
@@ -106,7 +106,7 @@ Add to `Cargo.toml` :
``` toml
[dependencies]
mlua = { version = "0.8.0-beta.4", features = ["lua54", "vendored"] }
mlua = { version = "0.8.0-beta.5", features = ["lua54", "vendored"] }
```
`main.rs`
@@ -141,7 +141,7 @@ Add to `Cargo.toml` :
crate-type = ["cdylib"]
[dependencies]
mlua = { version = "0.8.0-beta.4", features = ["lua54", "vendored", "module"] }
mlua = { version = "0.8.0-beta.5", features = ["lua54", "vendored", "module"] }
```
`lib.rs` :
+1 -1
View File
@@ -1,5 +1,5 @@
use std::path::PathBuf;
pub fn probe_lua() -> Option<PathBuf> {
unreachable!()
None
}
+2
View File
@@ -1,3 +1,5 @@
#![allow(dead_code)]
use std::env;
use std::ops::Bound;
use std::path::PathBuf;
+2 -1
View File
@@ -1,3 +1,5 @@
#![allow(dead_code)]
use std::path::PathBuf;
pub fn probe_lua() -> Option<PathBuf> {
@@ -20,7 +22,6 @@ pub fn probe_lua() -> Option<PathBuf> {
#[cfg(feature = "luau")]
let artifacts = luau0_src::Build::new().build();
#[cfg(not(feature = "module"))]
artifacts.print_cargo_metadata();
Some(artifacts.include_dir().to_owned())
+4
View File
@@ -105,6 +105,10 @@ fn main() {
+ "Please, use `pkg-config` or custom mode to link to a Lua dll."
);
#[cfg(all(feature = "luau", feature = "module"))]
compile_error!("Luau does not support module mode");
#[cfg(any(not(feature = "module"), target_os = "windows"))]
find::probe_lua();
println!("cargo:rerun-if-changed=build");
+2 -1
View File
@@ -7,13 +7,14 @@ edition = "2018"
[lib]
crate-type = ["cdylib"]
[workspace]
[features]
lua54 = ["mlua/lua54"]
lua53 = ["mlua/lua53"]
lua52 = ["mlua/lua52"]
lua51 = ["mlua/lua51"]
luajit = ["mlua/luajit"]
vendored = ["mlua/vendored"]
[dependencies]
mlua = { path = "../..", features = ["module"] }
-22
View File
@@ -8,32 +8,10 @@ fn used_memory(lua: &Lua, _: ()) -> LuaResult<usize> {
Ok(lua.used_memory())
}
fn check_userdata(_: &Lua, ud: MyUserData) -> LuaResult<i32> {
Ok(ud.0)
}
#[mlua::lua_module]
fn rust_module(lua: &Lua) -> LuaResult<LuaTable> {
let exports = lua.create_table()?;
exports.set("sum", lua.create_function(sum)?)?;
exports.set("used_memory", lua.create_function(used_memory)?)?;
exports.set("check_userdata", lua.create_function(check_userdata)?)?;
Ok(exports)
}
#[derive(Clone, Copy)]
struct MyUserData(i32);
impl LuaUserData for MyUserData {}
#[mlua::lua_module]
fn rust_module_second(lua: &Lua) -> LuaResult<LuaTable> {
let exports = lua.create_table()?;
exports.set("userdata", lua.create_userdata(MyUserData(123))?)?;
Ok(exports)
}
#[mlua::lua_module]
fn rust_module_error(_: &Lua) -> LuaResult<LuaTable> {
Err("custom module error".to_lua_err())
}
+57 -9
View File
@@ -1,4 +1,5 @@
use std::borrow::Cow;
use std::collections::HashMap;
use std::ffi::CString;
use std::io::Result as IoResult;
use std::path::{Path, PathBuf};
@@ -394,20 +395,68 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
/// Compiles the chunk and changes mode to binary.
///
/// It does nothing if the chunk is already binary.
#[cfg(feature = "luau")]
fn compile(&mut self) {
if let Ok(ref source) = self.source {
if self.detect_mode() == ChunkMode::Text {
let data = self
.compiler
.get_or_insert_with(Default::default)
.compile(source);
self.mode = Some(ChunkMode::Binary);
self.source = Ok(Cow::Owned(data));
#[cfg(feature = "luau")]
{
let data = self
.compiler
.get_or_insert_with(Default::default)
.compile(source);
self.source = Ok(Cow::Owned(data));
self.mode = Some(ChunkMode::Binary);
}
#[cfg(not(feature = "luau"))]
if let Ok(func) = self.lua.load_chunk(source.as_ref(), None, None, None) {
let data = func.dump(false);
self.source = Ok(Cow::Owned(data));
self.mode = Some(ChunkMode::Binary);
}
}
}
}
/// Fetches compiled bytecode of this chunk from the cache.
///
/// If not found, compiles the source code and stores it on the cache.
pub(crate) fn try_cache(mut self) -> Self {
struct ChunksCache(HashMap<Vec<u8>, Vec<u8>>);
// Try to fetch compiled chunk from cache
let mut text_source = None;
if let Ok(ref source) = self.source {
if self.detect_mode() == ChunkMode::Text {
if let Some(cache) = self.lua.app_data_ref::<ChunksCache>() {
if let Some(data) = cache.0.get(source.as_ref()) {
self.source = Ok(Cow::Owned(data.clone()));
self.mode = Some(ChunkMode::Binary);
return self;
}
}
text_source = Some(source.as_ref().to_vec());
}
}
// Compile and cache the chunk
if let Some(text_source) = text_source {
self.compile();
if let Ok(ref binary_source) = self.source {
if self.detect_mode() == ChunkMode::Binary {
if let Some(mut cache) = self.lua.app_data_mut::<ChunksCache>() {
cache.0.insert(text_source, binary_source.as_ref().to_vec());
} else {
let mut cache = ChunksCache(HashMap::new());
cache.0.insert(text_source, binary_source.as_ref().to_vec());
self.lua.set_app_data(cache);
}
}
}
}
self
}
fn to_expression(&self) -> Result<Function<'lua>> {
// We assume that mode is Text
let source = self.source.as_ref();
@@ -429,14 +478,13 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
fn detect_mode(&self) -> ChunkMode {
match (self.mode, &self.source) {
(Some(mode), _) => mode,
(None, Ok(source)) if source.len() == 0 => ChunkMode::Text,
(None, Ok(source)) => {
#[cfg(not(feature = "luau"))]
if source.starts_with(ffi::LUA_SIGNATURE) {
return ChunkMode::Binary;
}
#[cfg(feature = "luau")]
if source[0] < b'\n' {
if *source.get(0).unwrap_or(&u8::MAX) < b'\n' {
return ChunkMode::Binary;
}
ChunkMode::Text
+5 -1
View File
@@ -259,7 +259,11 @@ extern "C" {
pub fn lua_concat(L: *mut lua_State, n: c_int);
// TODO: lua_encodepointer
pub fn lua_clock() -> c_double;
pub fn lua_setuserdatadtor(L: *mut lua_State, tag: c_int, dtor: Option<lua_Udestructor>);
pub fn lua_setuserdatadtor(
L: *mut lua_State,
tag: c_int,
dtor: Option<unsafe extern "C" fn(*mut lua_State, *mut c_void)>,
);
pub fn lua_clonefunction(L: *mut lua_State, idx: c_int);
}
+90 -25
View File
@@ -1,6 +1,7 @@
use std::mem;
use std::os::raw::c_int;
use std::os::raw::{c_int, c_void};
use std::ptr;
use std::slice;
use crate::error::{Error, Result};
use crate::ffi;
@@ -29,6 +30,17 @@ pub struct FunctionInfo {
pub last_line_defined: i32,
}
/// Luau function coverage snapshot.
#[cfg(any(feature = "luau", doc))]
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CoverageInfo {
pub function: Option<std::string::String>,
pub line_defined: i32,
pub depth: i32,
pub hits: Vec<i32>,
}
impl<'lua> Function<'lua> {
/// Calls the function, passing `args` as function arguments.
///
@@ -178,24 +190,17 @@ impl<'lua> Function<'lua> {
/// # }
/// ```
pub fn bind<A: ToLuaMulti<'lua>>(&self, args: A) -> Result<Function<'lua>> {
unsafe extern "C" fn bind_call_impl(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C" fn args_wrapper_impl(state: *mut ffi::lua_State) -> c_int {
let nargs = ffi::lua_gettop(state);
let nbinds = ffi::lua_tointeger(state, ffi::lua_upvalueindex(2)) as c_int;
ffi::luaL_checkstack(state, nbinds + 2, ptr::null());
ffi::lua_settop(state, nargs + nbinds + 1);
ffi::lua_rotate(state, -(nargs + nbinds + 1), nbinds + 1);
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(1));
ffi::lua_replace(state, 1);
let nbinds = ffi::lua_tointeger(state, ffi::lua_upvalueindex(1)) as c_int;
ffi::luaL_checkstack(state, nbinds, ptr::null());
for i in 0..nbinds {
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(i + 3));
ffi::lua_replace(state, i + 2);
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(i + 2));
}
ffi::lua_rotate(state, 1, nbinds);
ffi::lua_call(state, nargs + nbinds, ffi::LUA_MULTRET);
ffi::lua_gettop(state)
nargs + nbinds
}
let lua = self.0.lua;
@@ -203,25 +208,36 @@ impl<'lua> Function<'lua> {
let args = args.to_lua_multi(lua)?;
let nargs = args.len() as c_int;
if nargs + 2 > ffi::LUA_MAX_UPVALUES {
if nargs + 1 > ffi::LUA_MAX_UPVALUES {
return Err(Error::BindError);
}
unsafe {
let args_wrapper = unsafe {
let _sg = StackGuard::new(lua.state);
check_stack(lua.state, nargs + 5)?;
check_stack(lua.state, nargs + 3)?;
lua.push_ref(&self.0);
ffi::lua_pushinteger(lua.state, nargs as ffi::lua_Integer);
for arg in args {
lua.push_value(arg)?;
}
protect_lua!(lua.state, nargs + 2, 1, fn(state) {
ffi::lua_pushcclosure(state, bind_call_impl, ffi::lua_gettop(state));
protect_lua!(lua.state, nargs + 1, 1, fn(state) {
ffi::lua_pushcclosure(state, args_wrapper_impl, ffi::lua_gettop(state));
})?;
Ok(Function(lua.pop_ref()))
}
Function(lua.pop_ref())
};
lua.load(
r#"
local func, args_wrapper = ...
return function(...)
return func(args_wrapper(...))
end
"#,
)
.try_cache()
.set_name("_mlua_bind")?
.call((self.clone(), args_wrapper))
}
/// Returns information about the function.
@@ -270,9 +286,6 @@ impl<'lua> Function<'lua> {
#[cfg(not(feature = "luau"))]
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
pub fn dump(&self, strip: bool) -> Vec<u8> {
use std::os::raw::c_void;
use std::slice;
unsafe extern "C" fn writer(
_state: *mut ffi::lua_State,
buf: *const c_void,
@@ -300,6 +313,58 @@ impl<'lua> Function<'lua> {
data
}
/// Retrieves recorded coverage information about this Lua function including inner calls.
///
/// This function takes a callback as an argument and calls it providing [`CoverageInfo`] snapshot
/// per each executed inner function.
///
/// Recording of coverage information is controlled by [`Compiler::set_coverage_level`] option.
///
/// Requires `feature = "luau"`
///
/// [`Compiler::set_coverage_level`]: crate::chunk::Compiler::set_coverage_level
#[cfg(any(feature = "luau", docsrs))]
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
pub fn coverage<F>(&self, mut func: F)
where
F: FnMut(CoverageInfo),
{
use std::ffi::CStr;
use std::os::raw::c_char;
unsafe extern "C" fn callback<F: FnMut(CoverageInfo)>(
data: *mut c_void,
function: *const c_char,
line_defined: c_int,
depth: c_int,
hits: *const c_int,
size: usize,
) {
let function = if !function.is_null() {
Some(CStr::from_ptr(function).to_string_lossy().to_string())
} else {
None
};
let rust_callback = &mut *(data as *mut F);
rust_callback(CoverageInfo {
function,
line_defined,
depth,
hits: slice::from_raw_parts(hits, size).to_vec(),
});
}
let lua = self.0.lua;
unsafe {
let _sg = StackGuard::new(lua.state);
assert_stack(lua.state, 1);
lua.push_ref(&self.0);
let func_ptr = &mut func as *mut F as *mut c_void;
ffi::lua_getcoverage(lua.state, -1, func_ptr, callback::<F>);
}
}
}
impl<'lua> PartialEq for Function<'lua> {
+2 -2
View File
@@ -72,7 +72,7 @@
//! [`serde::Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html
// mlua types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/mlua/0.8.0-beta.4")]
#![doc(html_root_url = "https://docs.rs/mlua/0.8.0-beta.5")]
// Deny warnings inside doc tests / examples. When this isn't present, rustdoc doesn't show *any*
// warnings at all.
#![doc(test(attr(deny(warnings))))]
@@ -128,7 +128,7 @@ pub use crate::hook::HookTriggers;
#[cfg(any(feature = "luau", doc))]
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
pub use crate::{chunk::Compiler, types::VmState};
pub use crate::{chunk::Compiler, function::CoverageInfo, types::VmState};
#[cfg(feature = "async")]
pub use crate::thread::AsyncThread;
+16 -8
View File
@@ -226,7 +226,7 @@ const MULTIVALUE_CACHE_SIZE: usize = 32;
/// Requires `feature = "send"`
#[cfg(feature = "send")]
#[cfg_attr(docsrs, doc(cfg(feature = "send")))]
unsafe impl Send for LuaInner {}
unsafe impl Send for Lua {}
#[cfg(not(feature = "module"))]
impl Drop for LuaInner {
@@ -2741,6 +2741,7 @@ impl Lua {
end
"#,
)
.try_cache()
.set_name("_mlua_async_poll")?
.set_environment(env)?
.into_function()
@@ -2910,6 +2911,18 @@ where
let nargs = ffi::lua_gettop(state);
// We need 2 extra stack spaces to store userdata and error/panic metatable.
// Luau workaround can be removed after solving https://github.com/Roblox/luau/issues/446
// Also see #142 and #153
if !cfg!(feature = "luau") || extra.wrapped_failures_cache.is_empty() {
let extra_stack = if nargs < 2 { 2 - nargs } else { 1 };
ffi::luaL_checkstack(
state,
extra_stack,
cstr!("not enough stack space for callback error handling"),
);
}
enum PreallocatedFailure {
New(*mut WrappedFailure),
Cached(i32),
@@ -2920,13 +2933,6 @@ where
let prealloc_failure = match extra.wrapped_failures_cache.pop() {
Some(index) => PreallocatedFailure::Cached(index),
None => {
// We need 2 extra stack spaces to store userdata and error/panic metatable.
let extra_stack = if nargs < 2 { 2 - nargs } else { 1 };
ffi::luaL_checkstack(
state,
extra_stack,
cstr!("not enough stack space for callback error handling"),
);
let ud = WrappedFailure::new_userdata(state);
ffi::lua_rotate(state, 1, 1);
PreallocatedFailure::New(ud)
@@ -2940,6 +2946,8 @@ where
}
PreallocatedFailure::Cached(index) => {
ffi::lua_settop(state, 0);
#[cfg(feature = "luau")]
assert_stack(state, 2);
ffi::lua_pushvalue(extra.ref_thread, index);
ffi::lua_xmove(extra.ref_thread, state, 1);
ffi::lua_pushnil(extra.ref_thread);
+1 -1
View File
@@ -21,7 +21,7 @@ pub use crate::HookTriggers as LuaHookTriggers;
#[cfg(feature = "luau")]
#[doc(no_inline)]
pub use crate::VmState as LuaVmState;
pub use crate::{CoverageInfo as LuaCoverageInfo, VmState as LuaVmState};
#[cfg(feature = "async")]
#[doc(no_inline)]
+9 -2
View File
@@ -320,10 +320,17 @@ impl<'lua, 'de> serde::Deserializer<'de> for Deserializer<'lua> {
self.deserialize_map(visitor)
}
#[inline]
fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes
byte_buf unit unit_struct newtype_struct
identifier ignored_any
byte_buf unit unit_struct identifier ignored_any
}
}
+14
View File
@@ -118,7 +118,17 @@ pub enum MetaMethod {
///
/// [`ipairs`]: https://www.lua.org/manual/5.2/manual.html#pdf-ipairs
#[cfg(any(feature = "lua52", feature = "luajit52", doc))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua52", feature = "luajit52"))))]
IPairs,
/// The `__iter` metamethod.
///
/// Executed before the iteration begins, and should return an iterator function like `next`
/// (or a custom one).
///
/// Requires `feature = "lua"`
#[cfg(any(feature = "luau", doc))]
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
Iter,
/// The `__close` metamethod.
///
/// Executed when a variable, that marked as to-be-closed, goes out of scope.
@@ -203,6 +213,8 @@ impl MetaMethod {
MetaMethod::Pairs => "__pairs",
#[cfg(any(feature = "lua52", feature = "luajit52"))]
MetaMethod::IPairs => "__ipairs",
#[cfg(feature = "luau")]
MetaMethod::Iter => "__iter",
#[cfg(feature = "lua54")]
MetaMethod::Close => "__close",
@@ -270,6 +282,8 @@ impl From<StdString> for MetaMethod {
"__pairs" => MetaMethod::Pairs,
#[cfg(any(feature = "lua52", feature = "luajit52"))]
"__ipairs" => MetaMethod::IPairs,
#[cfg(feature = "luau")]
"__iter" => MetaMethod::Iter,
#[cfg(feature = "lua54")]
"__close" => MetaMethod::Close,
+26 -1
View File
@@ -1,5 +1,6 @@
use std::iter::{self, FromIterator};
use std::{slice, str, vec};
use std::os::raw::c_void;
use std::{ptr, slice, str, vec};
#[cfg(feature = "serialize")]
use {
@@ -9,6 +10,7 @@ use {
};
use crate::error::{Error, Result};
use crate::ffi;
use crate::function::Function;
use crate::lua::Lua;
use crate::string::String;
@@ -93,6 +95,29 @@ impl<'lua> Value<'lua> {
_ => Ok(self == other.as_ref()),
}
}
/// Converts the value to a generic C pointer.
///
/// The value can be a userdata, a table, a thread, a string, or a function; otherwise it returns NULL.
/// Different objects will give different pointers.
/// There is no way to convert the pointer back to its original value.
///
/// Typically this function is used only for hashing and debug information.
pub fn to_pointer(&self) -> *const c_void {
unsafe {
match self {
Value::LightUserData(ud) => ud.0,
Value::String(String(v))
| Value::Table(Table(v))
| Value::Function(Function(v))
| Value::Thread(Thread(v))
| Value::UserData(AnyUserData(v)) => v
.lua
.ref_thread_exec(|refthr| ffi::lua_topointer(refthr, v.index)),
_ => ptr::null(),
}
}
}
}
impl<'lua> PartialEq for Value<'lua> {
+4 -1
View File
@@ -75,7 +75,10 @@ async fn test_async_call() -> Result<()> {
async fn test_async_bind_call() -> Result<()> {
let lua = Lua::new();
let sum = lua.create_async_function(|_lua, (a, b): (i64, i64)| async move { Ok(a + b) })?;
let sum = lua.create_async_function(|_lua, (a, b): (i64, i64)| async move {
tokio::task::yield_now().await;
Ok(a + b)
})?;
let plus_10 = sum.bind(10)?;
lua.globals().set("plus_10", plus_10)?;
+74 -1
View File
@@ -5,7 +5,7 @@ use std::fs;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use mlua::{Compiler, Error, Lua, Result, Table, ThreadStatus, Value, VmState};
use mlua::{Compiler, CoverageInfo, Error, Lua, Result, Table, ThreadStatus, Value, VmState};
#[test]
fn test_require() -> Result<()> {
@@ -212,3 +212,76 @@ fn test_interrupts() -> Result<()> {
Ok(())
}
#[test]
fn test_coverate() -> Result<()> {
let lua = Lua::new();
lua.set_compiler(Compiler::default().set_coverage_level(1));
let f = lua
.load(
r#"local v = vector(1, 2, 3)
assert(v.x == 1 and v.y == 2 and v.z == 3)
function abc(i)
if i < 5 then
return 0
else
return 1
end
end
(function()
(function() abc(10) end)()
end)()
"#,
)
.into_function()?;
f.call(())?;
let mut report = Vec::new();
f.coverage(|cov| {
report.push(cov);
});
assert_eq!(
report[0],
CoverageInfo {
function: None,
line_defined: 1,
depth: 0,
hits: vec![-1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1],
}
);
assert_eq!(
report[1],
CoverageInfo {
function: Some("abc".into()),
line_defined: 4,
depth: 1,
hits: vec![-1, -1, -1, -1, -1, 1, 0, -1, 1, -1, -1, -1, -1, -1, -1, -1],
}
);
assert_eq!(
report[2],
CoverageInfo {
function: None,
line_defined: 12,
depth: 1,
hits: vec![-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1],
}
);
assert_eq!(
report[3],
CoverageInfo {
function: None,
line_defined: 13,
depth: 2,
hits: vec![-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1],
}
);
Ok(())
}
+8 -5
View File
@@ -1,8 +1,11 @@
[target.x86_64-apple-darwin]
rustflags = ["-C", "link-args=-rdynamic"]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]
[target.aarch64-apple-darwin]
rustflags = ["-C", "link-args=-rdynamic"]
[target.x86_64-unknown-linux-gnu]
rustflags = ["-C", "link-args=-rdynamic"]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]
+10 -3
View File
@@ -1,16 +1,23 @@
[package]
name = "module_runner"
name = "rust_module"
version = "0.0.0"
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
edition = "2018"
[lib]
crate-type = ["cdylib"]
[workspace]
members = [
"loader",
]
[features]
lua54 = ["mlua/lua54"]
lua53 = ["mlua/lua53"]
lua52 = ["mlua/lua52"]
lua51 = ["mlua/lua51"]
luajit = ["mlua/luajit"]
vendored = ["mlua/vendored"]
[dependencies]
mlua = { path = "../.." }
mlua = { path = "../..", features = ["module"] }
+8
View File
@@ -0,0 +1,8 @@
[target.x86_64-apple-darwin]
rustflags = ["-C", "link-args=-rdynamic"]
[target.aarch64-apple-darwin]
rustflags = ["-C", "link-args=-rdynamic"]
[target.x86_64-unknown-linux-gnu]
rustflags = ["-C", "link-args=-rdynamic"]
+16
View File
@@ -0,0 +1,16 @@
[package]
name = "module_loader"
version = "0.0.0"
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
edition = "2018"
[features]
lua54 = ["mlua/lua54"]
lua53 = ["mlua/lua53"]
lua52 = ["mlua/lua52"]
lua51 = ["mlua/lua51"]
luajit = ["mlua/luajit"]
vendored = ["mlua/vendored"]
[dependencies]
mlua = { path = "../../.." }
+39
View File
@@ -0,0 +1,39 @@
use mlua::prelude::*;
fn sum(_: &Lua, (a, b): (i64, i64)) -> LuaResult<i64> {
Ok(a + b)
}
fn used_memory(lua: &Lua, _: ()) -> LuaResult<usize> {
Ok(lua.used_memory())
}
fn check_userdata(_: &Lua, ud: MyUserData) -> LuaResult<i32> {
Ok(ud.0)
}
#[mlua::lua_module]
fn rust_module(lua: &Lua) -> LuaResult<LuaTable> {
let exports = lua.create_table()?;
exports.set("sum", lua.create_function(sum)?)?;
exports.set("used_memory", lua.create_function(used_memory)?)?;
exports.set("check_userdata", lua.create_function(check_userdata)?)?;
Ok(exports)
}
#[derive(Clone, Copy)]
struct MyUserData(i32);
impl LuaUserData for MyUserData {}
#[mlua::lua_module]
fn rust_module_second(lua: &Lua) -> LuaResult<LuaTable> {
let exports = lua.create_table()?;
exports.set("userdata", lua.create_userdata(MyUserData(123))?)?;
Ok(exports)
}
#[mlua::lua_module]
fn rust_module_error(_: &Lua) -> LuaResult<LuaTable> {
Err("custom module error".to_lua_err())
}
+13
View File
@@ -375,6 +375,19 @@ fn test_from_value_struct() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
#[test]
fn test_from_value_newtype_struct() -> Result<(), Box<dyn std::error::Error>> {
let lua = Lua::new();
#[derive(Deserialize, PartialEq, Debug)]
struct Test(f64);
let got = lua.from_value(Value::Number(123.456))?;
assert_eq!(Test(123.456), got);
Ok(())
}
#[test]
fn test_from_value_enum() -> Result<(), Box<dyn std::error::Error>> {
let lua = Lua::new();
+12 -4
View File
@@ -1,3 +1,5 @@
use std::ptr;
use mlua::{Lua, Result, Value};
#[test]
@@ -41,17 +43,23 @@ fn test_value_eq() -> Result<()> {
let thread2: Value = globals.get("thread2")?;
assert!(table1 != table2);
assert!(table1.equals(table2)?);
assert!(table1.equals(&table2)?);
assert!(string1 == string2);
assert!(string1.equals(string2)?);
assert!(string1.equals(&string2)?);
assert!(num1 == num2);
assert!(num1.equals(num2)?);
assert!(num1 != num3);
assert!(func1 == func2);
assert!(func1 != func3);
assert!(!func1.equals(func3)?);
assert!(!func1.equals(&func3)?);
assert!(thread1 == thread2);
assert!(thread1.equals(thread2)?);
assert!(thread1.equals(&thread2)?);
assert!(!table1.to_pointer().is_null());
assert!(!ptr::eq(table1.to_pointer(), table2.to_pointer()));
assert!(ptr::eq(string1.to_pointer(), string2.to_pointer()));
assert!(ptr::eq(func1.to_pointer(), func2.to_pointer()));
assert!(num1.to_pointer().is_null());
Ok(())
}