mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d8b9c46d28 | |||
| 9bd6d6fa92 | |||
| ea6e6e00b2 | |||
| 03ed7f6f99 | |||
| d5bc9c8c24 | |||
| 5cd0b645c4 | |||
| bf36eb72f8 | |||
| 1f7f8f62ab | |||
| e4dc773aa3 | |||
| 07fc4642ae | |||
| 27121c779d | |||
| 5eec0ef56b | |||
| 831161bfda |
@@ -1,49 +0,0 @@
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/rust:latest
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Version information
|
||||
command: rustc --version; cargo --version; rustup --version
|
||||
- run:
|
||||
name: Calculate dependencies
|
||||
command: cargo generate-lockfile
|
||||
- restore_cache:
|
||||
keys:
|
||||
- cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
- run:
|
||||
name: Check Formatting
|
||||
command: |
|
||||
rustup component add rustfmt
|
||||
rustfmt --version
|
||||
cargo fmt --all -- --check --color=auto
|
||||
- run:
|
||||
name: Install Lua
|
||||
command: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y --no-install-recommends install liblua5.3-dev liblua5.2-dev liblua5.1-0-dev libluajit-5.1-dev
|
||||
- run:
|
||||
name: Build all targets
|
||||
command: cargo build --all --all-targets
|
||||
- run:
|
||||
name: Run all tests / Lua 5.3
|
||||
command: cargo test --all --no-default-features --features lua53
|
||||
- run:
|
||||
name: Run all tests / Lua 5.2
|
||||
command: cargo test --all --no-default-features --features lua52
|
||||
- run:
|
||||
name: Run all tests / Lua 5.1
|
||||
command: cargo test --all --no-default-features --features lua51
|
||||
- run:
|
||||
name: Run all tests / LuaJIT
|
||||
command: cargo test --all --no-default-features --features luajit
|
||||
- save_cache:
|
||||
paths:
|
||||
- /usr/local/cargo/registry
|
||||
- target/debug/.fingerprint
|
||||
- target/debug/build
|
||||
- target/debug/deps
|
||||
key: cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
@@ -0,0 +1,147 @@
|
||||
name: CI
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
thing:
|
||||
- stable
|
||||
- macos-x86_64
|
||||
- x86_64-msvc
|
||||
include:
|
||||
- thing: stable
|
||||
target: x86_64-unknown-linux-gnu
|
||||
rust: stable
|
||||
os: ubuntu-latest
|
||||
- thing: macos-x86_64
|
||||
target: x86_64-apple-darwin
|
||||
rust: stable
|
||||
os: macos-latest
|
||||
- thing: x86_64-msvc
|
||||
target: x86_64-pc-windows-msvc
|
||||
rust: stable-x86_64-msvc
|
||||
os: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install Rust (rustup)
|
||||
if: matrix.os != 'macos-latest'
|
||||
run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }}
|
||||
shell: bash
|
||||
- name: Install Lua (ubuntu)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y --no-install-recommends liblua5.3-dev liblua5.2-dev liblua5.1-0-dev libluajit-5.1-dev
|
||||
- name: Install Rust (macos)
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: |
|
||||
curl https://sh.rustup.rs | sh -s -- -y
|
||||
echo ::add-path::$HOME/.cargo/bin
|
||||
shell: bash
|
||||
- name: Install GCC (aarch64-linux)
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y --no-install-recommends gcc-aarch64-linux-gnu libc6-dev-arm64-cross
|
||||
if: matrix.thing == 'aarch64-linux'
|
||||
shell: bash
|
||||
- run: rustup target add ${{ matrix.target }}
|
||||
- name: Build (Lua 5.3/5.2/5.1 and LuaJIT vendored)
|
||||
run: |
|
||||
for FEATURE in lua53 lua52 lua51 luajit; do
|
||||
echo "Building $FEATURE"
|
||||
cargo build --target ${{ matrix.target }} --release --no-default-features --features "$FEATURE vendored"
|
||||
done
|
||||
shell: bash
|
||||
- name: Build (Lua 5.3/5.2/5.1 and LuaJIT via pkg-config)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
for FEATURE in lua53 lua52 lua51 luajit; do
|
||||
echo "Building $FEATURE"
|
||||
cargo build --target ${{ matrix.target }} --release --no-default-features --features $FEATURE
|
||||
done
|
||||
shell: bash
|
||||
|
||||
test_linux:
|
||||
name: Test on Linux
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install Rust
|
||||
run: rustup update stable --no-self-update && rustup default stable
|
||||
shell: bash
|
||||
- name: Run tests (Lua 5.3 vendored)
|
||||
run: cargo test --release --no-default-features --features "lua53 vendored"
|
||||
shell: bash
|
||||
- name: Run tests (Lua 5.2 vendored)
|
||||
run: cargo test --release --no-default-features --features "lua52 vendored"
|
||||
shell: bash
|
||||
- name: Run tests (Lua 5.1 vendored)
|
||||
run: cargo test --release --no-default-features --features "lua51 vendored"
|
||||
shell: bash
|
||||
- name: Run tests (LuaJIT vendored)
|
||||
run: cargo test --release --no-default-features --features "luajit vendored"
|
||||
shell: bash
|
||||
- name: Run compile test (Lua 5.3)
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y --no-install-recommends liblua5.3-dev
|
||||
cargo test --release --no-default-features --features "lua53 vendored" -- --ignored
|
||||
|
||||
test_macos:
|
||||
name: Test on MacOS
|
||||
runs-on: macos-latest
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install Rust
|
||||
run: |
|
||||
curl https://sh.rustup.rs | sh -s -- -y
|
||||
echo ::add-path::$HOME/.cargo/bin
|
||||
shell: bash
|
||||
- name: Run tests (Lua 5.3 vendored)
|
||||
run: cargo test --release --no-default-features --features "lua53 vendored"
|
||||
shell: bash
|
||||
- name: Run tests (Lua 5.2 vendored)
|
||||
run: cargo test --release --no-default-features --features "lua52 vendored"
|
||||
shell: bash
|
||||
- name: Run tests (Lua 5.1 vendored)
|
||||
run: cargo test --release --no-default-features --features "lua51 vendored"
|
||||
shell: bash
|
||||
- name: Run tests (LuaJIT vendored)
|
||||
run: cargo test --release --no-default-features --features "luajit vendored"
|
||||
shell: bash
|
||||
|
||||
test_windows:
|
||||
name: Test on Windows
|
||||
runs-on: windows-latest
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install Rust
|
||||
run: rustup update stable --no-self-update && rustup default stable
|
||||
shell: bash
|
||||
- name: Run tests (Lua 5.3 vendored)
|
||||
run: cargo test --release --no-default-features --features "lua53 vendored"
|
||||
shell: bash
|
||||
- name: Run tests (Lua 5.2 vendored)
|
||||
run: cargo test --release --no-default-features --features "lua52 vendored"
|
||||
shell: bash
|
||||
- name: Run tests (Lua 5.1 vendored)
|
||||
run: cargo test --release --no-default-features --features "lua51 vendored"
|
||||
shell: bash
|
||||
- name: Run tests (LuaJIT vendored)
|
||||
run: cargo test --release --no-default-features --features "luajit vendored"
|
||||
shell: bash
|
||||
|
||||
rustfmt:
|
||||
name: Rustfmt
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install Rust
|
||||
run: rustup update stable && rustup default stable && rustup component add rustfmt
|
||||
- run: cargo fmt -- --check
|
||||
+7
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mlua"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@chucklefish.org>"]
|
||||
edition = "2018"
|
||||
repository = "https://github.com/khvzak/mlua"
|
||||
@@ -9,13 +9,15 @@ readme = "README.md"
|
||||
keywords = ["lua", "luajit"]
|
||||
categories = ["api-bindings"]
|
||||
license = "MIT"
|
||||
links = "lua"
|
||||
build = "build/main.rs"
|
||||
description = """
|
||||
High level bindings to Lua 5.1/5.2/5.3 (including LuaJIT)
|
||||
with support of writing native lua modules in Rust.
|
||||
"""
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "khvzak/mlua", branch = "master" }
|
||||
# github-actions = { repository = "khvzak/mlua", workflow = "CI" }
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
@@ -28,6 +30,7 @@ lua53 = []
|
||||
lua52 = []
|
||||
lua51 = []
|
||||
luajit = []
|
||||
vendored = ["lua-src", "luajit-src"]
|
||||
|
||||
[dependencies]
|
||||
num-traits = { version = "0.2.6" }
|
||||
@@ -36,6 +39,8 @@ bstr = { version = "0.2", features = ["std"], default_features = false }
|
||||
[build-dependencies]
|
||||
cc = { version = "1.0" }
|
||||
pkg-config = { version = "0.3.11" }
|
||||
lua-src = { version = "535.0.1", optional = true }
|
||||
luajit-src = { version = "210.0.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rustyline = "5.0"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# mlua
|
||||
[![Build Status]][circleci] [![Latest Version]][crates.io] [![API Documentation]][docs.rs]
|
||||
[![Build Status]][github-actions] [![Latest Version]][crates.io] [![API Documentation]][docs.rs]
|
||||
|
||||
[Build Status]: https://img.shields.io/circleci/project/github/khvzak/mlua.svg
|
||||
[circleci]: https://circleci.com/gh/khvzak/mlua
|
||||
[Build Status]: https://github.com/khvzak/mlua/workflows/CI/badge.svg
|
||||
[github-actions]: https://github.com/khvzak/mlua/actions
|
||||
[Latest Version]: https://img.shields.io/crates/v/mlua.svg
|
||||
[crates.io]: https://crates.io/crates/mlua
|
||||
[API Documentation]: https://docs.rs/mlua/badge.svg
|
||||
@@ -16,9 +16,27 @@ The `mlua` goal is to be an easy to use, practical and flexible API between Rust
|
||||
*__not__* always 100% safe due to the Lua VM nature. Also, `mlua` provides a way to write native lua
|
||||
modules in Rust.
|
||||
|
||||
### Usage
|
||||
## Usage
|
||||
|
||||
#### standalone mode
|
||||
### Choosing Lua version
|
||||
|
||||
The following features could be used to choose Lua version: `lua53` (default), `lua52`, `lua51` and `luajit`.
|
||||
|
||||
By default mlua uses `pkg-config` tool to find lua includes and lib.
|
||||
In most cases it works as desired, although sometimes could be more preferable to use a custom lua library.
|
||||
To achieve this, mlua supports `LUA_INC`, `LUA_LIB`, `LUA_LIB_NAME` and `LUA_LINK` environment variables.
|
||||
`LUA_LINK` is optional and may be `dylib` (a dynamic library) or `static` (a static library, `.a` archive).
|
||||
|
||||
An example how to use them:
|
||||
``` sh
|
||||
my_project $ LUA_INC=$HOME/tmp/lua-5.2.4/src LUA_LIB=$HOME/tmp/lua-5.2.4/src LUA_LIB_NAME=lua LUA_LINK=static cargo build
|
||||
```
|
||||
|
||||
`mlua` also supports vendored lua/luajit using the auxilary crates [lua-src](https://crates.io/crates/lua-src) and
|
||||
[luajit-src](https://crates.io/crates/luajit-src).
|
||||
Just enable the `vendored` feature and cargo will automatically build and link specified lua/luajit version. This is the easiest way to get started with mlua.
|
||||
|
||||
### Standalone mode
|
||||
Add to `Cargo.toml` :
|
||||
|
||||
``` toml
|
||||
@@ -46,7 +64,7 @@ fn main() -> LuaResult<()> {
|
||||
}
|
||||
```
|
||||
|
||||
#### module mode
|
||||
### Module mode
|
||||
|
||||
Add to `Cargo.toml` :
|
||||
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader, Error, ErrorKind, Result};
|
||||
use std::ops::Bound;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
trait CommandExt {
|
||||
fn execute(&mut self) -> Result<()>;
|
||||
}
|
||||
|
||||
impl CommandExt for Command {
|
||||
/// Execute the command and return an error if it exited with a failure status.
|
||||
fn execute(&mut self) -> Result<()> {
|
||||
self.status()
|
||||
.and_then(|status| {
|
||||
if status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(ErrorKind::Other, "non-zero exit code"))
|
||||
}
|
||||
})
|
||||
.map_err(|_| {
|
||||
Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("The command {:?} did not run successfully.", self),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn use_custom_lua<S: AsRef<str>>(include_dir: &S, lib_dir: &S, lua_lib: &S) -> Result<String> {
|
||||
let mut version_found = String::new();
|
||||
|
||||
// Find LUA_VERSION_NUM
|
||||
let mut lua_h_path = PathBuf::from(include_dir.as_ref());
|
||||
lua_h_path.push("lua.h");
|
||||
let f = File::open(lua_h_path)?;
|
||||
let reader = BufReader::new(f);
|
||||
for line in reader.lines() {
|
||||
let line = line?;
|
||||
let parts = line.split_whitespace().collect::<Vec<_>>();
|
||||
if parts.len() == 3 && parts[1] == "LUA_VERSION_NUM" {
|
||||
version_found = parts[2].to_string();
|
||||
}
|
||||
}
|
||||
|
||||
let mut static_link = "";
|
||||
if env::var("LUA_LINK").unwrap_or(String::new()) == "static" {
|
||||
static_link = "static=";
|
||||
}
|
||||
|
||||
println!("cargo:rustc-link-search=native={}", lib_dir.as_ref());
|
||||
println!("cargo:rustc-link-lib={}{}", static_link, lua_lib.as_ref());
|
||||
|
||||
Ok(version_found)
|
||||
}
|
||||
|
||||
fn build_glue<P: AsRef<Path> + std::fmt::Debug>(include_paths: &[P]) {
|
||||
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
|
||||
// Ensure the presence of glue.rs
|
||||
// if build_dir.join("glue.rs").exists() {
|
||||
// return;
|
||||
// }
|
||||
|
||||
let mut config = cc::Build::new();
|
||||
|
||||
for path in include_paths {
|
||||
config.include(path);
|
||||
}
|
||||
|
||||
// Compile and run glue.c
|
||||
let glue = build_dir.join("glue");
|
||||
|
||||
config
|
||||
.get_compiler()
|
||||
.to_command()
|
||||
.arg("src/ffi/glue/glue.c")
|
||||
.arg("-o")
|
||||
.arg(&glue)
|
||||
.execute()
|
||||
.unwrap();
|
||||
|
||||
Command::new(glue)
|
||||
.arg(build_dir.join("glue.rs"))
|
||||
.execute()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let include_dir = env::var("LUA_INC").unwrap_or(String::new());
|
||||
let lib_dir = env::var("LUA_LIB").unwrap_or(String::new());
|
||||
let lua_lib = env::var("LUA_LIB_NAME").unwrap_or(String::new());
|
||||
|
||||
println!("cargo:rerun-if-env-changed=LUA_INC");
|
||||
println!("cargo:rerun-if-env-changed=LUA_LIB");
|
||||
println!("cargo:rerun-if-env-changed=LUA_LIB_NAME");
|
||||
println!("cargo:rerun-if-env-changed=LUA_LINK");
|
||||
println!("cargo:rerun-if-changed=src/ffi/glue/glue.c");
|
||||
|
||||
if include_dir != "" && lib_dir != "" && lua_lib != "" {
|
||||
let _version = use_custom_lua(&include_dir, &lib_dir, &lua_lib).unwrap();
|
||||
build_glue(&[include_dir]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find lua via pkg-config
|
||||
|
||||
#[cfg(not(any(
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "lua51",
|
||||
feature = "luajit"
|
||||
)))]
|
||||
panic!("You must enable one of the features: lua53, lua52, lua51, luajit");
|
||||
|
||||
#[cfg(all(
|
||||
feature = "lua53",
|
||||
any(feature = "lua52", feature = "lua51", feature = "luajit")
|
||||
))]
|
||||
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
|
||||
|
||||
#[cfg(all(feature = "lua52", any(feature = "lua51", feature = "luajit")))]
|
||||
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
|
||||
|
||||
#[cfg(all(feature = "lua51", feature = "luajit"))]
|
||||
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
|
||||
|
||||
#[cfg(feature = "lua53")]
|
||||
{
|
||||
let mut lua = pkg_config::Config::new()
|
||||
.range_version((Bound::Included("5.3"), Bound::Excluded("5.4")))
|
||||
.probe("lua");
|
||||
|
||||
if lua.is_err() {
|
||||
lua = pkg_config::Config::new().probe("lua5.3");
|
||||
}
|
||||
|
||||
match lua {
|
||||
Ok(lua) => build_glue(&lua.include_paths),
|
||||
Err(err) => panic!(err),
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "lua52")]
|
||||
{
|
||||
let mut lua = pkg_config::Config::new()
|
||||
.range_version((Bound::Included("5.2"), Bound::Excluded("5.3")))
|
||||
.probe("lua");
|
||||
|
||||
if lua.is_err() {
|
||||
lua = pkg_config::Config::new().probe("lua5.2");
|
||||
}
|
||||
|
||||
match lua {
|
||||
Ok(lua) => build_glue(&lua.include_paths),
|
||||
Err(_) => panic!("Lua 5.2 not found"),
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "lua51")]
|
||||
{
|
||||
let mut lua = pkg_config::Config::new()
|
||||
.range_version((Bound::Included("5.1"), Bound::Excluded("5.2")))
|
||||
.probe("lua");
|
||||
|
||||
if lua.is_err() {
|
||||
lua = pkg_config::Config::new().probe("lua5.1");
|
||||
}
|
||||
|
||||
match lua {
|
||||
Ok(lua) => build_glue(&lua.include_paths),
|
||||
Err(err) => panic!(err),
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "luajit")]
|
||||
{
|
||||
let lua = pkg_config::Config::new()
|
||||
.range_version((Bound::Included("2.0.5"), Bound::Unbounded))
|
||||
.probe("luajit");
|
||||
|
||||
match lua {
|
||||
Ok(lua) => build_glue(&lua.include_paths),
|
||||
Err(err) => panic!(err),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader, Result};
|
||||
use std::ops::Bound;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub fn probe_lua() -> PathBuf {
|
||||
let include_dir = env::var_os("LUA_INC").unwrap_or(OsString::new());
|
||||
let lib_dir = env::var_os("LUA_LIB").unwrap_or(OsString::new());
|
||||
let lua_lib = env::var_os("LUA_LIB_NAME").unwrap_or(OsString::new());
|
||||
|
||||
println!("cargo:rerun-if-env-changed=LUA_INC");
|
||||
println!("cargo:rerun-if-env-changed=LUA_LIB");
|
||||
println!("cargo:rerun-if-env-changed=LUA_LIB_NAME");
|
||||
println!("cargo:rerun-if-env-changed=LUA_LINK");
|
||||
|
||||
if include_dir != "" && lib_dir != "" && lua_lib != "" {
|
||||
let _version = use_custom_lua(&include_dir, &lib_dir, &lua_lib).unwrap();
|
||||
return PathBuf::from(include_dir);
|
||||
}
|
||||
|
||||
// Find using via pkg-config
|
||||
|
||||
#[cfg(feature = "lua53")]
|
||||
{
|
||||
let mut lua = pkg_config::Config::new()
|
||||
.range_version((Bound::Included("5.3"), Bound::Excluded("5.4")))
|
||||
.probe("lua");
|
||||
|
||||
if lua.is_err() {
|
||||
lua = pkg_config::Config::new().probe("lua5.3");
|
||||
}
|
||||
|
||||
return lua.unwrap().include_paths[0].clone();
|
||||
}
|
||||
|
||||
#[cfg(feature = "lua52")]
|
||||
{
|
||||
let mut lua = pkg_config::Config::new()
|
||||
.range_version((Bound::Included("5.2"), Bound::Excluded("5.3")))
|
||||
.probe("lua");
|
||||
|
||||
if lua.is_err() {
|
||||
lua = pkg_config::Config::new().probe("lua5.2");
|
||||
}
|
||||
|
||||
return lua.unwrap().include_paths[0].clone();
|
||||
}
|
||||
|
||||
#[cfg(feature = "lua51")]
|
||||
{
|
||||
let mut lua = pkg_config::Config::new()
|
||||
.range_version((Bound::Included("5.1"), Bound::Excluded("5.2")))
|
||||
.probe("lua");
|
||||
|
||||
if lua.is_err() {
|
||||
lua = pkg_config::Config::new().probe("lua5.1");
|
||||
}
|
||||
|
||||
return lua.unwrap().include_paths[0].clone();
|
||||
}
|
||||
|
||||
#[cfg(feature = "luajit")]
|
||||
{
|
||||
let lua = pkg_config::Config::new()
|
||||
.range_version((Bound::Included("2.1.0"), Bound::Unbounded))
|
||||
.probe("luajit");
|
||||
|
||||
return lua.unwrap().include_paths[0].clone();
|
||||
}
|
||||
}
|
||||
|
||||
fn use_custom_lua<S: AsRef<Path>>(include_dir: &S, lib_dir: &S, lua_lib: &S) -> Result<String> {
|
||||
let mut version_found = String::new();
|
||||
|
||||
// Find LUA_VERSION_NUM
|
||||
let mut lua_h_path = include_dir.as_ref().to_owned();
|
||||
lua_h_path.push("lua.h");
|
||||
let f = File::open(lua_h_path)?;
|
||||
let reader = BufReader::new(f);
|
||||
for line in reader.lines() {
|
||||
let line = line?;
|
||||
let parts = line.split_whitespace().collect::<Vec<_>>();
|
||||
if parts.len() == 3 && parts[1] == "LUA_VERSION_NUM" {
|
||||
version_found = parts[2].to_string();
|
||||
}
|
||||
}
|
||||
|
||||
let mut link_lib = String::new();
|
||||
if env::var("LUA_LINK").unwrap_or(String::new()) == "static" {
|
||||
link_lib = "static=".to_string();
|
||||
}
|
||||
|
||||
println!(
|
||||
"cargo:rustc-link-search=native={}",
|
||||
lib_dir.as_ref().display()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-link-lib={}{}",
|
||||
link_lib,
|
||||
lua_lib.as_ref().display()
|
||||
);
|
||||
|
||||
Ok(version_found)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[cfg(any(feature = "lua53", feature = "lua52", feature = "lua51"))]
|
||||
use lua_src;
|
||||
#[cfg(feature = "luajit")]
|
||||
use luajit_src;
|
||||
|
||||
pub fn probe_lua() -> PathBuf {
|
||||
#[cfg(feature = "lua53")]
|
||||
let artifacts = lua_src::Build::new().build(lua_src::Lua53);
|
||||
#[cfg(feature = "lua52")]
|
||||
let artifacts = lua_src::Build::new().build(lua_src::Lua52);
|
||||
#[cfg(feature = "lua51")]
|
||||
let artifacts = lua_src::Build::new().build(lua_src::Lua51);
|
||||
#[cfg(feature = "luajit")]
|
||||
let artifacts = luajit_src::Build::new().build();
|
||||
|
||||
artifacts.print_cargo_metadata();
|
||||
artifacts.include_dir().to_owned()
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
#![allow(unreachable_code)]
|
||||
|
||||
use std::env;
|
||||
use std::io::{Error, ErrorKind, Result};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
#[cfg_attr(feature = "vendored", path = "find_vendored.rs")]
|
||||
#[cfg_attr(not(feature = "vendored"), path = "find_normal.rs")]
|
||||
mod find;
|
||||
|
||||
trait CommandExt {
|
||||
fn execute(&mut self) -> Result<()>;
|
||||
}
|
||||
|
||||
impl CommandExt for Command {
|
||||
/// Execute the command and return an error if it exited with a failure status.
|
||||
fn execute(&mut self) -> Result<()> {
|
||||
self.status()
|
||||
.and_then(|status| {
|
||||
if status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(ErrorKind::Other, "non-zero exit code"))
|
||||
}
|
||||
})
|
||||
.map_err(|_| {
|
||||
Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("The command {:?} did not run successfully.", self),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn build_glue<P: AsRef<Path> + std::fmt::Debug>(include_path: &P) {
|
||||
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
|
||||
let mut config = cc::Build::new();
|
||||
config.include(include_path);
|
||||
|
||||
// Compile and run glue.c
|
||||
let glue = build_dir.join("glue");
|
||||
|
||||
config
|
||||
.get_compiler()
|
||||
.to_command()
|
||||
.arg("src/ffi/glue/glue.c")
|
||||
.arg("-o")
|
||||
.arg(&glue)
|
||||
.execute()
|
||||
.unwrap();
|
||||
|
||||
Command::new(glue)
|
||||
.arg(build_dir.join("glue.rs"))
|
||||
.execute()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[cfg(not(any(
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "lua51",
|
||||
feature = "luajit"
|
||||
)))]
|
||||
panic!("You must enable one of the features: lua53, lua52, lua51, luajit");
|
||||
|
||||
#[cfg(all(
|
||||
feature = "lua53",
|
||||
any(feature = "lua52", feature = "lua51", feature = "luajit")
|
||||
))]
|
||||
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
|
||||
|
||||
#[cfg(all(feature = "lua52", any(feature = "lua51", feature = "luajit")))]
|
||||
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
|
||||
|
||||
#[cfg(all(feature = "lua51", feature = "luajit"))]
|
||||
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
|
||||
|
||||
#[cfg(all(feature = "lua51", feature = "luajit"))]
|
||||
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
|
||||
|
||||
let include_dir = find::probe_lua();
|
||||
build_glue(&include_dir);
|
||||
}
|
||||
@@ -160,3 +160,9 @@ impl<'lua> Function<'lua> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> PartialEq for Function<'lua> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
+132
-6
@@ -1,7 +1,7 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::function::Function;
|
||||
use crate::types::{Integer, LuaRef};
|
||||
@@ -166,11 +166,60 @@ impl<'lua> Table<'lua> {
|
||||
self.get::<_, Function>(key)?.call(args)
|
||||
}
|
||||
|
||||
/// Removes a key from the table, returning the value at the key
|
||||
/// if the key was previously in the table.
|
||||
pub fn raw_remove<K: ToLua<'lua>>(&self, key: K) -> Result<()> {
|
||||
self.raw_set(key, Nil)?;
|
||||
Ok(())
|
||||
/// Compares two tables for equality.
|
||||
///
|
||||
/// Tables are compared by reference first.
|
||||
/// If they are not primitively equals, then mlua will try to invoke the `__eq` metamethod.
|
||||
/// mlua will check `self` first for the metamethod, then `other` if not found.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Compare two tables using `__eq` metamethod:
|
||||
///
|
||||
/// ```
|
||||
/// # use mlua::{Lua, Result, Table};
|
||||
/// # fn main() -> Result<()> {
|
||||
/// # let lua = Lua::new();
|
||||
/// let table1 = lua.create_table()?;
|
||||
/// table1.set(1, "value")?;
|
||||
///
|
||||
/// let table2 = lua.create_table()?;
|
||||
/// table2.set(2, "value")?;
|
||||
///
|
||||
/// let always_equals_mt = lua.create_table()?;
|
||||
/// always_equals_mt.set("__eq", lua.create_function(|_, (_t1, _t2): (Table, Table)| Ok(true))?)?;
|
||||
/// table2.set_metatable(Some(always_equals_mt));
|
||||
///
|
||||
/// assert!(table1.equals(&table1.clone())?);
|
||||
/// assert!(table1.equals(&table2)?);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn equals<T: AsRef<Self>>(&self, other: T) -> Result<bool> {
|
||||
let other = other.as_ref();
|
||||
if self == other {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
// Compare using __eq metamethod if exists
|
||||
// First, check the self for the metamethod.
|
||||
// If self does not define it, then check the other table.
|
||||
if let Some(mt) = self.get_metatable() {
|
||||
if mt.contains_key("__eq")? {
|
||||
return mt
|
||||
.get::<_, Function>("__eq")?
|
||||
.call((self.clone(), other.clone()));
|
||||
}
|
||||
}
|
||||
if let Some(mt) = other.get_metatable() {
|
||||
if mt.contains_key("__eq")? {
|
||||
return mt
|
||||
.get::<_, Function>("__eq")?
|
||||
.call((self.clone(), other.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Sets a key-value pair without invoking metamethods.
|
||||
@@ -213,6 +262,70 @@ impl<'lua> Table<'lua> {
|
||||
V::from_lua(value, lua)
|
||||
}
|
||||
|
||||
/// Inserts element value at position idx to the table, shifting up the elements from table[idx].
|
||||
/// The worst case complexity is O(n), where n is the table length.
|
||||
pub fn raw_insert<V: ToLua<'lua>>(&self, idx: Integer, value: V) -> Result<()> {
|
||||
let lua = self.0.lua;
|
||||
let size = self.raw_len();
|
||||
if idx < 1 || idx > size + 1 {
|
||||
return Err(Error::RuntimeError("index out of bounds".to_string()));
|
||||
}
|
||||
|
||||
let value = value.to_lua(lua)?;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
assert_stack(lua.state, 6);
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
lua.push_value(value)?;
|
||||
|
||||
protect_lua_closure(lua.state, 2, 0, |state| {
|
||||
for i in (idx..size + 1).rev() {
|
||||
// table[i+1] = table[i]
|
||||
ffi::lua_rawgeti(state, -2, i);
|
||||
ffi::lua_rawseti(state, -3, i + 1);
|
||||
}
|
||||
ffi::lua_rawseti(state, -2, idx);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes a key from the table.
|
||||
///
|
||||
/// If `key` is an integer, mlua shifts down the elements from table[key+1],
|
||||
/// and erases element table[key]. The complexity is O(n) in worst case,
|
||||
/// where n is the table length.
|
||||
///
|
||||
/// For othey key types this is equivalent to setting table[key] = nil.
|
||||
pub fn raw_remove<K: ToLua<'lua>>(&self, key: K) -> Result<()> {
|
||||
let lua = self.0.lua;
|
||||
let key = key.to_lua(lua)?;
|
||||
match key {
|
||||
Value::Integer(idx) => {
|
||||
let size = self.raw_len();
|
||||
if idx < 1 || idx > size {
|
||||
return Err(Error::RuntimeError("index out of bounds".to_string()));
|
||||
}
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
assert_stack(lua.state, 6);
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
|
||||
protect_lua_closure(lua.state, 1, 0, |state| {
|
||||
for i in idx..size {
|
||||
ffi::lua_rawgeti(state, -1, i + 1);
|
||||
ffi::lua_rawseti(state, -2, i);
|
||||
}
|
||||
ffi::lua_pushnil(state);
|
||||
ffi::lua_rawseti(state, -2, size);
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => self.raw_set(key, Nil),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the result of the Lua `#` operator.
|
||||
///
|
||||
/// This might invoke the `__len` metamethod. Use the [`raw_len`] method if that is not desired.
|
||||
@@ -368,6 +481,19 @@ impl<'lua> Table<'lua> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> PartialEq for Table<'lua> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsRef<Table<'lua>> for Table<'lua> {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the pairs of a Lua table.
|
||||
///
|
||||
/// This struct is created by the [`Table::pairs`] method.
|
||||
|
||||
@@ -143,3 +143,9 @@ impl<'lua> Thread<'lua> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> PartialEq for Thread<'lua> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ use std::{fmt, mem, ptr};
|
||||
use crate::error::Result;
|
||||
use crate::ffi;
|
||||
use crate::lua::Lua;
|
||||
use crate::util::{assert_stack, StackGuard};
|
||||
use crate::value::MultiValue;
|
||||
|
||||
/// Type of Lua integer numbers.
|
||||
@@ -92,3 +93,16 @@ impl<'lua> Drop for LuaRef<'lua> {
|
||||
self.lua.drop_ref(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> PartialEq for LuaRef<'lua> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let lua = self.lua;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
assert_stack(lua.state, 2);
|
||||
lua.push_ref(&self);
|
||||
lua.push_ref(&other);
|
||||
ffi::lua_rawequal(lua.state, -1, -2) == 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+51
-7
@@ -2,7 +2,9 @@ use std::cell::{Ref, RefCell, RefMut};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::function::Function;
|
||||
use crate::lua::Lua;
|
||||
use crate::table::Table;
|
||||
use crate::types::LuaRef;
|
||||
use crate::util::{assert_stack, get_userdata, StackGuard};
|
||||
use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti};
|
||||
@@ -75,11 +77,6 @@ pub enum MetaMethod {
|
||||
///
|
||||
/// This is not an operator, but it will be called by the built-in `pairs` function.
|
||||
Pairs,
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
/// The `__ipairs` metamethod.
|
||||
///
|
||||
/// This is not an operator, but it will be called by the built-in `ipairs` function.
|
||||
IPairs,
|
||||
}
|
||||
|
||||
impl MetaMethod {
|
||||
@@ -117,8 +114,6 @@ impl MetaMethod {
|
||||
MetaMethod::ToString => b"__tostring",
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
MetaMethod::Pairs => b"__pairs",
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
MetaMethod::IPairs => b"__ipairs",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -398,6 +393,42 @@ impl<'lua> AnyUserData<'lua> {
|
||||
V::from_lua(res, lua)
|
||||
}
|
||||
|
||||
fn get_metatable(&self) -> Result<Table<'lua>> {
|
||||
unsafe {
|
||||
let lua = self.0.lua;
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
assert_stack(lua.state, 3);
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
|
||||
if ffi::lua_getmetatable(lua.state, -1) == 0 {
|
||||
return Err(Error::UserDataTypeMismatch);
|
||||
}
|
||||
|
||||
Ok(Table(lua.pop_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn equals<T: AsRef<Self>>(&self, other: T) -> Result<bool> {
|
||||
let other = other.as_ref();
|
||||
if self == other {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
let mt = self.get_metatable()?;
|
||||
if mt != other.get_metatable()? {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
if mt.contains_key("__eq")? {
|
||||
return mt
|
||||
.get::<_, Function>("__eq")?
|
||||
.call((self.clone(), other.clone()));
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn inspect<'a, T, R, F>(&'a self, func: F) -> Result<R>
|
||||
where
|
||||
T: 'static + UserData,
|
||||
@@ -428,3 +459,16 @@ impl<'lua> AnyUserData<'lua> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> PartialEq for AnyUserData<'lua> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsRef<AnyUserData<'lua>> for AnyUserData<'lua> {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::iter::{self, FromIterator};
|
||||
use std::{slice, str, vec};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::function::Function;
|
||||
use crate::lua::Lua;
|
||||
use crate::string::String;
|
||||
@@ -61,6 +62,51 @@ impl<'lua> Value<'lua> {
|
||||
Value::UserData(_) | Value::Error(_) => "userdata",
|
||||
}
|
||||
}
|
||||
|
||||
/// Compares two values for equality.
|
||||
///
|
||||
/// Equality comparisons do not convert strings to numbers or vice versa.
|
||||
/// Tables, Functions, Threads, and Userdata are compared by reference:
|
||||
/// two objects are considered equal only if they are the same object.
|
||||
///
|
||||
/// If Tables or Userdata have `__eq` metamethod then mlua will try to invoke it.
|
||||
/// The first value is checked first. If that value does not define a metamethod
|
||||
/// for `__eq`, then mlua will check the second value.
|
||||
/// Then mlua calls the metamethod with the two values as arguments, if found.
|
||||
pub fn equals<T: AsRef<Self>>(&self, other: T) -> Result<bool> {
|
||||
match (self, other.as_ref()) {
|
||||
(Value::Table(a), Value::Table(b)) => a.equals(b),
|
||||
(Value::UserData(a), Value::UserData(b)) => a.equals(b),
|
||||
_ => Ok(self == other.as_ref()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> PartialEq for Value<'lua> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Value::Nil, Value::Nil) => true,
|
||||
(Value::Boolean(a), Value::Boolean(b)) => a == b,
|
||||
(Value::LightUserData(a), Value::LightUserData(b)) => a == b,
|
||||
(Value::Integer(a), Value::Integer(b)) => *a == *b,
|
||||
(Value::Integer(a), Value::Number(b)) => *a as ffi::lua_Number == *b,
|
||||
(Value::Number(a), Value::Integer(b)) => *a == *b as ffi::lua_Number,
|
||||
(Value::Number(a), Value::Number(b)) => *a == *b,
|
||||
(Value::String(a), Value::String(b)) => a == b,
|
||||
(Value::Table(a), Value::Table(b)) => a == b,
|
||||
(Value::Function(a), Value::Function(b)) => a == b,
|
||||
(Value::Thread(a), Value::Thread(b)) => a == b,
|
||||
(Value::UserData(a), Value::UserData(b)) => a == b,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsRef<Value<'lua>> for Value<'lua> {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for types convertible to `Value`.
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
#![cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
feature(link_args)
|
||||
)]
|
||||
|
||||
#[cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
link_args = "-pagezero_size 10000 -image_base 100000000"
|
||||
)]
|
||||
extern "system" {}
|
||||
|
||||
use bstr::{BStr, BString};
|
||||
use mlua::{Lua, Result};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#[cfg(any(feature = "lua53", feature = "lua51"))]
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_compile_fail() {
|
||||
let t = trybuild::TestCases::new();
|
||||
t.compile_fail("tests/compile_fail/*.rs");
|
||||
|
||||
@@ -18,7 +18,8 @@ error[E0277]: the type `std::cell::UnsafeCell<mlua::lua::ExtraData>` may contain
|
||||
|
|
||||
= help: within `mlua::lua::Lua`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<mlua::lua::ExtraData>`
|
||||
= note: required because it appears within the type `std::cell::RefCell<mlua::lua::ExtraData>`
|
||||
= note: required because it appears within the type `std::marker::PhantomData<std::cell::RefCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `alloc::sync::ArcInner<std::cell::RefCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `std::marker::PhantomData<alloc::sync::ArcInner<std::cell::RefCell<mlua::lua::ExtraData>>>`
|
||||
= note: required because it appears within the type `std::sync::Arc<std::cell::RefCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `mlua::lua::Lua`
|
||||
= note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&mlua::lua::Lua`
|
||||
@@ -33,7 +34,8 @@ error[E0277]: the type `std::cell::UnsafeCell<isize>` may contain interior mutab
|
||||
= help: within `mlua::lua::Lua`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<isize>`
|
||||
= note: required because it appears within the type `std::cell::Cell<isize>`
|
||||
= note: required because it appears within the type `std::cell::RefCell<mlua::lua::ExtraData>`
|
||||
= note: required because it appears within the type `std::marker::PhantomData<std::cell::RefCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `alloc::sync::ArcInner<std::cell::RefCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `std::marker::PhantomData<alloc::sync::ArcInner<std::cell::RefCell<mlua::lua::ExtraData>>>`
|
||||
= note: required because it appears within the type `std::sync::Arc<std::cell::RefCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `mlua::lua::Lua`
|
||||
= note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&mlua::lua::Lua`
|
||||
|
||||
@@ -20,7 +20,8 @@ error[E0277]: the type `std::cell::UnsafeCell<mlua::lua::ExtraData>` may contain
|
||||
|
|
||||
= help: within `mlua::lua::Lua`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<mlua::lua::ExtraData>`
|
||||
= note: required because it appears within the type `std::cell::RefCell<mlua::lua::ExtraData>`
|
||||
= note: required because it appears within the type `std::marker::PhantomData<std::cell::RefCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `alloc::sync::ArcInner<std::cell::RefCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `std::marker::PhantomData<alloc::sync::ArcInner<std::cell::RefCell<mlua::lua::ExtraData>>>`
|
||||
= note: required because it appears within the type `std::sync::Arc<std::cell::RefCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `mlua::lua::Lua`
|
||||
= note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&mlua::lua::Lua`
|
||||
@@ -37,7 +38,8 @@ error[E0277]: the type `std::cell::UnsafeCell<isize>` may contain interior mutab
|
||||
= help: within `mlua::lua::Lua`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<isize>`
|
||||
= note: required because it appears within the type `std::cell::Cell<isize>`
|
||||
= note: required because it appears within the type `std::cell::RefCell<mlua::lua::ExtraData>`
|
||||
= note: required because it appears within the type `std::marker::PhantomData<std::cell::RefCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `alloc::sync::ArcInner<std::cell::RefCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `std::marker::PhantomData<alloc::sync::ArcInner<std::cell::RefCell<mlua::lua::ExtraData>>>`
|
||||
= note: required because it appears within the type `std::sync::Arc<std::cell::RefCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `mlua::lua::Lua`
|
||||
= note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&mlua::lua::Lua`
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
#![cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
feature(link_args)
|
||||
)]
|
||||
|
||||
#[cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
link_args = "-pagezero_size 10000 -image_base 100000000"
|
||||
)]
|
||||
extern "system" {}
|
||||
|
||||
use mlua::{Function, Lua, Result, String};
|
||||
|
||||
#[test]
|
||||
|
||||
+12
-23
@@ -1,14 +1,3 @@
|
||||
#![cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
feature(link_args)
|
||||
)]
|
||||
|
||||
#[cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
link_args = "-pagezero_size 10000 -image_base 100000000"
|
||||
)]
|
||||
extern "system" {}
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use mlua::{Lua, Result, UserData};
|
||||
@@ -16,6 +5,7 @@ use mlua::{Lua, Result, UserData};
|
||||
#[test]
|
||||
fn test_gc_control() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
let globals = lua.globals();
|
||||
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
{
|
||||
@@ -30,9 +20,8 @@ fn test_gc_control() -> Result<()> {
|
||||
impl UserData for MyUserdata {}
|
||||
|
||||
let rc = Arc::new(());
|
||||
lua.globals()
|
||||
.set("userdata", lua.create_userdata(MyUserdata(rc.clone()))?)?;
|
||||
lua.globals().raw_remove("userdata")?;
|
||||
globals.set("userdata", lua.create_userdata(MyUserdata(rc.clone()))?)?;
|
||||
globals.raw_remove("userdata")?;
|
||||
|
||||
assert_eq!(Arc::strong_count(&rc), 2);
|
||||
lua.gc_collect()?;
|
||||
@@ -51,15 +40,15 @@ fn test_gc_error() {
|
||||
match lua
|
||||
.load(
|
||||
r#"
|
||||
val = nil
|
||||
table = {}
|
||||
setmetatable(table, {
|
||||
__gc = function()
|
||||
error("gcwascalled")
|
||||
end
|
||||
})
|
||||
table = nil
|
||||
collectgarbage("collect")
|
||||
val = nil
|
||||
table = {}
|
||||
setmetatable(table, {
|
||||
__gc = function()
|
||||
error("gcwascalled")
|
||||
end
|
||||
})
|
||||
table = nil
|
||||
collectgarbage("collect")
|
||||
"#,
|
||||
)
|
||||
.exec()
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
#![cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
feature(link_args)
|
||||
)]
|
||||
|
||||
#[cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
link_args = "-pagezero_size 10000 -image_base 100000000"
|
||||
)]
|
||||
extern "system" {}
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
#![cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
feature(link_args)
|
||||
)]
|
||||
|
||||
#[cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
link_args = "-pagezero_size 10000 -image_base 100000000"
|
||||
)]
|
||||
extern "system" {}
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use mlua::{Lua, Result, String};
|
||||
|
||||
+57
-12
@@ -1,14 +1,3 @@
|
||||
#![cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
feature(link_args)
|
||||
)]
|
||||
|
||||
#[cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
link_args = "-pagezero_size 10000 -image_base 100000000"
|
||||
)]
|
||||
extern "system" {}
|
||||
|
||||
use mlua::{Lua, Nil, Result, Table, Value};
|
||||
|
||||
#[test]
|
||||
@@ -91,10 +80,32 @@ fn test_table() -> Result<()> {
|
||||
globals.set("table4", lua.create_sequence_from(vec![1, 2, 3, 4, 5])?)?;
|
||||
let table4 = globals.get::<_, Table>("table4")?;
|
||||
assert_eq!(
|
||||
table4.pairs().collect::<Result<Vec<(i64, i64)>>>()?,
|
||||
table4
|
||||
.clone()
|
||||
.pairs()
|
||||
.collect::<Result<Vec<(i64, i64)>>>()?,
|
||||
vec![(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]
|
||||
);
|
||||
|
||||
table4.raw_insert(4, 35)?;
|
||||
table4.raw_insert(7, 7)?;
|
||||
assert_eq!(
|
||||
table4
|
||||
.clone()
|
||||
.pairs()
|
||||
.collect::<Result<Vec<(i64, i64)>>>()?,
|
||||
vec![(1, 1), (2, 2), (3, 3), (4, 35), (5, 4), (6, 5), (7, 7)]
|
||||
);
|
||||
|
||||
table4.raw_remove(1)?;
|
||||
assert_eq!(
|
||||
table4
|
||||
.clone()
|
||||
.pairs()
|
||||
.collect::<Result<Vec<(i64, i64)>>>()?,
|
||||
vec![(1, 2), (2, 3), (3, 35), (4, 4), (5, 5), (6, 7)]
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -148,6 +159,40 @@ fn test_metatable() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_table_eq() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
let globals = lua.globals();
|
||||
|
||||
lua.load(
|
||||
r#"
|
||||
table1 = {1}
|
||||
table2 = {1}
|
||||
table3 = table1
|
||||
table4 = {1}
|
||||
|
||||
setmetatable(table4, {
|
||||
__eq = function(a, b) return a[1] == b[1] end
|
||||
})
|
||||
"#,
|
||||
)
|
||||
.exec()?;
|
||||
|
||||
let table1 = globals.get::<_, Table>("table1")?;
|
||||
let table2 = globals.get::<_, Table>("table2")?;
|
||||
let table3 = globals.get::<_, Table>("table3")?;
|
||||
let table4 = globals.get::<_, Table>("table4")?;
|
||||
|
||||
assert!(table1 != table2);
|
||||
assert!(!table1.equals(&table2)?);
|
||||
assert!(table1 == table3);
|
||||
assert!(table1.equals(&table3)?);
|
||||
assert!(table1 != table4);
|
||||
assert!(table1.equals(&table4)?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_table_error() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
+6
-17
@@ -1,14 +1,3 @@
|
||||
#![cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
feature(link_args)
|
||||
)]
|
||||
|
||||
#[cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
link_args = "-pagezero_size 10000 -image_base 100000000"
|
||||
)]
|
||||
extern "system" {}
|
||||
|
||||
use std::iter::FromIterator;
|
||||
use std::panic::catch_unwind;
|
||||
use std::sync::Arc;
|
||||
@@ -92,13 +81,13 @@ fn test_lua_multi() -> Result<()> {
|
||||
|
||||
lua.load(
|
||||
r#"
|
||||
function concat(arg1, arg2)
|
||||
return arg1 .. arg2
|
||||
end
|
||||
function concat(arg1, arg2)
|
||||
return arg1 .. arg2
|
||||
end
|
||||
|
||||
function mreturn()
|
||||
return 1, 2, 3, 4, 5, 6
|
||||
end
|
||||
function mreturn()
|
||||
return 1, 2, 3, 4, 5, 6
|
||||
end
|
||||
"#,
|
||||
)
|
||||
.exec()?;
|
||||
|
||||
+10
-21
@@ -1,14 +1,3 @@
|
||||
#![cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
feature(link_args)
|
||||
)]
|
||||
|
||||
#[cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
link_args = "-pagezero_size 10000 -image_base 100000000"
|
||||
)]
|
||||
extern "system" {}
|
||||
|
||||
use std::panic::catch_unwind;
|
||||
|
||||
use mlua::{Error, Function, Lua, Result, Thread, ThreadStatus};
|
||||
@@ -20,13 +9,13 @@ fn test_thread() -> Result<()> {
|
||||
let thread = lua.create_thread(
|
||||
lua.load(
|
||||
r#"
|
||||
function (s)
|
||||
local sum = s
|
||||
for i = 1,4 do
|
||||
sum = sum + coroutine.yield(sum)
|
||||
end
|
||||
return sum
|
||||
function (s)
|
||||
local sum = s
|
||||
for i = 1,4 do
|
||||
sum = sum + coroutine.yield(sum)
|
||||
end
|
||||
return sum
|
||||
end
|
||||
"#,
|
||||
)
|
||||
.eval()?,
|
||||
@@ -47,11 +36,11 @@ fn test_thread() -> Result<()> {
|
||||
let accumulate = lua.create_thread(
|
||||
lua.load(
|
||||
r#"
|
||||
function (sum)
|
||||
while true do
|
||||
sum = sum + coroutine.yield(sum)
|
||||
end
|
||||
function (sum)
|
||||
while true do
|
||||
sum = sum + coroutine.yield(sum)
|
||||
end
|
||||
end
|
||||
"#,
|
||||
)
|
||||
.eval::<Function>()?,
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
#![cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
feature(link_args)
|
||||
)]
|
||||
|
||||
#[cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
link_args = "-pagezero_size 10000 -image_base 100000000"
|
||||
)]
|
||||
extern "system" {}
|
||||
|
||||
use std::os::raw::c_void;
|
||||
|
||||
use mlua::{Function, LightUserData, Lua, Result};
|
||||
|
||||
+29
-29
@@ -1,19 +1,8 @@
|
||||
#![cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
feature(link_args)
|
||||
)]
|
||||
|
||||
#[cfg_attr(
|
||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||
link_args = "-pagezero_size 10000 -image_base 100000000"
|
||||
)]
|
||||
extern "system" {}
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use mlua::{
|
||||
AnyUserData, ExternalError, Function, Lua, MetaMethod, Result, String, UserData,
|
||||
UserDataMethods,
|
||||
UserDataMethods, Value,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -96,6 +85,9 @@ fn test_metamethods() -> Result<()> {
|
||||
MetaMethod::Sub,
|
||||
|_, (lhs, rhs): (MyUserData, MyUserData)| Ok(MyUserData(lhs.0 - rhs.0)),
|
||||
);
|
||||
methods.add_meta_function(MetaMethod::Eq, |_, (lhs, rhs): (MyUserData, MyUserData)| {
|
||||
Ok(lhs.0 == rhs.0)
|
||||
});
|
||||
methods.add_meta_method(MetaMethod::Index, |_, data, index: String| {
|
||||
if index.to_str()? == "inner" {
|
||||
Ok(data.0)
|
||||
@@ -104,7 +96,7 @@ fn test_metamethods() -> Result<()> {
|
||||
}
|
||||
});
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
methods.add_meta_method(MetaMethod::IPairs, |lua, data, ()| {
|
||||
methods.add_meta_method(MetaMethod::Pairs, |lua, data, ()| {
|
||||
use std::iter::FromIterator;
|
||||
let stateless_iter = lua.create_function(|_, (data, i): (MyUserData, i64)| {
|
||||
let i = i + 1;
|
||||
@@ -122,18 +114,19 @@ fn test_metamethods() -> Result<()> {
|
||||
let globals = lua.globals();
|
||||
globals.set("userdata1", MyUserData(7))?;
|
||||
globals.set("userdata2", MyUserData(3))?;
|
||||
globals.set("userdata3", MyUserData(3))?;
|
||||
assert_eq!(
|
||||
lua.load("userdata1 + userdata2").eval::<MyUserData>()?.0,
|
||||
10
|
||||
);
|
||||
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
let ipairs_it = {
|
||||
let pairs_it = {
|
||||
lua.load(
|
||||
r#"
|
||||
function ipairs_it()
|
||||
function pairs_it()
|
||||
local r = 0
|
||||
for i, v in ipairs(userdata1) do
|
||||
for i, v in pairs(userdata1) do
|
||||
r = r + v
|
||||
end
|
||||
return r
|
||||
@@ -141,16 +134,23 @@ fn test_metamethods() -> Result<()> {
|
||||
"#,
|
||||
)
|
||||
.exec()?;
|
||||
globals.get::<_, Function>("ipairs_it")?
|
||||
globals.get::<_, Function>("pairs_it")?
|
||||
};
|
||||
|
||||
assert_eq!(lua.load("userdata1 - userdata2").eval::<MyUserData>()?.0, 4);
|
||||
assert_eq!(lua.load("userdata1:get()").eval::<i64>()?, 7);
|
||||
assert_eq!(lua.load("userdata2.inner").eval::<i64>()?, 3);
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
assert_eq!(ipairs_it.call::<_, i64>(())?, 28);
|
||||
assert_eq!(pairs_it.call::<_, i64>(())?, 28);
|
||||
assert!(lua.load("userdata2.nonexist_field").eval::<()>().is_err());
|
||||
|
||||
let userdata2: Value = globals.get("userdata2")?;
|
||||
let userdata3: Value = globals.get("userdata3")?;
|
||||
|
||||
assert!(lua.load("userdata2 == userdata3").eval::<bool>()?);
|
||||
assert!(userdata2 != userdata3); // because references are differ
|
||||
assert!(userdata2.equals(userdata3)?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -175,18 +175,18 @@ fn test_gc_userdata() -> Result<()> {
|
||||
assert!(lua
|
||||
.load(
|
||||
r#"
|
||||
local tbl = setmetatable({
|
||||
userdata = userdata
|
||||
}, { __gc = function(self)
|
||||
-- resurrect userdata
|
||||
hatch = self.userdata
|
||||
end })
|
||||
local tbl = setmetatable({
|
||||
userdata = userdata
|
||||
}, { __gc = function(self)
|
||||
-- resurrect userdata
|
||||
hatch = self.userdata
|
||||
end })
|
||||
|
||||
tbl = nil
|
||||
userdata = nil -- make table and userdata collectable
|
||||
collectgarbage("collect")
|
||||
hatch:access()
|
||||
"#
|
||||
tbl = nil
|
||||
userdata = nil -- make table and userdata collectable
|
||||
collectgarbage("collect")
|
||||
hatch:access()
|
||||
"#
|
||||
)
|
||||
.exec()
|
||||
.is_err());
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
use mlua::{Lua, Result, Value};
|
||||
|
||||
#[test]
|
||||
fn test_value_eq() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
let globals = lua.globals();
|
||||
|
||||
lua.load(
|
||||
r#"
|
||||
table1 = {1}
|
||||
table2 = {1}
|
||||
string1 = "hello"
|
||||
string2 = "hello"
|
||||
num1 = 1
|
||||
num2 = 1.0
|
||||
num3 = "1"
|
||||
func1 = function() end
|
||||
func2 = func1
|
||||
func3 = function() end
|
||||
thread1 = coroutine.create(function() end)
|
||||
thread2 = thread1
|
||||
|
||||
setmetatable(table1, {
|
||||
__eq = function(a, b) return a[1] == b[1] end
|
||||
})
|
||||
"#,
|
||||
)
|
||||
.exec()?;
|
||||
|
||||
let table1: Value = globals.get("table1")?;
|
||||
let table2: Value = globals.get("table2")?;
|
||||
let string1: Value = globals.get("string1")?;
|
||||
let string2: Value = globals.get("string2")?;
|
||||
let num1: Value = globals.get("num1")?;
|
||||
let num2: Value = globals.get("num2")?;
|
||||
let num3: Value = globals.get("num3")?;
|
||||
let func1: Value = globals.get("func1")?;
|
||||
let func2: Value = globals.get("func2")?;
|
||||
let func3: Value = globals.get("func3")?;
|
||||
let thread1: Value = globals.get("thread1")?;
|
||||
let thread2: Value = globals.get("thread2")?;
|
||||
|
||||
assert!(table1 != table2);
|
||||
assert!(table1.equals(table2)?);
|
||||
assert!(string1 == 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!(thread1 == thread2);
|
||||
assert!(thread1.equals(thread2)?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user