mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f06f614a9 | |||
| 30ba616a8a | |||
| 0076aa735a | |||
| bcf2cbea37 | |||
| 8cd594c609 | |||
| 8d71ea79aa | |||
| 2a8c5c7f82 | |||
| 6b2ceb60c4 | |||
| 3aac7131ee | |||
| 1807fa789c | |||
| 7db7526a08 | |||
| bea9b0f8b5 | |||
| 32a3f478bd | |||
| 294b3b7aae | |||
| b0dabe9d3c | |||
| 5133a9837a | |||
| 790df77965 | |||
| a62636fde0 | |||
| d77c0e3b8d | |||
| 3904213ed0 | |||
| a5ce0c1409 | |||
| dba76f3994 | |||
| 86f506a170 | |||
| d3975bdf30 | |||
| 21affdadfd | |||
| 17473269f8 | |||
| 88e3e92009 | |||
| 1ba7a409d5 | |||
| ef81f40afa | |||
| a018d3b6dc | |||
| 0215c31a3a | |||
| 5cd82d0f6b | |||
| 75697e3a3b | |||
| d1c80be033 | |||
| a8fef51e86 | |||
| 28a063c1e5 | |||
| 55fac90a74 | |||
| 70d287cf9f |
+13
-13
@@ -28,7 +28,7 @@ jobs:
|
||||
- name: Build ${{ matrix.lua }} vendored
|
||||
run: |
|
||||
cargo build --features "${{ matrix.lua }},vendored"
|
||||
cargo build --features "${{ matrix.lua }},vendored,async,send,serialize,macros"
|
||||
cargo build --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot"
|
||||
shell: bash
|
||||
- name: Build ${{ matrix.lua }} pkg-config
|
||||
if: ${{ matrix.os == 'ubuntu-20.04' && matrix.lua != 'lua54' }}
|
||||
@@ -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:
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
target: aarch64-apple-darwin
|
||||
override: true
|
||||
- name: Cross-compile
|
||||
run: cargo build --target aarch64-apple-darwin --features "${{ matrix.lua }},vendored,async,send,serialize,macros"
|
||||
run: cargo build --target aarch64-apple-darwin --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot"
|
||||
|
||||
build_aarch64_cross_ubuntu:
|
||||
name: Cross-compile to aarch64-unknown-linux-gnu
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
sudo apt-get install -y --no-install-recommends gcc-aarch64-linux-gnu libc6-dev-arm64-cross
|
||||
shell: bash
|
||||
- name: Cross-compile
|
||||
run: cargo build --target aarch64-unknown-linux-gnu --features "${{ matrix.lua }},vendored,async,send,serialize,macros"
|
||||
run: cargo build --target aarch64-unknown-linux-gnu --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot"
|
||||
shell: bash
|
||||
|
||||
build_armv7_cross_ubuntu:
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
sudo apt-get install -y --no-install-recommends gcc-arm-linux-gnueabihf libc-dev-armhf-cross
|
||||
shell: bash
|
||||
- name: Cross-compile
|
||||
run: cargo build --target armv7-unknown-linux-gnueabihf --features "${{ matrix.lua }},vendored,async,send,serialize,macros"
|
||||
run: cargo build --target armv7-unknown-linux-gnueabihf --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot"
|
||||
shell: bash
|
||||
|
||||
test:
|
||||
@@ -127,13 +127,13 @@ jobs:
|
||||
- name: Run ${{ matrix.lua }} tests
|
||||
run: |
|
||||
cargo test --features "${{ matrix.lua }},vendored"
|
||||
cargo test --features "${{ matrix.lua }},vendored,async,send,serialize,macros"
|
||||
cargo test --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot"
|
||||
shell: bash
|
||||
- name: Run compile tests (macos lua54)
|
||||
if: ${{ matrix.os == 'macos-latest' && matrix.lua == 'lua54' }}
|
||||
run: |
|
||||
TRYBUILD=overwrite cargo test --features "${{ matrix.lua }},vendored" -- --ignored
|
||||
TRYBUILD=overwrite cargo test --features "${{ matrix.lua }},vendored,async,send,serialize,macros" -- --ignored
|
||||
TRYBUILD=overwrite cargo test --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot" -- --ignored
|
||||
shell: bash
|
||||
|
||||
test_with_sanitizer:
|
||||
@@ -159,7 +159,7 @@ jobs:
|
||||
- name: Run ${{ matrix.lua }} tests with address sanitizer
|
||||
run: |
|
||||
RUSTFLAGS="-Z sanitizer=address" \
|
||||
cargo test --tests --features "${{ matrix.lua }},vendored,async,send,serialize,macros" --target x86_64-unknown-linux-gnu -- --skip test_too_many_recursions
|
||||
cargo test --tests --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot" --target x86_64-unknown-linux-gnu -- --skip test_too_many_recursions
|
||||
shell: bash
|
||||
|
||||
test_modules:
|
||||
@@ -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
|
||||
@@ -239,4 +239,4 @@ jobs:
|
||||
- uses: actions-rs/clippy-check@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --features "${{ matrix.lua }},vendored,async,send,serialize,macros"
|
||||
args: --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot"
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
## 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)
|
||||
- Enabled `Lua::gc_inc` for Luau
|
||||
- Luau `debug` module marked as safe (enabled by default)
|
||||
- Implemented `Hash` for Lua String
|
||||
- Support mode options in `collectgarbage` for Luau
|
||||
- Added ability to set global Luau compiler (used for loading all chunks).
|
||||
- Refactored `AsChunk` trait (breaking changes).
|
||||
`AsChunk` now implemented for `Path` and `PathBuf` to load lua files from fs.
|
||||
- Added `parking_lot` dependency and feature flag (for `UserData`)
|
||||
- Added `Function::info()` to get information about functions (#149).
|
||||
- Bugfixes and improvements (#104 #142)
|
||||
|
||||
## v0.8.0-beta.3
|
||||
|
||||
- Luau vector constructor
|
||||
|
||||
+5
-6
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mlua"
|
||||
version = "0.8.0-beta.3" # 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"
|
||||
@@ -17,14 +17,12 @@ with async/await features and support of writing native Lua modules in Rust.
|
||||
"""
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["lua54", "vendored", "async", "send", "serialize", "macros"]
|
||||
features = ["lua54", "vendored", "async", "send", "serialize", "macros", "parking_lot"]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"mlua_derive",
|
||||
"examples/module",
|
||||
"tests/module",
|
||||
]
|
||||
|
||||
[features]
|
||||
@@ -43,7 +41,7 @@ serialize = ["serde", "erased-serde"]
|
||||
macros = ["mlua_derive/macros"]
|
||||
|
||||
[dependencies]
|
||||
mlua_derive = { version = "=0.6.0", optional = true, path = "mlua_derive" }
|
||||
mlua_derive = { version = "=0.8.0-beta.1", 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" }
|
||||
@@ -53,13 +51,14 @@ futures-task = { version = "0.3.5", optional = true }
|
||||
futures-util = { version = "0.3.5", optional = true }
|
||||
serde = { version = "1.0", optional = true }
|
||||
erased-serde = { version = "0.3", optional = true }
|
||||
parking_lot = { version = "0.12", optional = true }
|
||||
|
||||
[build-dependencies]
|
||||
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"
|
||||
|
||||
@@ -43,6 +43,7 @@ Below is a list of the available feature flags. By default `mlua` does not enabl
|
||||
* `send`: make `mlua::Lua` transferable across thread boundaries (adds [`Send`] requirement to `mlua::Function` and `mlua::UserData`)
|
||||
* `serialize`: add serialization and deserialization support to `mlua` types using [serde] framework
|
||||
* `macros`: enable procedural macros (such as `chunk!`)
|
||||
* `parking_lot`: support UserData types wrapped in [parking_lot]'s primitives (`Arc<Mutex>` and `Arc<RwLock>`)
|
||||
|
||||
[5.4]: https://www.lua.org/manual/5.4/manual.html
|
||||
[5.3]: https://www.lua.org/manual/5.3/manual.html
|
||||
@@ -56,6 +57,7 @@ Below is a list of the available feature flags. By default `mlua` does not enabl
|
||||
[async-std]: https://github.com/async-rs/async-std
|
||||
[`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
|
||||
[serde]: https://github.com/serde-rs/serde
|
||||
[parking_lot]: https://github.com/Amanieu/parking_lot
|
||||
|
||||
### Async/await support
|
||||
|
||||
@@ -104,7 +106,7 @@ Add to `Cargo.toml` :
|
||||
|
||||
``` toml
|
||||
[dependencies]
|
||||
mlua = { version = "0.8.0-beta.3", features = ["lua54", "vendored"] }
|
||||
mlua = { version = "0.8.0-beta.5", features = ["lua54", "vendored"] }
|
||||
```
|
||||
|
||||
`main.rs`
|
||||
@@ -139,7 +141,7 @@ Add to `Cargo.toml` :
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
mlua = { version = "0.8.0-beta.3", features = ["lua54", "vendored", "module"] }
|
||||
mlua = { version = "0.8.0-beta.5", features = ["lua54", "vendored", "module"] }
|
||||
```
|
||||
|
||||
`lib.rs` :
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn probe_lua() -> Option<PathBuf> {
|
||||
unreachable!()
|
||||
None
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::env;
|
||||
use std::ops::Bound;
|
||||
use std::path::PathBuf;
|
||||
@@ -79,7 +81,7 @@ pub fn probe_lua() -> Option<PathBuf> {
|
||||
#[cfg(feature = "luajit")]
|
||||
{
|
||||
let lua = pkg_config::Config::new()
|
||||
.range_version((Bound::Included("2.0.5"), Bound::Unbounded))
|
||||
.range_version((Bound::Included("2.0.4"), Bound::Unbounded))
|
||||
.cargo_metadata(need_lua_lib)
|
||||
.probe("luajit");
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mlua_derive"
|
||||
version = "0.6.0"
|
||||
version = "0.8.0-beta.1"
|
||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
|
||||
edition = "2018"
|
||||
description = "Procedural macros for the mlua crate."
|
||||
@@ -21,4 +21,4 @@ proc-macro-error = { version = "1.0", optional = true }
|
||||
syn = { version = "1.0", features = ["full"] }
|
||||
itertools = { version = "0.10", optional = true }
|
||||
regex = { version = "1.4", optional = true }
|
||||
once_cell = { version = "1.5", optional = true }
|
||||
once_cell = { version = "1.0", optional = true }
|
||||
|
||||
@@ -62,6 +62,8 @@ pub fn chunk(input: TokenStream) -> TokenStream {
|
||||
|
||||
let wrapped_code = quote! {{
|
||||
use ::mlua::{AsChunk, ChunkMode, Lua, Result, Value};
|
||||
use ::std::borrow::Cow;
|
||||
use ::std::io::Result as IoResult;
|
||||
use ::std::marker::PhantomData;
|
||||
use ::std::sync::Mutex;
|
||||
|
||||
@@ -73,8 +75,8 @@ pub fn chunk(input: TokenStream) -> TokenStream {
|
||||
where
|
||||
F: FnOnce(&'lua Lua) -> Result<Value<'lua>>,
|
||||
{
|
||||
fn source(&self) -> &[u8] {
|
||||
(#source).as_bytes()
|
||||
fn source(&self) -> IoResult<Cow<[u8]>> {
|
||||
Ok(Cow::Borrowed((#source).as_bytes()))
|
||||
}
|
||||
|
||||
fn env(&self, lua: &'lua Lua) -> Result<Option<Value<'lua>>> {
|
||||
|
||||
+160
-135
@@ -1,5 +1,9 @@
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CString;
|
||||
use std::io::Result as IoResult;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::string::String as StdString;
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
@@ -16,10 +20,10 @@ use {futures_core::future::LocalBoxFuture, futures_util::future};
|
||||
/// [`Chunk`]: crate::Chunk
|
||||
pub trait AsChunk<'lua> {
|
||||
/// Returns chunk data (can be text or binary)
|
||||
fn source(&self) -> &[u8];
|
||||
fn source(&self) -> IoResult<Cow<[u8]>>;
|
||||
|
||||
/// Returns optional chunk name
|
||||
fn name(&self) -> Option<CString> {
|
||||
fn name(&self) -> Option<StdString> {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -36,9 +40,47 @@ pub trait AsChunk<'lua> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: AsRef<[u8]> + ?Sized> AsChunk<'lua> for T {
|
||||
fn source(&self) -> &[u8] {
|
||||
self.as_ref()
|
||||
impl<'lua> AsChunk<'lua> for str {
|
||||
fn source(&self) -> IoResult<Cow<[u8]>> {
|
||||
Ok(Cow::Borrowed(self.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsChunk<'lua> for StdString {
|
||||
fn source(&self) -> IoResult<Cow<[u8]>> {
|
||||
Ok(Cow::Borrowed(self.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsChunk<'lua> for [u8] {
|
||||
fn source(&self) -> IoResult<Cow<[u8]>> {
|
||||
Ok(Cow::Borrowed(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsChunk<'lua> for Vec<u8> {
|
||||
fn source(&self) -> IoResult<Cow<[u8]>> {
|
||||
Ok(Cow::Borrowed(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsChunk<'lua> for Path {
|
||||
fn source(&self) -> IoResult<Cow<[u8]>> {
|
||||
std::fs::read(self).map(Cow::Owned)
|
||||
}
|
||||
|
||||
fn name(&self) -> Option<StdString> {
|
||||
Some(format!("@{}", self.display()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsChunk<'lua> for PathBuf {
|
||||
fn source(&self) -> IoResult<Cow<[u8]>> {
|
||||
std::fs::read(self).map(Cow::Owned)
|
||||
}
|
||||
|
||||
fn name(&self) -> Option<StdString> {
|
||||
Some(format!("@{}", self.display()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,8 +90,8 @@ impl<'lua, T: AsRef<[u8]> + ?Sized> AsChunk<'lua> for T {
|
||||
#[must_use = "`Chunk`s do nothing unless one of `exec`, `eval`, `call`, or `into_function` are called on them"]
|
||||
pub struct Chunk<'lua, 'a> {
|
||||
pub(crate) lua: &'lua Lua,
|
||||
pub(crate) source: Cow<'a, [u8]>,
|
||||
pub(crate) name: Option<CString>,
|
||||
pub(crate) source: IoResult<Cow<'a, [u8]>>,
|
||||
pub(crate) name: Option<StdString>,
|
||||
pub(crate) env: Result<Option<Value<'lua>>>,
|
||||
pub(crate) mode: Option<ChunkMode>,
|
||||
#[cfg(feature = "luau")]
|
||||
@@ -104,7 +146,7 @@ impl Compiler {
|
||||
/// * 0 - no optimization
|
||||
/// * 1 - baseline optimization level that doesn't prevent debuggability (default)
|
||||
/// * 2 - includes optimizations that harm debuggability such as inlining
|
||||
pub fn set_optimization_level(&mut self, level: u8) -> &mut Self {
|
||||
pub fn set_optimization_level(mut self, level: u8) -> Self {
|
||||
self.optimization_level = level;
|
||||
self
|
||||
}
|
||||
@@ -115,7 +157,7 @@ impl Compiler {
|
||||
/// * 0 - no debugging support
|
||||
/// * 1 - line info & function names only; sufficient for backtraces (default)
|
||||
/// * 2 - full debug info with local & upvalue names; necessary for debugger
|
||||
pub fn set_debug_level(&mut self, level: u8) -> &mut Self {
|
||||
pub fn set_debug_level(mut self, level: u8) -> Self {
|
||||
self.debug_level = level;
|
||||
self
|
||||
}
|
||||
@@ -126,19 +168,19 @@ impl Compiler {
|
||||
/// * 0 - no code coverage support (default)
|
||||
/// * 1 - statement coverage
|
||||
/// * 2 - statement and expression coverage (verbose)
|
||||
pub fn set_coverage_level(&mut self, level: u8) -> &mut Self {
|
||||
pub fn set_coverage_level(mut self, level: u8) -> Self {
|
||||
self.coverage_level = level;
|
||||
self
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn set_vector_lib(&mut self, lib: Option<String>) -> &mut Self {
|
||||
pub fn set_vector_lib(mut self, lib: Option<String>) -> Self {
|
||||
self.vector_lib = lib;
|
||||
self
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn set_vector_ctor(&mut self, ctor: Option<String>) -> &mut Self {
|
||||
pub fn set_vector_ctor(mut self, ctor: Option<String>) -> Self {
|
||||
self.vector_ctor = ctor;
|
||||
self
|
||||
}
|
||||
@@ -146,7 +188,7 @@ impl Compiler {
|
||||
/// Sets a list of globals that are mutable.
|
||||
///
|
||||
/// It disables the import optimization for fields accessed through these.
|
||||
pub fn set_mutable_globals(&mut self, globals: Vec<String>) -> &mut Self {
|
||||
pub fn set_mutable_globals(mut self, globals: Vec<String>) -> Self {
|
||||
self.mutable_globals = globals;
|
||||
self
|
||||
}
|
||||
@@ -174,7 +216,7 @@ impl Compiler {
|
||||
.map(|s| s.as_ptr())
|
||||
.collect::<Vec<_>>();
|
||||
let mut mutable_globals_ptr = ptr::null_mut();
|
||||
if mutable_globals.len() > 0 {
|
||||
if !mutable_globals.is_empty() {
|
||||
mutable_globals.push(ptr::null());
|
||||
mutable_globals_ptr = mutable_globals.as_mut_ptr();
|
||||
}
|
||||
@@ -195,14 +237,10 @@ impl Compiler {
|
||||
|
||||
impl<'lua, 'a> Chunk<'lua, 'a> {
|
||||
/// Sets the name of this chunk, which results in more informative error traces.
|
||||
pub fn set_name<S: AsRef<[u8]> + ?Sized>(mut self, name: &S) -> Result<Self> {
|
||||
let name =
|
||||
CString::new(name.as_ref().to_vec()).map_err(|e| Error::ToLuaConversionError {
|
||||
from: "&str",
|
||||
to: "string",
|
||||
message: Some(e.to_string()),
|
||||
})?;
|
||||
self.name = Some(name);
|
||||
pub fn set_name(mut self, name: impl AsRef<str>) -> Result<Self> {
|
||||
self.name = Some(name.as_ref().to_string());
|
||||
// Do extra validation
|
||||
let _ = self.convert_name()?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
@@ -232,96 +270,15 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets Luau compiler optimization level.
|
||||
/// Sets or overwrites a Luau compiler used for this chunk.
|
||||
///
|
||||
/// See [`Compiler::set_optimization_level`] for details.
|
||||
/// See [`Compiler`] for details and possible options.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn set_optimization_level(mut self, level: u8) -> Self {
|
||||
self.compiler
|
||||
.get_or_insert_with(Default::default)
|
||||
.set_optimization_level(level);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets Luau compiler debug level.
|
||||
///
|
||||
/// See [`Compiler::set_debug_level`] for details.
|
||||
///
|
||||
/// Requires `feature = "luau`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn set_debug_level(mut self, level: u8) -> Self {
|
||||
self.compiler
|
||||
.get_or_insert_with(Default::default)
|
||||
.set_debug_level(level);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets Luau compiler code coverage level.
|
||||
///
|
||||
/// See [`Compiler::set_coverage_level`] for details.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn set_coverage_level(mut self, level: u8) -> Self {
|
||||
self.compiler
|
||||
.get_or_insert_with(Default::default)
|
||||
.set_coverage_level(level);
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
#[doc(hidden)]
|
||||
pub fn set_vector_lib(mut self, lib: Option<String>) -> Self {
|
||||
self.compiler
|
||||
.get_or_insert_with(Default::default)
|
||||
.set_vector_lib(lib);
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
#[doc(hidden)]
|
||||
pub fn set_vector_ctor(mut self, ctor: Option<String>) -> Self {
|
||||
self.compiler
|
||||
.get_or_insert_with(Default::default)
|
||||
.set_vector_ctor(ctor);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets a list of globals that are mutable for Luau compiler.
|
||||
///
|
||||
/// See [`Compiler::set_mutable_globals`] for details.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn set_mutable_globals(mut self, globals: Vec<String>) -> Self {
|
||||
self.compiler
|
||||
.get_or_insert_with(Default::default)
|
||||
.set_mutable_globals(globals);
|
||||
self
|
||||
}
|
||||
|
||||
/// Compiles the chunk and changes mode to binary.
|
||||
///
|
||||
/// It does nothing if the chunk is already binary.
|
||||
#[cfg(feature = "luau")]
|
||||
#[doc(hidden)]
|
||||
pub fn compile(mut self) -> Self {
|
||||
if self.detect_mode() == ChunkMode::Text {
|
||||
let data = self
|
||||
.compiler
|
||||
.get_or_insert_with(Default::default)
|
||||
.compile(self.source.as_ref());
|
||||
self.mode = Some(ChunkMode::Binary);
|
||||
self.source = Cow::Owned(data);
|
||||
}
|
||||
pub fn set_compiler(mut self, compiler: Compiler) -> Self {
|
||||
self.compiler = Some(compiler);
|
||||
self
|
||||
}
|
||||
|
||||
@@ -422,38 +379,89 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
|
||||
/// Load this chunk into a regular `Function`.
|
||||
///
|
||||
/// This simply compiles the chunk without actually executing it.
|
||||
pub fn into_function(self) -> Result<Function<'lua>> {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
let self_ = self;
|
||||
#[cfg_attr(not(feature = "luau"), allow(unused_mut))]
|
||||
pub fn into_function(mut self) -> Result<Function<'lua>> {
|
||||
#[cfg(feature = "luau")]
|
||||
let self_ = match self.compiler {
|
||||
// We don't need to compile source if no compiler options set
|
||||
Some(_) => self.compile(),
|
||||
_ => self,
|
||||
};
|
||||
if self.compiler.is_some() {
|
||||
// We don't need to compile source if no compiler set
|
||||
self.compile();
|
||||
}
|
||||
|
||||
self_.lua.load_chunk(
|
||||
self_.source.as_ref(),
|
||||
self_.name.as_ref(),
|
||||
self_.env()?,
|
||||
self_.mode,
|
||||
)
|
||||
let name = self.convert_name()?;
|
||||
self.lua
|
||||
.load_chunk(self.source?.as_ref(), name.as_deref(), self.env?, self.mode)
|
||||
}
|
||||
|
||||
fn env(&self) -> Result<Option<Value<'lua>>> {
|
||||
self.env.clone()
|
||||
/// Compiles the chunk and changes mode to binary.
|
||||
///
|
||||
/// It does nothing if the chunk is already binary.
|
||||
fn compile(&mut self) {
|
||||
if let Ok(ref source) = self.source {
|
||||
if self.detect_mode() == ChunkMode::Text {
|
||||
#[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expression_source(&self) -> Vec<u8> {
|
||||
let mut buf = Vec::with_capacity(b"return ".len() + self.source.len());
|
||||
buf.extend(b"return ");
|
||||
buf.extend(self.source.as_ref());
|
||||
buf
|
||||
/// 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.expression_source();
|
||||
let source = self.source.as_ref();
|
||||
let source = source.map_err(|err| Error::RuntimeError(err.to_string()))?;
|
||||
let source = Self::expression_source(source);
|
||||
// We don't need to compile source if no compiler options set
|
||||
#[cfg(feature = "luau")]
|
||||
let source = self
|
||||
@@ -462,24 +470,41 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
|
||||
.map(|c| c.compile(&source))
|
||||
.unwrap_or(source);
|
||||
|
||||
let name = self.convert_name()?;
|
||||
self.lua
|
||||
.load_chunk(&source, self.name.as_ref(), self.env()?, None)
|
||||
.load_chunk(&source, name.as_deref(), self.env.clone()?, None)
|
||||
}
|
||||
|
||||
fn detect_mode(&self) -> ChunkMode {
|
||||
match self.mode {
|
||||
Some(mode) => mode,
|
||||
None => {
|
||||
match (self.mode, &self.source) {
|
||||
(Some(mode), _) => mode,
|
||||
(None, Ok(source)) => {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
if self.source.starts_with(ffi::LUA_SIGNATURE) {
|
||||
if source.starts_with(ffi::LUA_SIGNATURE) {
|
||||
return ChunkMode::Binary;
|
||||
}
|
||||
#[cfg(feature = "luau")]
|
||||
if self.source[0] < b'\n' {
|
||||
if *source.get(0).unwrap_or(&u8::MAX) < b'\n' {
|
||||
return ChunkMode::Binary;
|
||||
}
|
||||
ChunkMode::Text
|
||||
}
|
||||
(None, Err(_)) => ChunkMode::Text, // any value is fine
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_name(&self) -> Result<Option<CString>> {
|
||||
self.name
|
||||
.clone()
|
||||
.map(CString::new)
|
||||
.transpose()
|
||||
.map_err(|err| Error::RuntimeError(format!("invalid name: {err}")))
|
||||
}
|
||||
|
||||
fn expression_source(source: &[u8]) -> Vec<u8> {
|
||||
let mut buf = Vec::with_capacity(b"return ".len() + source.len());
|
||||
buf.extend(b"return ");
|
||||
buf.extend(source);
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +155,13 @@ pub unsafe fn lua_absindex(L: *mut lua_State, mut idx: c_int) -> c_int {
|
||||
|
||||
pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
|
||||
idx = lua_absindex(L, idx);
|
||||
if n > 0 {
|
||||
// Faster version
|
||||
for _ in 0..n {
|
||||
lua_insert(L, idx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let n_elems = lua_gettop(L) - idx + 1;
|
||||
if n < 0 {
|
||||
n += n_elems;
|
||||
|
||||
@@ -27,6 +27,13 @@ unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
|
||||
|
||||
pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
|
||||
idx = lua_absindex(L, idx);
|
||||
if n > 0 {
|
||||
// Faster version
|
||||
for _ in 0..n {
|
||||
lua_insert(L, idx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let n_elems = lua_gettop(L) - idx + 1;
|
||||
if n < 0 {
|
||||
n += n_elems;
|
||||
|
||||
@@ -90,6 +90,13 @@ unsafe fn compat53_pushfuncname(L: *mut lua_State, level: c_int, ar: *mut lua_De
|
||||
|
||||
pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
|
||||
idx = lua_absindex(L, idx);
|
||||
if n > 0 {
|
||||
// Faster version
|
||||
for _ in 0..n {
|
||||
lua_insert(L, idx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let n_elems = lua_gettop(L) - idx + 1;
|
||||
if n < 0 {
|
||||
n += n_elems;
|
||||
|
||||
+5
-1
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+144
-25
@@ -1,10 +1,14 @@
|
||||
use std::os::raw::c_int;
|
||||
use std::mem;
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::types::LuaRef;
|
||||
use crate::util::{assert_stack, check_stack, error_traceback, pop_error, StackGuard};
|
||||
use crate::util::{
|
||||
assert_stack, check_stack, error_traceback, pop_error, ptr_to_cstr_bytes, StackGuard,
|
||||
};
|
||||
use crate::value::{FromLuaMulti, ToLuaMulti};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
@@ -14,6 +18,29 @@ use {futures_core::future::LocalBoxFuture, futures_util::future};
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Function<'lua>(pub(crate) LuaRef<'lua>);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FunctionInfo {
|
||||
pub name: Option<Vec<u8>>,
|
||||
pub name_what: Option<Vec<u8>>,
|
||||
pub what: Option<Vec<u8>>,
|
||||
pub source: Option<Vec<u8>>,
|
||||
pub short_src: Option<Vec<u8>>,
|
||||
pub line_defined: i32,
|
||||
#[cfg(not(feature = "luau"))]
|
||||
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.
|
||||
///
|
||||
@@ -163,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;
|
||||
@@ -188,24 +208,70 @@ 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.
|
||||
///
|
||||
/// Corresponds to the `>Sn` what mask for [`lua_getinfo`] when applied to the function.
|
||||
///
|
||||
/// [`lua_getinfo`]: https://www.lua.org/manual/5.4/manual.html#lua_getinfo
|
||||
pub fn info(&self) -> FunctionInfo {
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
assert_stack(lua.state, 1);
|
||||
|
||||
let mut ar: ffi::lua_Debug = mem::zeroed();
|
||||
lua.push_ref(&self.0);
|
||||
#[cfg(not(feature = "luau"))]
|
||||
let res = ffi::lua_getinfo(lua.state, cstr!(">Sn"), &mut ar);
|
||||
#[cfg(feature = "luau")]
|
||||
let res = ffi::lua_getinfo(lua.state, -1, cstr!("sn"), &mut ar);
|
||||
mlua_assert!(res != 0, "lua_getinfo failed with `>Sn`");
|
||||
|
||||
FunctionInfo {
|
||||
name: ptr_to_cstr_bytes(ar.name).map(|s| s.to_vec()),
|
||||
#[cfg(not(feature = "luau"))]
|
||||
name_what: ptr_to_cstr_bytes(ar.namewhat).map(|s| s.to_vec()),
|
||||
#[cfg(feature = "luau")]
|
||||
name_what: None,
|
||||
what: ptr_to_cstr_bytes(ar.what).map(|s| s.to_vec()),
|
||||
source: ptr_to_cstr_bytes(ar.source).map(|s| s.to_vec()),
|
||||
short_src: ptr_to_cstr_bytes(&ar.short_src as *const _).map(|s| s.to_vec()),
|
||||
line_defined: ar.linedefined as i32,
|
||||
#[cfg(not(feature = "luau"))]
|
||||
last_line_defined: ar.lastlinedefined as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,12 +279,13 @@ impl<'lua> Function<'lua> {
|
||||
///
|
||||
/// If `strip` is true, the binary representation may not include all debug information
|
||||
/// about the function, to save space.
|
||||
///
|
||||
/// For Luau a [Compiler] can be used to compile Lua chunks to bytecode.
|
||||
///
|
||||
/// [Compiler]: crate::chunk::Compiler
|
||||
#[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,
|
||||
@@ -246,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> {
|
||||
|
||||
+7
-15
@@ -1,11 +1,11 @@
|
||||
use std::cell::UnsafeCell;
|
||||
use std::ffi::CStr;
|
||||
#[cfg(not(feature = "luau"))]
|
||||
use std::ops::{BitOr, BitOrAssign};
|
||||
use std::os::raw::{c_char, c_int};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use crate::ffi::{self, lua_Debug};
|
||||
use crate::lua::Lua;
|
||||
use crate::util::ptr_to_cstr_bytes;
|
||||
|
||||
/// Contains information about currently executing Lua code.
|
||||
///
|
||||
@@ -77,9 +77,9 @@ impl<'lua> Debug<'lua> {
|
||||
);
|
||||
|
||||
DebugNames {
|
||||
name: ptr_to_str((*self.ar.get()).name),
|
||||
name: ptr_to_cstr_bytes((*self.ar.get()).name),
|
||||
#[cfg(not(feature = "luau"))]
|
||||
name_what: ptr_to_str((*self.ar.get()).namewhat),
|
||||
name_what: ptr_to_cstr_bytes((*self.ar.get()).namewhat),
|
||||
#[cfg(feature = "luau")]
|
||||
name_what: None,
|
||||
}
|
||||
@@ -101,12 +101,12 @@ impl<'lua> Debug<'lua> {
|
||||
);
|
||||
|
||||
DebugSource {
|
||||
source: ptr_to_str((*self.ar.get()).source),
|
||||
short_src: ptr_to_str((*self.ar.get()).short_src.as_ptr()),
|
||||
source: ptr_to_cstr_bytes((*self.ar.get()).source),
|
||||
short_src: ptr_to_cstr_bytes((*self.ar.get()).short_src.as_ptr()),
|
||||
line_defined: (*self.ar.get()).linedefined as i32,
|
||||
#[cfg(not(feature = "luau"))]
|
||||
last_line_defined: (*self.ar.get()).lastlinedefined as i32,
|
||||
what: ptr_to_str((*self.ar.get()).what),
|
||||
what: ptr_to_cstr_bytes((*self.ar.get()).what),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -349,11 +349,3 @@ impl BitOrAssign for HookTriggers {
|
||||
*self = *self | rhs;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn ptr_to_str<'a>(input: *const c_char) -> Option<&'a [u8]> {
|
||||
if input.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(CStr::from_ptr(input).to_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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.3")]
|
||||
#![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))))]
|
||||
@@ -108,7 +108,7 @@ pub use crate::{ffi::lua_CFunction, ffi::lua_State};
|
||||
|
||||
pub use crate::chunk::{AsChunk, Chunk, ChunkMode};
|
||||
pub use crate::error::{Error, ExternalError, ExternalResult, Result};
|
||||
pub use crate::function::Function;
|
||||
pub use crate::function::{Function, FunctionInfo};
|
||||
pub use crate::hook::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack};
|
||||
pub use crate::lua::{GCMode, Lua, LuaOptions};
|
||||
pub use crate::multi::Variadic;
|
||||
@@ -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;
|
||||
|
||||
+283
-233
File diff suppressed because it is too large
Load Diff
+24
-8
@@ -29,26 +29,42 @@ impl Lua {
|
||||
unsafe extern "C" fn lua_collectgarbage(state: *mut ffi::lua_State) -> c_int {
|
||||
let option = ffi::luaL_optstring(state, 1, cstr!("collect"));
|
||||
let option = CStr::from_ptr(option);
|
||||
let arg = ffi::luaL_optinteger(state, 2, 0);
|
||||
match option.to_str() {
|
||||
Ok("collect") => {
|
||||
ffi::lua_gc(state, ffi::LUA_GCCOLLECT, 0);
|
||||
0
|
||||
}
|
||||
Ok("stop") => {
|
||||
ffi::lua_gc(state, ffi::LUA_GCSTOP, 0);
|
||||
0
|
||||
}
|
||||
Ok("restart") => {
|
||||
ffi::lua_gc(state, ffi::LUA_GCRESTART, 0);
|
||||
0
|
||||
}
|
||||
Ok("count") => {
|
||||
let n = ffi::lua_gc(state, ffi::LUA_GCCOUNT, 0);
|
||||
ffi::lua_pushnumber(state, n as ffi::lua_Number);
|
||||
let kbytes = ffi::lua_gc(state, ffi::LUA_GCCOUNT, 0) as ffi::lua_Number;
|
||||
let kbytes_rem = ffi::lua_gc(state, ffi::LUA_GCCOUNTB, 0) as ffi::lua_Number;
|
||||
ffi::lua_pushnumber(state, kbytes + kbytes_rem / 1024.0);
|
||||
1
|
||||
}
|
||||
// TODO: More variants
|
||||
_ => ffi::luaL_error(
|
||||
state,
|
||||
cstr!("collectgarbage must be called with 'count' or 'collect'"),
|
||||
),
|
||||
Ok("step") => {
|
||||
let res = ffi::lua_gc(state, ffi::LUA_GCSTEP, arg);
|
||||
ffi::lua_pushboolean(state, res);
|
||||
1
|
||||
}
|
||||
Ok("isrunning") => {
|
||||
let res = ffi::lua_gc(state, ffi::LUA_GCISRUNNING, 0);
|
||||
ffi::lua_pushboolean(state, res);
|
||||
1
|
||||
}
|
||||
_ => ffi::luaL_error(state, cstr!("collectgarbage called with invalid option")),
|
||||
}
|
||||
}
|
||||
|
||||
fn lua_require(lua: &Lua, name: Option<std::string::String>) -> Result<Value> {
|
||||
let name = name.ok_or_else(|| Error::RuntimeError("name is nil".into()))?;
|
||||
let name = name.ok_or_else(|| Error::RuntimeError("invalid module name".into()))?;
|
||||
|
||||
// Find module in the cache
|
||||
let loaded = unsafe {
|
||||
|
||||
+8
-8
@@ -4,13 +4,13 @@
|
||||
pub use crate::{
|
||||
AnyUserData as LuaAnyUserData, Chunk as LuaChunk, Error as LuaError,
|
||||
ExternalError as LuaExternalError, ExternalResult as LuaExternalResult, FromLua, FromLuaMulti,
|
||||
Function as LuaFunction, GCMode as LuaGCMode, Integer as LuaInteger,
|
||||
LightUserData as LuaLightUserData, Lua, LuaOptions, MetaMethod as LuaMetaMethod,
|
||||
MultiValue as LuaMultiValue, Nil as LuaNil, Number as LuaNumber, RegistryKey as LuaRegistryKey,
|
||||
Result as LuaResult, StdLib as LuaStdLib, String as LuaString, Table as LuaTable,
|
||||
TableExt as LuaTableExt, TablePairs as LuaTablePairs, TableSequence as LuaTableSequence,
|
||||
Thread as LuaThread, ThreadStatus as LuaThreadStatus, ToLua, ToLuaMulti,
|
||||
UserData as LuaUserData, UserDataFields as LuaUserDataFields,
|
||||
Function as LuaFunction, FunctionInfo as LuaFunctionInfo, GCMode as LuaGCMode,
|
||||
Integer as LuaInteger, LightUserData as LuaLightUserData, Lua, LuaOptions,
|
||||
MetaMethod as LuaMetaMethod, MultiValue as LuaMultiValue, Nil as LuaNil, Number as LuaNumber,
|
||||
RegistryKey as LuaRegistryKey, Result as LuaResult, StdLib as LuaStdLib, String as LuaString,
|
||||
Table as LuaTable, TableExt as LuaTableExt, TablePairs as LuaTablePairs,
|
||||
TableSequence as LuaTableSequence, Thread as LuaThread, ThreadStatus as LuaThreadStatus, ToLua,
|
||||
ToLuaMulti, UserData as LuaUserData, UserDataFields as LuaUserDataFields,
|
||||
UserDataMetatable as LuaUserDataMetatable, UserDataMethods as LuaUserDataMethods,
|
||||
Value as LuaValue,
|
||||
};
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -158,6 +158,7 @@ pub trait LuaSerdeExt<'lua> {
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
fn from_value<T: Deserialize<'lua>>(&'lua self, value: Value<'lua>) -> Result<T>;
|
||||
|
||||
/// Deserializes a [`Value`] into any serde deserializable object with options.
|
||||
@@ -189,6 +190,7 @@ pub trait LuaSerdeExt<'lua> {
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
fn from_value_with<T: Deserialize<'lua>>(
|
||||
&'lua self,
|
||||
value: Value<'lua>,
|
||||
@@ -257,7 +259,7 @@ pub(crate) unsafe fn init_metatables(state: *mut ffi::lua_State) -> Result<()> {
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn push_array_metatable(state: *mut ffi::lua_State) {
|
||||
let array_metatable_key = &ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void;
|
||||
let array_metatable_key = &ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *const c_void;
|
||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, array_metatable_key);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,12 +46,14 @@ impl StdLib {
|
||||
///
|
||||
/// Requires `feature = "luajit"`
|
||||
#[cfg(any(feature = "luajit", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luajit")))]
|
||||
pub const JIT: StdLib = StdLib(1 << 9);
|
||||
|
||||
/// (**unsafe**) [`ffi`](http://luajit.org/ext_ffi.html) library
|
||||
///
|
||||
/// Requires `feature = "luajit"`
|
||||
#[cfg(any(feature = "luajit", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luajit")))]
|
||||
pub const FFI: StdLib = StdLib(1 << 30);
|
||||
/// (**unsafe**) [`debug`](https://www.lua.org/manual/5.4/manual.html#6.10) library
|
||||
pub const DEBUG: StdLib = StdLib(1 << 31);
|
||||
@@ -61,7 +63,10 @@ impl StdLib {
|
||||
/// (**unsafe**) All standard libraries
|
||||
pub const ALL: StdLib = StdLib(u32::MAX);
|
||||
/// The safe subset of the standard libraries
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub const ALL_SAFE: StdLib = StdLib((1 << 30) - 1);
|
||||
#[cfg(feature = "luau")]
|
||||
pub const ALL_SAFE: StdLib = StdLib(u32::MAX);
|
||||
|
||||
pub fn contains(self, lib: Self) -> bool {
|
||||
(self & lib).0 != 0
|
||||
|
||||
+16
-1
@@ -1,4 +1,5 @@
|
||||
use std::borrow::Cow;
|
||||
use std::borrow::{Borrow, Cow};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::string::String as StdString;
|
||||
use std::{slice, str};
|
||||
|
||||
@@ -119,6 +120,12 @@ impl<'lua> AsRef<[u8]> for String<'lua> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> Borrow<[u8]> for String<'lua> {
|
||||
fn borrow(&self) -> &[u8] {
|
||||
self.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
// Lua strings are basically &[u8] slices, so implement PartialEq for anything resembling that.
|
||||
//
|
||||
// This makes our `String` comparable with `Vec<u8>`, `[u8]`, `&str`, `String` and `mlua::String`
|
||||
@@ -136,6 +143,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> Eq for String<'lua> {}
|
||||
|
||||
impl<'lua> Hash for String<'lua> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.as_bytes().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
impl<'lua> Serialize for String<'lua> {
|
||||
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
|
||||
|
||||
+2
-2
@@ -351,7 +351,7 @@ impl<'lua> Table<'lua> {
|
||||
/// Sets `readonly` attribute on the table.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(feature = "luau")]
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn set_readonly(&self, enabled: bool) {
|
||||
let lua = self.0.lua;
|
||||
@@ -369,7 +369,7 @@ impl<'lua> Table<'lua> {
|
||||
/// Returns `readonly` attribute of the table.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(feature = "luau")]
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn is_readonly(&self) -> bool {
|
||||
let lua = self.0.lua;
|
||||
|
||||
+4
-9
@@ -24,7 +24,6 @@ use {
|
||||
std::{
|
||||
cell::RefCell,
|
||||
marker::PhantomData,
|
||||
os::raw::c_void,
|
||||
pin::Pin,
|
||||
task::{Context, Poll, Waker},
|
||||
},
|
||||
@@ -299,9 +298,8 @@ impl<'lua> Thread<'lua> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #[cfg(feature = "luau")]
|
||||
/// # fn main() -> mlua::Result<()> {
|
||||
/// use mlua::Lua;
|
||||
/// # use mlua::{Lua, Result};
|
||||
/// # fn main() -> Result<()> {
|
||||
/// let lua = Lua::new();
|
||||
/// let thread = lua.create_thread(lua.create_function(|lua2, ()| {
|
||||
/// lua2.load("var = 123").exec()?;
|
||||
@@ -315,13 +313,10 @@ impl<'lua> Thread<'lua> {
|
||||
/// assert_eq!(lua.globals().get::<_, Option<u32>>("var")?, None);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
///
|
||||
/// # #[cfg(not(feature = "luau"))]
|
||||
/// fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg(any(feature = "luau", docsrs))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
#[doc(hidden)]
|
||||
pub fn sandbox(&self) -> Result<()> {
|
||||
@@ -440,7 +435,7 @@ where
|
||||
fn is_poll_pending(val: &MultiValue) -> bool {
|
||||
match val.iter().enumerate().last() {
|
||||
Some((0, Value::LightUserData(ud))) => {
|
||||
ud.0 == &ASYNC_POLL_PENDING as *const u8 as *mut c_void
|
||||
std::ptr::eq(ud.0 as *const u8, &ASYNC_POLL_PENDING as *const u8)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
|
||||
+11
-14
@@ -1,3 +1,4 @@
|
||||
use std::cell::UnsafeCell;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::sync::{Arc, Mutex};
|
||||
@@ -13,7 +14,7 @@ use crate::error::Result;
|
||||
use crate::ffi;
|
||||
#[cfg(not(feature = "luau"))]
|
||||
use crate::hook::Debug;
|
||||
use crate::lua::Lua;
|
||||
use crate::lua::{ExtraData, Lua};
|
||||
use crate::util::{assert_stack, StackGuard};
|
||||
use crate::value::MultiValue;
|
||||
|
||||
@@ -29,26 +30,22 @@ pub struct LightUserData(pub *mut c_void);
|
||||
pub(crate) type Callback<'lua, 'a> =
|
||||
Box<dyn Fn(&'lua Lua, MultiValue<'lua>) -> Result<MultiValue<'lua>> + 'a>;
|
||||
|
||||
pub(crate) struct CallbackUpvalue<'lua> {
|
||||
pub(crate) lua: Lua,
|
||||
pub(crate) func: Callback<'lua, 'static>,
|
||||
pub(crate) struct Upvalue<T> {
|
||||
pub(crate) data: T,
|
||||
pub(crate) extra: Arc<UnsafeCell<ExtraData>>,
|
||||
}
|
||||
|
||||
pub(crate) type CallbackUpvalue = Upvalue<Callback<'static, 'static>>;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub(crate) type AsyncCallback<'lua, 'a> =
|
||||
Box<dyn Fn(&'lua Lua, MultiValue<'lua>) -> LocalBoxFuture<'lua, Result<MultiValue<'lua>>> + 'a>;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub(crate) struct AsyncCallbackUpvalue<'lua> {
|
||||
pub(crate) lua: Lua,
|
||||
pub(crate) func: AsyncCallback<'lua, 'static>,
|
||||
}
|
||||
pub(crate) type AsyncCallbackUpvalue = Upvalue<AsyncCallback<'static, 'static>>;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub(crate) struct AsyncPollUpvalue<'lua> {
|
||||
pub(crate) lua: Lua,
|
||||
pub(crate) fut: LocalBoxFuture<'lua, Result<MultiValue<'lua>>>,
|
||||
}
|
||||
pub(crate) type AsyncPollUpvalue = Upvalue<LocalBoxFuture<'static, Result<MultiValue<'static>>>>;
|
||||
|
||||
/// Type to set next Luau VM action after executing interrupt function.
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
@@ -65,10 +62,10 @@ pub(crate) type HookCallback = Arc<dyn Fn(&Lua, Debug) -> Result<()> + Send>;
|
||||
pub(crate) type HookCallback = Arc<dyn Fn(&Lua, Debug) -> Result<()>>;
|
||||
|
||||
#[cfg(all(feature = "luau", feature = "send"))]
|
||||
pub(crate) type InterruptCallback = Arc<dyn Fn(&Lua) -> Result<VmState> + Send>;
|
||||
pub(crate) type InterruptCallback = Arc<dyn Fn() -> Result<VmState> + Send>;
|
||||
|
||||
#[cfg(all(feature = "luau", not(feature = "send")))]
|
||||
pub(crate) type InterruptCallback = Arc<dyn Fn(&Lua) -> Result<VmState>>;
|
||||
pub(crate) type InterruptCallback = Arc<dyn Fn() -> Result<VmState>>;
|
||||
|
||||
#[cfg(all(feature = "send", feature = "lua54"))]
|
||||
pub(crate) type WarnCallback = Box<dyn Fn(&Lua, &CStr, bool) -> Result<()> + Send>;
|
||||
|
||||
+26
-12
@@ -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,
|
||||
@@ -914,16 +928,16 @@ impl<'lua> AnyUserData<'lua> {
|
||||
|
||||
// Multiple (extra) user values are emulated by storing them in a table
|
||||
protect_lua!(lua.state, 2, 0, |state| {
|
||||
if getuservalue_table(lua.state, -2) != ffi::LUA_TTABLE {
|
||||
if getuservalue_table(state, -2) != ffi::LUA_TTABLE {
|
||||
// Create a new table to use as uservalue
|
||||
ffi::lua_pop(lua.state, 1);
|
||||
ffi::lua_pop(state, 1);
|
||||
ffi::lua_newtable(state);
|
||||
ffi::lua_pushvalue(state, -1);
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
ffi::lua_setiuservalue(lua.state, -4, USER_VALUE_MAXSLOT as c_int);
|
||||
ffi::lua_setiuservalue(state, -4, USER_VALUE_MAXSLOT as c_int);
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
ffi::lua_setuservalue(lua.state, -4);
|
||||
ffi::lua_setuservalue(state, -4);
|
||||
}
|
||||
ffi::lua_pushvalue(state, -2);
|
||||
#[cfg(feature = "lua54")]
|
||||
@@ -967,8 +981,8 @@ impl<'lua> AnyUserData<'lua> {
|
||||
|
||||
// Multiple (extra) user values are emulated by storing them in a table
|
||||
protect_lua!(lua.state, 1, 1, |state| {
|
||||
if getuservalue_table(lua.state, -1) != ffi::LUA_TTABLE {
|
||||
ffi::lua_pushnil(lua.state);
|
||||
if getuservalue_table(state, -1) != ffi::LUA_TTABLE {
|
||||
ffi::lua_pushnil(state);
|
||||
return;
|
||||
}
|
||||
#[cfg(feature = "lua54")]
|
||||
@@ -1002,16 +1016,16 @@ impl<'lua> AnyUserData<'lua> {
|
||||
// Multiple (extra) user values are emulated by storing them in a table
|
||||
let name = name.as_ref();
|
||||
protect_lua!(lua.state, 2, 0, |state| {
|
||||
if getuservalue_table(lua.state, -2) != ffi::LUA_TTABLE {
|
||||
if getuservalue_table(state, -2) != ffi::LUA_TTABLE {
|
||||
// Create a new table to use as uservalue
|
||||
ffi::lua_pop(lua.state, 1);
|
||||
ffi::lua_pop(state, 1);
|
||||
ffi::lua_newtable(state);
|
||||
ffi::lua_pushvalue(state, -1);
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
ffi::lua_setiuservalue(lua.state, -4, USER_VALUE_MAXSLOT as c_int);
|
||||
ffi::lua_setiuservalue(state, -4, USER_VALUE_MAXSLOT as c_int);
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
ffi::lua_setuservalue(lua.state, -4);
|
||||
ffi::lua_setuservalue(state, -4);
|
||||
}
|
||||
ffi::lua_pushlstring(state, name.as_ptr() as *const c_char, name.len());
|
||||
ffi::lua_pushvalue(state, -3);
|
||||
@@ -1040,8 +1054,8 @@ impl<'lua> AnyUserData<'lua> {
|
||||
// Multiple (extra) user values are emulated by storing them in a table
|
||||
let name = name.as_ref();
|
||||
protect_lua!(lua.state, 1, 1, |state| {
|
||||
if getuservalue_table(lua.state, -1) != ffi::LUA_TTABLE {
|
||||
ffi::lua_pushnil(lua.state);
|
||||
if getuservalue_table(state, -1) != ffi::LUA_TTABLE {
|
||||
ffi::lua_pushnil(state);
|
||||
return;
|
||||
}
|
||||
ffi::lua_pushlstring(state, name.as_ptr() as *const c_char, name.len());
|
||||
|
||||
@@ -246,11 +246,23 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
|
||||
let ud = ud.try_lock().map_err(|_| Error::UserDataBorrowError)?;
|
||||
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
#[cfg(feature = "parking_lot")]
|
||||
Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
|
||||
let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(lua.state)?;
|
||||
let ud = ud.try_lock().ok_or(Error::UserDataBorrowError)?;
|
||||
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
|
||||
let ud = get_userdata_ref::<Arc<RwLock<T>>>(lua.state)?;
|
||||
let ud = ud.try_read().map_err(|_| Error::UserDataBorrowError)?;
|
||||
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
#[cfg(feature = "parking_lot")]
|
||||
Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
|
||||
let ud = get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(lua.state)?;
|
||||
let ud = ud.try_read().ok_or(Error::UserDataBorrowError)?;
|
||||
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
_ => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
}
|
||||
@@ -301,12 +313,24 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
|
||||
ud.try_lock().map_err(|_| Error::UserDataBorrowMutError)?;
|
||||
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
#[cfg(feature = "parking_lot")]
|
||||
Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
|
||||
let ud = get_userdata_mut::<Arc<parking_lot::Mutex<T>>>(lua.state)?;
|
||||
let mut ud = ud.try_lock().ok_or(Error::UserDataBorrowMutError)?;
|
||||
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
|
||||
let ud = get_userdata_mut::<Arc<RwLock<T>>>(lua.state)?;
|
||||
let mut ud =
|
||||
ud.try_write().map_err(|_| Error::UserDataBorrowMutError)?;
|
||||
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
#[cfg(feature = "parking_lot")]
|
||||
Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
|
||||
let ud = get_userdata_mut::<Arc<parking_lot::RwLock<T>>>(lua.state)?;
|
||||
let mut ud = ud.try_write().ok_or(Error::UserDataBorrowMutError)?;
|
||||
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
_ => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
}
|
||||
@@ -354,11 +378,24 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
|
||||
let ud = ud.try_lock().map_err(|_| Error::UserDataBorrowError)?;
|
||||
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
|
||||
}
|
||||
#[cfg(feature = "parking_lot")]
|
||||
Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
|
||||
let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(lua.state)?;
|
||||
let ud = ud.try_lock().ok_or(Error::UserDataBorrowError)?;
|
||||
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
|
||||
}
|
||||
Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
|
||||
let ud = get_userdata_ref::<Arc<RwLock<T>>>(lua.state)?;
|
||||
let ud = ud.try_read().map_err(|_| Error::UserDataBorrowError)?;
|
||||
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
|
||||
}
|
||||
#[cfg(feature = "parking_lot")]
|
||||
Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
|
||||
let ud =
|
||||
get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(lua.state)?;
|
||||
let ud = ud.try_read().ok_or(Error::UserDataBorrowError)?;
|
||||
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
|
||||
}
|
||||
_ => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
}
|
||||
@@ -581,3 +618,7 @@ macro_rules! lua_userdata_impl {
|
||||
lua_userdata_impl!(Rc<RefCell<T>>);
|
||||
lua_userdata_impl!(Arc<Mutex<T>>);
|
||||
lua_userdata_impl!(Arc<RwLock<T>>);
|
||||
#[cfg(feature = "parking_lot")]
|
||||
lua_userdata_impl!(Arc<parking_lot::Mutex<T>>);
|
||||
#[cfg(feature = "parking_lot")]
|
||||
lua_userdata_impl!(Arc<parking_lot::RwLock<T>>);
|
||||
|
||||
@@ -992,6 +992,13 @@ pub(crate) unsafe fn get_destructed_userdata_metatable(state: *mut ffi::lua_Stat
|
||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, key);
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn ptr_to_cstr_bytes<'a>(input: *const c_char) -> Option<&'a [u8]> {
|
||||
if input.is_null() {
|
||||
return None;
|
||||
}
|
||||
Some(CStr::from_ptr(input).to_bytes())
|
||||
}
|
||||
|
||||
static DESTRUCTED_USERDATA_METATABLE: u8 = 0;
|
||||
static ERROR_PRINT_BUFFER_KEY: u8 = 0;
|
||||
static USERDATA_METATABLE_INDEX: u8 = 0;
|
||||
|
||||
+26
-1
@@ -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
@@ -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)?;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
use std::fs;
|
||||
use std::io;
|
||||
|
||||
use mlua::{Error, Lua, Result};
|
||||
|
||||
#[test]
|
||||
fn test_chunk_path() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
fs::write(
|
||||
temp_dir.path().join("module.lua"),
|
||||
r#"
|
||||
return 321
|
||||
"#,
|
||||
)?;
|
||||
let i: i32 = lua.load(&temp_dir.path().join("module.lua")).eval()?;
|
||||
assert_eq!(i, 321);
|
||||
|
||||
match lua.load(&temp_dir.path().join("module2.lua")).exec() {
|
||||
Err(Error::ExternalError(err))
|
||||
if err.downcast_ref::<io::Error>().unwrap().kind() == io::ErrorKind::NotFound => {}
|
||||
res => panic!("expected io::Error, got {:?}", res),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "macros")]
|
||||
fn test_chunk_macro() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let name = "Rustacean";
|
||||
let table = vec![1];
|
||||
|
||||
let data = lua.create_table()?;
|
||||
data.raw_set("num", 1)?;
|
||||
|
||||
lua.globals().set("g", 123)?;
|
||||
|
||||
lua.load(mlua::chunk! {
|
||||
assert($name == "Rustacean")
|
||||
assert($table[1] == 1)
|
||||
assert($data.num == 1)
|
||||
assert(g == 123)
|
||||
s = 321
|
||||
})
|
||||
.exec()?;
|
||||
|
||||
assert_eq!(lua.globals().get::<_, i32>("s")?, 321);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,36 +1,41 @@
|
||||
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
|
||||
--> $DIR/async_nonstatic_userdata.rs:11:72
|
||||
|
|
||||
11 | methods.add_async_method("print", |_, data, ()| async move {
|
||||
| ________________________________________________________________________^
|
||||
12 | | println!("{}", data.0);
|
||||
13 | | Ok(())
|
||||
14 | | });
|
||||
| |_____________^
|
||||
|
|
||||
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 9:10...
|
||||
--> $DIR/async_nonstatic_userdata.rs:9:10
|
||||
|
|
||||
9 | impl<'a> UserData for MyUserData<'a> {
|
||||
| ^^
|
||||
--> tests/compile/async_nonstatic_userdata.rs:11:72
|
||||
|
|
||||
11 | methods.add_async_method("print", |_, data, ()| async move {
|
||||
| ________________________________________________________________________^
|
||||
12 | | println!("{}", data.0);
|
||||
13 | | Ok(())
|
||||
14 | | });
|
||||
| |_____________^
|
||||
|
|
||||
note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
|
||||
--> tests/compile/async_nonstatic_userdata.rs:9:10
|
||||
|
|
||||
9 | impl<'a> UserData for MyUserData<'a> {
|
||||
| ^^
|
||||
note: ...so that the types are compatible
|
||||
--> $DIR/async_nonstatic_userdata.rs:11:72
|
||||
|
|
||||
11 | methods.add_async_method("print", |_, data, ()| async move {
|
||||
| ________________________________________________________________________^
|
||||
12 | | println!("{}", data.0);
|
||||
13 | | Ok(())
|
||||
14 | | });
|
||||
| |_____________^
|
||||
= note: expected `(MyUserData<'_>,)`
|
||||
found `(MyUserData<'a>,)`
|
||||
note: but, the lifetime must be valid for the lifetime `'lua` as defined on the method body at 10:24...
|
||||
--> $DIR/async_nonstatic_userdata.rs:10:24
|
||||
|
|
||||
10 | fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
| ^^^^
|
||||
note: ...so that the type `impl Future` will meet its required lifetime bounds
|
||||
--> $DIR/async_nonstatic_userdata.rs:11:21
|
||||
|
|
||||
11 | methods.add_async_method("print", |_, data, ()| async move {
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
--> tests/compile/async_nonstatic_userdata.rs:11:72
|
||||
|
|
||||
11 | methods.add_async_method("print", |_, data, ()| async move {
|
||||
| ________________________________________________________________________^
|
||||
12 | | println!("{}", data.0);
|
||||
13 | | Ok(())
|
||||
14 | | });
|
||||
| |_____________^
|
||||
= note: expected `(MyUserData<'_>,)`
|
||||
found `(MyUserData<'a>,)`
|
||||
note: but, the lifetime must be valid for the lifetime `'lua` as defined here...
|
||||
--> tests/compile/async_nonstatic_userdata.rs:10:24
|
||||
|
|
||||
10 | fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
| ^^^^
|
||||
note: ...so that the type `impl Future<Output = [async output]>` will meet its required lifetime bounds...
|
||||
--> tests/compile/async_nonstatic_userdata.rs:11:21
|
||||
|
|
||||
11 | methods.add_async_method("print", |_, data, ()| async move {
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
note: ...that is required by this bound
|
||||
--> src/userdata.rs
|
||||
|
|
||||
| MR: 'lua + Future<Output = Result<R>>;
|
||||
| ^^^^
|
||||
|
||||
@@ -1,30 +1,13 @@
|
||||
error[E0277]: the type `UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
error[E0277]: the type `UnsafeCell<mlua::lua::LuaInner>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/lua_norefunwindsafe.rs:7:5
|
||||
|
|
||||
7 | catch_unwind(|| lua.create_table().unwrap());
|
||||
| ^^^^^^^^^^^^ `UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| ^^^^^^^^^^^^ `UnsafeCell<mlua::lua::LuaInner>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
|
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<()>`
|
||||
= note: required because it appears within the type `PhantomData<UnsafeCell<()>>`
|
||||
= note: required because it appears within the type `Lua`
|
||||
= note: required because of the requirements on the impl of `UnwindSafe` for `&Lua`
|
||||
= note: required because it appears within the type `[closure@$DIR/tests/compile/lua_norefunwindsafe.rs:7:18: 7:48]`
|
||||
note: required by a bound in `catch_unwind`
|
||||
--> $RUST/std/src/panic.rs
|
||||
|
|
||||
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
| ^^^^^^^^^^ required by this bound in `catch_unwind`
|
||||
|
||||
error[E0277]: the type `UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/lua_norefunwindsafe.rs:7:5
|
||||
|
|
||||
7 | catch_unwind(|| lua.create_table().unwrap());
|
||||
| ^^^^^^^^^^^^ `UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
|
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::lua::ExtraData>`
|
||||
= note: required because it appears within the type `alloc::sync::ArcInner<UnsafeCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `PhantomData<alloc::sync::ArcInner<UnsafeCell<mlua::lua::ExtraData>>>`
|
||||
= note: required because it appears within the type `Arc<UnsafeCell<mlua::lua::ExtraData>>`
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::lua::LuaInner>`
|
||||
= note: required because it appears within the type `alloc::sync::ArcInner<UnsafeCell<mlua::lua::LuaInner>>`
|
||||
= note: required because it appears within the type `PhantomData<alloc::sync::ArcInner<UnsafeCell<mlua::lua::LuaInner>>>`
|
||||
= note: required because it appears within the type `Arc<UnsafeCell<mlua::lua::LuaInner>>`
|
||||
= note: required because it appears within the type `Lua`
|
||||
= note: required because of the requirements on the impl of `UnwindSafe` for `&Lua`
|
||||
= note: required because it appears within the type `[closure@$DIR/tests/compile/lua_norefunwindsafe.rs:7:18: 7:48]`
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
error[E0277]: `Rc<Cell<i32>>` cannot be sent between threads safely
|
||||
--> $DIR/non_send.rs:11:9
|
||||
|
|
||||
11 | lua.create_function(move |_, ()| {
|
||||
| _________^^^^^^^^^^^^^^^_-
|
||||
| | |
|
||||
| | `Rc<Cell<i32>>` cannot be sent between threads safely
|
||||
12 | | Ok(data.get())
|
||||
13 | | })?
|
||||
| |_____- within this `[closure@$DIR/tests/compile/non_send.rs:11:25: 13:6]`
|
||||
|
|
||||
= help: within `[closure@$DIR/tests/compile/non_send.rs:11:25: 13:6]`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
|
||||
= note: required because it appears within the type `[closure@$DIR/tests/compile/non_send.rs:11:25: 13:6]`
|
||||
= note: required because of the requirements on the impl of `mlua::types::MaybeSend` for `[closure@$DIR/tests/compile/non_send.rs:11:25: 13:6]`
|
||||
--> tests/compile/non_send.rs:11:9
|
||||
|
|
||||
11 | lua.create_function(move |_, ()| {
|
||||
| _________^^^^^^^^^^^^^^^_-
|
||||
| | |
|
||||
| | `Rc<Cell<i32>>` cannot be sent between threads safely
|
||||
12 | | Ok(data.get())
|
||||
13 | | })?
|
||||
| |_____- within this `[closure@$DIR/tests/compile/non_send.rs:11:25: 13:6]`
|
||||
|
|
||||
= help: within `[closure@$DIR/tests/compile/non_send.rs:11:25: 13:6]`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
|
||||
= note: required because it appears within the type `[closure@$DIR/tests/compile/non_send.rs:11:25: 13:6]`
|
||||
= note: required because of the requirements on the impl of `mlua::types::MaybeSend` for `[closure@$DIR/tests/compile/non_send.rs:11:25: 13:6]`
|
||||
note: required by a bound in `Lua::create_function`
|
||||
--> src/lua.rs
|
||||
|
|
||||
| F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
|
||||
| ^^^^^^^^^ required by this bound in `Lua::create_function`
|
||||
|
||||
@@ -1,32 +1,13 @@
|
||||
error[E0277]: the type `UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
error[E0277]: the type `UnsafeCell<mlua::lua::LuaInner>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:5
|
||||
|
|
||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
||||
| ^^^^^^^^^^^^ `UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| ^^^^^^^^^^^^ `UnsafeCell<mlua::lua::LuaInner>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
|
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<()>`
|
||||
= note: required because it appears within the type `PhantomData<UnsafeCell<()>>`
|
||||
= note: required because it appears within the type `Lua`
|
||||
= note: required because of the requirements on the impl of `UnwindSafe` for `&Lua`
|
||||
= note: required because it appears within the type `mlua::types::LuaRef<'_>`
|
||||
= note: required because it appears within the type `LuaTable<'_>`
|
||||
= note: required because it appears within the type `[closure@$DIR/tests/compile/ref_nounwindsafe.rs:8:18: 8:54]`
|
||||
note: required by a bound in `catch_unwind`
|
||||
--> $RUST/std/src/panic.rs
|
||||
|
|
||||
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
| ^^^^^^^^^^ required by this bound in `catch_unwind`
|
||||
|
||||
error[E0277]: the type `UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:5
|
||||
|
|
||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
||||
| ^^^^^^^^^^^^ `UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
|
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::lua::ExtraData>`
|
||||
= note: required because it appears within the type `alloc::sync::ArcInner<UnsafeCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `PhantomData<alloc::sync::ArcInner<UnsafeCell<mlua::lua::ExtraData>>>`
|
||||
= note: required because it appears within the type `Arc<UnsafeCell<mlua::lua::ExtraData>>`
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::lua::LuaInner>`
|
||||
= note: required because it appears within the type `alloc::sync::ArcInner<UnsafeCell<mlua::lua::LuaInner>>`
|
||||
= note: required because it appears within the type `PhantomData<alloc::sync::ArcInner<UnsafeCell<mlua::lua::LuaInner>>>`
|
||||
= note: required because it appears within the type `Arc<UnsafeCell<mlua::lua::LuaInner>>`
|
||||
= note: required because it appears within the type `Lua`
|
||||
= note: required because of the requirements on the impl of `UnwindSafe` for `&Lua`
|
||||
= note: required because it appears within the type `mlua::types::LuaRef<'_>`
|
||||
|
||||
@@ -19,7 +19,7 @@ error[E0373]: closure may outlive the current function, but it borrows `inner`,
|
||||
--> tests/compile/scope_callback_inner.rs:8:34
|
||||
|
|
||||
5 | lua.scope(|scope| {
|
||||
| ----- has type `&Scope<'_, '2>`
|
||||
| ----- has type `&mlua::Scope<'_, '2>`
|
||||
...
|
||||
8 | .create_function_mut(|_, t: Table| {
|
||||
| ^^^^^^^^^^^^^ may outlive borrowed value `inner`
|
||||
|
||||
@@ -2,7 +2,7 @@ error[E0373]: closure may outlive the current function, but it borrows `test`, w
|
||||
--> tests/compile/scope_invariance.rs:14:38
|
||||
|
|
||||
9 | lua.scope(|scope| {
|
||||
| ----- has type `&Scope<'_, '1>`
|
||||
| ----- has type `&mlua::Scope<'_, '1>`
|
||||
...
|
||||
14 | .create_function_mut(|_, ()| {
|
||||
| ^^^^^^^ may outlive borrowed value `test`
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
error[E0597]: `ibad` does not live long enough
|
||||
--> $DIR/scope_userdata_borrow.rs:15:56
|
||||
--> tests/compile/scope_userdata_borrow.rs:15:56
|
||||
|
|
||||
11 | lua.scope(|scope| {
|
||||
| ----- has type `&Scope<'_, '1>`
|
||||
| ----- has type `&mlua::Scope<'_, '1>`
|
||||
...
|
||||
15 | scope.create_nonstatic_userdata(MyUserData(&ibad)).unwrap();
|
||||
| -------------------------------------------^^^^^--
|
||||
|
||||
@@ -1,35 +1,33 @@
|
||||
error[E0597]: `lua` does not live long enough
|
||||
--> $DIR/static_callback_args.rs:12:5
|
||||
--> tests/compile/static_callback_args.rs:12:5
|
||||
|
|
||||
12 | lua.create_function(|_, table: Table| {
|
||||
| -^^
|
||||
| |
|
||||
| _____borrowed value does not live long enough
|
||||
| |
|
||||
12 | / lua.create_function(|_, table: Table| {
|
||||
13 | | BAD_TIME.with(|bt| {
|
||||
14 | | *bt.borrow_mut() = Some(table);
|
||||
15 | | });
|
||||
16 | | Ok(())
|
||||
17 | | })?
|
||||
| |______- argument requires that `lua` is borrowed for `'static`
|
||||
| | ^
|
||||
| | |
|
||||
| |______borrowed value does not live long enough
|
||||
| argument requires that `lua` is borrowed for `'static`
|
||||
...
|
||||
32 | }
|
||||
| - `lua` dropped here while still borrowed
|
||||
|
||||
error[E0505]: cannot move out of `lua` because it is borrowed
|
||||
--> $DIR/static_callback_args.rs:22:10
|
||||
--> tests/compile/static_callback_args.rs:22:10
|
||||
|
|
||||
12 | lua.create_function(|_, table: Table| {
|
||||
| ---
|
||||
| |
|
||||
| _____borrow of `lua` occurs here
|
||||
| |
|
||||
12 | / lua.create_function(|_, table: Table| {
|
||||
13 | | BAD_TIME.with(|bt| {
|
||||
14 | | *bt.borrow_mut() = Some(table);
|
||||
15 | | });
|
||||
16 | | Ok(())
|
||||
17 | | })?
|
||||
| |______- argument requires that `lua` is borrowed for `'static`
|
||||
| | -
|
||||
| | |
|
||||
| |______borrow of `lua` occurs here
|
||||
| argument requires that `lua` is borrowed for `'static`
|
||||
...
|
||||
22 | drop(lua);
|
||||
| ^^^ move out of `lua` occurs here
|
||||
|
||||
@@ -107,3 +107,57 @@ fn test_dump() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_function_info() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let globals = lua.globals();
|
||||
lua.load(
|
||||
r#"
|
||||
function function1()
|
||||
return function() end
|
||||
end
|
||||
"#,
|
||||
)
|
||||
.set_name("source1")?
|
||||
.exec()?;
|
||||
|
||||
let function1 = globals.get::<_, Function>("function1")?;
|
||||
let function2 = function1.call::<_, Function>(())?;
|
||||
let function3 = lua.create_function(|_, ()| Ok(()))?;
|
||||
|
||||
let function1_info = function1.info();
|
||||
#[cfg(feature = "luau")]
|
||||
assert_eq!(function1_info.name, Some(b"function1".to_vec()));
|
||||
assert_eq!(function1_info.source, Some(b"source1".to_vec()));
|
||||
assert_eq!(function1_info.line_defined, 2);
|
||||
#[cfg(not(feature = "luau"))]
|
||||
assert_eq!(function1_info.last_line_defined, 4);
|
||||
assert_eq!(function1_info.what, Some(b"Lua".to_vec()));
|
||||
|
||||
let function2_info = function2.info();
|
||||
assert_eq!(function2_info.name, None);
|
||||
assert_eq!(function2_info.source, Some(b"source1".to_vec()));
|
||||
assert_eq!(function2_info.line_defined, 3);
|
||||
#[cfg(not(feature = "luau"))]
|
||||
assert_eq!(function2_info.last_line_defined, 3);
|
||||
assert_eq!(function2_info.what, Some(b"Lua".to_vec()));
|
||||
|
||||
let function3_info = function3.info();
|
||||
assert_eq!(function3_info.name, None);
|
||||
assert_eq!(function3_info.source, Some(b"=[C]".to_vec()));
|
||||
assert_eq!(function3_info.line_defined, -1);
|
||||
#[cfg(not(feature = "luau"))]
|
||||
assert_eq!(function3_info.last_line_defined, -1);
|
||||
assert_eq!(function3_info.what, Some(b"C".to_vec()));
|
||||
|
||||
let print_info = globals.get::<_, Function>("print")?.info();
|
||||
#[cfg(feature = "luau")]
|
||||
assert_eq!(print_info.name, Some(b"print".to_vec()));
|
||||
assert_eq!(print_info.source, Some(b"=[C]".to_vec()));
|
||||
assert_eq!(print_info.what, Some(b"C".to_vec()));
|
||||
assert_eq!(print_info.line_defined, -1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+78
-5
@@ -5,7 +5,7 @@ use std::fs;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use mlua::{Error, Lua, Result, Table, ThreadStatus, Value, VmState};
|
||||
use mlua::{Compiler, CoverageInfo, Error, Lua, Result, Table, ThreadStatus, Value, VmState};
|
||||
|
||||
#[test]
|
||||
fn test_require() -> Result<()> {
|
||||
@@ -59,7 +59,7 @@ fn test_vectors() -> Result<()> {
|
||||
assert(v.z == 3)
|
||||
"#,
|
||||
)
|
||||
.set_vector_ctor(Some("vector".to_string()))
|
||||
.set_compiler(Compiler::new().set_vector_ctor(Some("vector".to_string())))
|
||||
.exec()?;
|
||||
|
||||
Ok(())
|
||||
@@ -150,7 +150,7 @@ fn test_interrupts() -> Result<()> {
|
||||
let interrupts_count = Arc::new(AtomicU64::new(0));
|
||||
let interrupts_count2 = interrupts_count.clone();
|
||||
|
||||
lua.set_interrupt(move |_lua| {
|
||||
lua.set_interrupt(move || {
|
||||
interrupts_count2.fetch_add(1, Ordering::Relaxed);
|
||||
Ok(VmState::Continue)
|
||||
});
|
||||
@@ -172,7 +172,7 @@ fn test_interrupts() -> Result<()> {
|
||||
//
|
||||
let yield_count = Arc::new(AtomicU64::new(0));
|
||||
let yield_count2 = yield_count.clone();
|
||||
lua.set_interrupt(move |_lua| {
|
||||
lua.set_interrupt(move || {
|
||||
if yield_count2.fetch_add(1, Ordering::Relaxed) == 1 {
|
||||
return Ok(VmState::Yield);
|
||||
}
|
||||
@@ -199,7 +199,7 @@ fn test_interrupts() -> Result<()> {
|
||||
//
|
||||
// Test errors in interrupts
|
||||
//
|
||||
lua.set_interrupt(|_| Err(Error::RuntimeError("error from interrupt".into())));
|
||||
lua.set_interrupt(|| Err(Error::RuntimeError("error from interrupt".into())));
|
||||
match f.call::<_, ()>(()) {
|
||||
Err(Error::CallbackError { cause, .. }) => match *cause {
|
||||
Error::RuntimeError(ref m) if m == "error from interrupt" => {}
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#![cfg(feature = "macros")]
|
||||
|
||||
use mlua::{chunk, Lua, Result};
|
||||
|
||||
#[test]
|
||||
fn test_chunk_macro() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let name = "Rustacean";
|
||||
let table = vec![1];
|
||||
|
||||
let data = lua.create_table()?;
|
||||
data.raw_set("num", 1)?;
|
||||
|
||||
lua.globals().set("g", 123)?;
|
||||
|
||||
lua.load(chunk! {
|
||||
assert($name == "Rustacean")
|
||||
assert($table[1] == 1)
|
||||
assert($data.num == 1)
|
||||
assert(g == 123)
|
||||
s = 321
|
||||
})
|
||||
.exec()?;
|
||||
|
||||
assert_eq!(lua.globals().get::<_, i32>("s")?, 321);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
+7
-5
@@ -1,6 +1,6 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use mlua::{Lua, Result, UserData};
|
||||
use mlua::{GCMode, Lua, Result, UserData};
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
use mlua::Error;
|
||||
@@ -39,7 +39,10 @@ fn test_gc_control() -> Result<()> {
|
||||
let globals = lua.globals();
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
assert_eq!(lua.gc_gen(0, 0), mlua::GCMode::Incremental);
|
||||
{
|
||||
assert_eq!(lua.gc_gen(0, 0), GCMode::Incremental);
|
||||
assert_eq!(lua.gc_inc(0, 0, 0), GCMode::Generational);
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
@@ -55,6 +58,8 @@ fn test_gc_control() -> Result<()> {
|
||||
assert!(lua.gc_is_running());
|
||||
}
|
||||
|
||||
assert_eq!(lua.gc_inc(200, 100, 13), GCMode::Incremental);
|
||||
|
||||
struct MyUserdata(Arc<()>);
|
||||
impl UserData for MyUserdata {}
|
||||
|
||||
@@ -67,9 +72,6 @@ fn test_gc_control() -> Result<()> {
|
||||
lua.gc_collect()?;
|
||||
assert_eq!(Arc::strong_count(&rc), 1);
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
assert_eq!(lua.gc_inc(0, 0, 0), mlua::GCMode::Generational);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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"] }
|
||||
|
||||
@@ -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"]
|
||||
@@ -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 = "../../.." }
|
||||
@@ -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())
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
use std::cell::RefCell;
|
||||
|
||||
use mlua::{Lua, Result, Table};
|
||||
|
||||
#[test]
|
||||
fn test_static_lua() -> Result<()> {
|
||||
let lua = Lua::new().into_static();
|
||||
|
||||
thread_local! {
|
||||
static TABLE: RefCell<Option<Table<'static>>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
let f = lua.create_function(|_, table: Table| {
|
||||
TABLE.with(|t| {
|
||||
table.raw_insert(1, "hello")?;
|
||||
*t.borrow_mut() = Some(table);
|
||||
Ok(())
|
||||
})
|
||||
})?;
|
||||
|
||||
f.call(lua.create_table()?)?;
|
||||
drop(f);
|
||||
lua.gc_collect()?;
|
||||
|
||||
TABLE.with(|t| {
|
||||
assert!(t.borrow().as_ref().unwrap().len().unwrap() == 1);
|
||||
*t.borrow_mut() = None;
|
||||
});
|
||||
|
||||
// Consume the Lua instance
|
||||
unsafe { Lua::from_static(lua) };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_static_lua_coroutine() -> Result<()> {
|
||||
let lua = Lua::new().into_static();
|
||||
|
||||
thread_local! {
|
||||
static TABLE: RefCell<Option<Table<'static>>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
let f = lua.create_function(|_, table: Table| {
|
||||
TABLE.with(|t| {
|
||||
table.raw_insert(1, "hello")?;
|
||||
*t.borrow_mut() = Some(table);
|
||||
Ok(())
|
||||
})
|
||||
})?;
|
||||
|
||||
let co = lua.create_thread(f)?;
|
||||
co.resume::<_, ()>(lua.create_table()?)?;
|
||||
drop(co);
|
||||
lua.gc_collect()?;
|
||||
|
||||
TABLE.with(|t| {
|
||||
assert_eq!(
|
||||
t.borrow().as_ref().unwrap().get::<_, String>(1i32).unwrap(),
|
||||
"hello".to_string()
|
||||
);
|
||||
*t.borrow_mut() = None;
|
||||
});
|
||||
|
||||
// Consume the Lua instance
|
||||
unsafe { Lua::from_static(lua) };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[tokio::test]
|
||||
async fn test_static_async() -> Result<()> {
|
||||
let lua = Lua::new().into_static();
|
||||
|
||||
let timer =
|
||||
lua.create_async_function(|_, (i, n, f): (u64, u64, mlua::Function)| async move {
|
||||
tokio::task::spawn_local(async move {
|
||||
let dur = std::time::Duration::from_millis(i);
|
||||
for _ in 0..n {
|
||||
tokio::task::spawn_local(f.call_async::<(), ()>(()));
|
||||
tokio::time::sleep(dur).await;
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
})?;
|
||||
lua.globals().set("timer", timer)?;
|
||||
|
||||
{
|
||||
let local_set = tokio::task::LocalSet::new();
|
||||
local_set
|
||||
.run_until(
|
||||
lua.load(
|
||||
r#"
|
||||
local cnt = 0
|
||||
timer(1, 100, function()
|
||||
cnt = cnt + 1
|
||||
if cnt % 10 == 0 then
|
||||
collectgarbage()
|
||||
end
|
||||
end)
|
||||
"#,
|
||||
)
|
||||
.exec_async(),
|
||||
)
|
||||
.await?;
|
||||
local_set.await;
|
||||
}
|
||||
|
||||
// Consume the Lua instance
|
||||
unsafe { Lua::from_static(lua) };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use mlua::{Lua, Result, String};
|
||||
|
||||
@@ -67,3 +68,18 @@ fn test_raw_string() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_hash() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let set: HashSet<String> = lua.load(r#"{"hello", "world", "abc", 321}"#).eval()?;
|
||||
assert_eq!(set.len(), 4);
|
||||
assert!(set.contains(b"hello".as_ref()));
|
||||
assert!(set.contains(b"world".as_ref()));
|
||||
assert!(set.contains(b"abc".as_ref()));
|
||||
assert!(set.contains(b"321".as_ref()));
|
||||
assert!(!set.contains(b"Hello".as_ref()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+12
-1
@@ -1,4 +1,9 @@
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::sync::Arc;
|
||||
#[cfg(not(feature = "parking_lot"))]
|
||||
use std::sync::{Mutex, RwLock};
|
||||
|
||||
#[cfg(feature = "parking_lot")]
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
|
||||
#[cfg(not(feature = "send"))]
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
@@ -623,7 +628,10 @@ fn test_userdata_wrapped() -> Result<()> {
|
||||
"#,
|
||||
)
|
||||
.exec()?;
|
||||
#[cfg(not(feature = "parking_lot"))]
|
||||
assert_eq!(ud2.lock().unwrap().0, 3);
|
||||
#[cfg(feature = "parking_lot")]
|
||||
assert_eq!(ud2.lock().0, 3);
|
||||
|
||||
let ud3 = Arc::new(RwLock::new(MyUserData(3)));
|
||||
globals.set("arc_rwlock_ud", ud3.clone())?;
|
||||
@@ -634,7 +642,10 @@ fn test_userdata_wrapped() -> Result<()> {
|
||||
"#,
|
||||
)
|
||||
.exec()?;
|
||||
#[cfg(not(feature = "parking_lot"))]
|
||||
assert_eq!(ud3.read().unwrap().0, 4);
|
||||
#[cfg(feature = "parking_lot")]
|
||||
assert_eq!(ud3.read().0, 4);
|
||||
|
||||
// Test drop
|
||||
globals.set("arc_mutex_ud", Nil)?;
|
||||
|
||||
+12
-4
@@ -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(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user