mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
Compare commits
105 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b93ace0224 | |||
| 5f37bf812d | |||
| 1f7e760d20 | |||
| 90bea4aa34 | |||
| 7775b4a99c | |||
| 1d9cda10eb | |||
| 7332c6a28c | |||
| 94670e3fdb | |||
| 335f433df4 | |||
| 2aed548747 | |||
| 6a77b5f003 | |||
| aeb66115f7 | |||
| ce873a40bf | |||
| 8de75d1c18 | |||
| b6ff501b8c | |||
| 0e73ae18f4 | |||
| e62fd400d7 | |||
| 1c79f646de | |||
| 7f5fd36a2b | |||
| faf19e4a06 | |||
| 24d9099ef7 | |||
| 84003f31e7 | |||
| e0d9ec41e2 | |||
| 618874ef3c | |||
| 9f82cbe0c5 | |||
| 1a81f8d447 | |||
| bedd430eb5 | |||
| afc41ab23c | |||
| c5d0ccc433 | |||
| ce8955f5b9 | |||
| 368c4428eb | |||
| 6e2b687cb7 | |||
| 661f8e592a | |||
| c8a7aa947c | |||
| a52135b62d | |||
| 68378a3957 | |||
| c65058a40a | |||
| 93d63cef35 | |||
| b743245aba | |||
| a172c021c9 | |||
| de2c5cd9a9 | |||
| d201beadc9 | |||
| dd58cdad52 | |||
| 5c8a5e0a5a | |||
| e07c53eafe | |||
| ad619390e1 | |||
| 350602ab6e | |||
| 4b1bc88273 | |||
| 883bf082b9 | |||
| 4265250cfd | |||
| 1d9fed2207 | |||
| a67cbafff1 | |||
| 39bcb19ae7 | |||
| efcaef3db7 | |||
| 0a13a9631d | |||
| 3d42bc4ca6 | |||
| 2eb40deafd | |||
| 2595fe9885 | |||
| 4865089a78 | |||
| a35b8dda68 | |||
| 95b9fe8dac | |||
| 5952a1f709 | |||
| 73c7c94d75 | |||
| d5c22d989a | |||
| a9a4cf13f1 | |||
| c3822219e0 | |||
| f6da437d8b | |||
| 2fd6757f39 | |||
| 56407fac0d | |||
| d0fa03e9c8 | |||
| cccec914ca | |||
| 687ecc9247 | |||
| 79bfb112aa | |||
| 60c659ecff | |||
| 9f2d598517 | |||
| 1492790ece | |||
| e88f086ed8 | |||
| 5a9a308790 | |||
| 1b2b94c808 | |||
| 526e7418d8 | |||
| 24d4f04c0d | |||
| 539b569ff4 | |||
| 5c226b4915 | |||
| d366ce0dd4 | |||
| 2bd5c2f6ca | |||
| 7b0e4b4280 | |||
| 6e2bb73cff | |||
| 7efcee853d | |||
| e9c2b8d306 | |||
| d672e19365 | |||
| bda399a5b4 | |||
| fe5e87b0f5 | |||
| 0f32e9cb43 | |||
| 0efa0fcb6a | |||
| 4e19ae6ccf | |||
| c826798a6d | |||
| ee08050c1f | |||
| d8897d867b | |||
| 222f4df668 | |||
| afaa0eb639 | |||
| db5ad6bc60 | |||
| ef06c5eec9 | |||
| f7dc9da107 | |||
| 47e8a80c1c | |||
| 1a788c48f1 |
@@ -0,0 +1,23 @@
|
|||||||
|
name: coverage
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: coverage
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: xd009642/tarpaulin
|
||||||
|
options: --security-opt seccomp=unconfined
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Generate code coverage
|
||||||
|
run: |
|
||||||
|
cargo tarpaulin --verbose --features lua53,vendored,async,send,serialize --out xml --exclude-files benches --exclude-files tests --exclude-files build --exclude-files src/ffi
|
||||||
|
|
||||||
|
- name: Upload to codecov.io
|
||||||
|
uses: codecov/codecov-action@v1
|
||||||
|
with:
|
||||||
|
token: ${{secrets.CODECOV_TOKEN}}
|
||||||
|
fail_ci_if_error: true
|
||||||
+200
-112
@@ -7,141 +7,229 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
thing:
|
os: [ubuntu-18.04, macos-latest, windows-latest]
|
||||||
- stable
|
rust: [stable]
|
||||||
- macos-x86_64
|
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||||
- x86_64-msvc
|
|
||||||
include:
|
include:
|
||||||
- thing: stable
|
- os: ubuntu-18.04
|
||||||
target: x86_64-unknown-linux-gnu
|
target: x86_64-unknown-linux-gnu
|
||||||
rust: stable
|
- os: macos-latest
|
||||||
os: ubuntu-latest
|
|
||||||
- thing: macos-x86_64
|
|
||||||
target: x86_64-apple-darwin
|
target: x86_64-apple-darwin
|
||||||
rust: stable
|
- os: windows-latest
|
||||||
os: macos-latest
|
|
||||||
- thing: x86_64-msvc
|
|
||||||
target: x86_64-pc-windows-msvc
|
target: x86_64-pc-windows-msvc
|
||||||
rust: stable-x86_64-msvc
|
|
||||||
os: windows-latest
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v2
|
||||||
- name: Install Rust (rustup)
|
- uses: actions-rs/toolchain@v1
|
||||||
if: matrix.os != 'macos-latest'
|
with:
|
||||||
run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }}
|
toolchain: ${{ matrix.rust }}
|
||||||
shell: bash
|
target: ${{ matrix.target }}
|
||||||
- name: Install Lua (ubuntu)
|
override: true
|
||||||
if: matrix.os == 'ubuntu-latest'
|
- name: Build ${{ matrix.lua }} vendored
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update -y
|
cargo build --release --features "${{ matrix.lua }} vendored"
|
||||||
|
cargo build --release --features "${{ matrix.lua }} vendored async send serialize"
|
||||||
|
shell: bash
|
||||||
|
- name: Build ${{ matrix.lua }} pkg-config
|
||||||
|
if: ${{ matrix.os == 'ubuntu-18.04' && matrix.lua != 'lua54' }}
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
sudo apt-get install -y --no-install-recommends liblua5.3-dev liblua5.2-dev liblua5.1-0-dev libluajit-5.1-dev
|
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)
|
cargo build --release --features "${{ matrix.lua }}"
|
||||||
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:
|
build_aarch64_cross_macos:
|
||||||
name: Test on Linux
|
name: Cross-compile to aarch64-apple-darwin
|
||||||
runs-on: ubuntu-latest
|
runs-on: macos-11.0
|
||||||
needs: build
|
needs: build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v2
|
||||||
- name: Install Rust
|
- uses: actions-rs/toolchain@v1
|
||||||
run: rustup update stable --no-self-update && rustup default stable
|
with:
|
||||||
shell: bash
|
toolchain: nightly
|
||||||
- name: Run tests (Lua 5.3 vendored)
|
target: aarch64-apple-darwin
|
||||||
run: cargo test --release --no-default-features --features "lua53 vendored"
|
override: true
|
||||||
shell: bash
|
- name: Cross-compile
|
||||||
- name: Run tests (Lua 5.2 vendored)
|
run: cargo build --target aarch64-apple-darwin --features "${{ matrix.lua }} async send serialize 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:
|
build_aarch64_cross_ubuntu:
|
||||||
name: Test on MacOS
|
name: Cross-compile to aarch64-unknown-linux-gnu
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
needs: build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: nightly
|
||||||
|
target: aarch64-unknown-linux-gnu
|
||||||
|
override: true
|
||||||
|
- name: Install ARM compiler toolchain
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
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 }} async send serialize vendored"
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
build_armv7_cross_ubuntu:
|
||||||
|
name: Cross-compile to armv7-unknown-linux-gnueabihf
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
needs: build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
lua: [lua54, lua53, lua52, lua51]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: nightly
|
||||||
|
target: armv7-unknown-linux-gnueabihf
|
||||||
|
override: true
|
||||||
|
- name: Install ARM compiler toolchain
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
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 }} async send serialize vendored"
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
test:
|
||||||
|
name: Test
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
needs: build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-18.04, macos-latest, windows-latest]
|
||||||
|
rust: [stable]
|
||||||
|
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||||
|
include:
|
||||||
|
- os: ubuntu-18.04
|
||||||
|
target: x86_64-unknown-linux-gnu
|
||||||
|
- os: macos-latest
|
||||||
|
target: x86_64-apple-darwin
|
||||||
|
- os: windows-latest
|
||||||
|
target: x86_64-pc-windows-msvc
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
override: true
|
||||||
|
- name: Run ${{ matrix.lua }} tests
|
||||||
|
if: ${{ matrix.os != 'macos-latest' || matrix.lua != 'luajit' }}
|
||||||
|
run: |
|
||||||
|
cargo test --release --features "${{ matrix.lua }} vendored"
|
||||||
|
cargo test --release --features "${{ matrix.lua }} vendored async send serialize"
|
||||||
|
shell: bash
|
||||||
|
- name: Run compile tests (macos lua53)
|
||||||
|
if: ${{ matrix.os == 'macos-latest' && matrix.lua == 'lua53' }}
|
||||||
|
run: |
|
||||||
|
TRYBUILD=overwrite cargo test --release --features "${{ matrix.lua }} vendored" -- --ignored
|
||||||
|
TRYBUILD=overwrite cargo test --release --features "${{ matrix.lua }} vendored async send serialize" -- --ignored
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
test_luajit_macos:
|
||||||
|
name: Test LuaJIT on macOS
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
needs: build
|
needs: build
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v2
|
||||||
- name: Install Rust
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: nightly
|
||||||
|
target: x86_64-apple-darwin
|
||||||
|
override: true
|
||||||
|
- name: Run LuaJIT 2.0.5 tests
|
||||||
run: |
|
run: |
|
||||||
curl https://sh.rustup.rs | sh -s -- -y
|
brew install luajit
|
||||||
echo ::add-path::$HOME/.cargo/bin
|
cargo test --tests --release --features "luajit async send serialize" -- --test-threads=1
|
||||||
shell: bash
|
shell: bash
|
||||||
- name: Run tests (Lua 5.3 vendored)
|
- name: Run LuaJIT vendored tests
|
||||||
run: cargo test --release --no-default-features --features "lua53 vendored"
|
run: |
|
||||||
shell: bash
|
cargo test --release --features "luajit vendored async send serialize"
|
||||||
- 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
|
shell: bash
|
||||||
|
|
||||||
test_windows:
|
test_modules:
|
||||||
name: Test on Windows
|
name: Test modules
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
needs: build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-18.04, macos-latest]
|
||||||
|
rust: [stable]
|
||||||
|
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||||
|
include:
|
||||||
|
- os: ubuntu-18.04
|
||||||
|
target: x86_64-unknown-linux-gnu
|
||||||
|
- os: macos-latest
|
||||||
|
target: x86_64-apple-darwin
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
override: true
|
||||||
|
- 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")
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
test_modules_windows:
|
||||||
|
name: Test modules on Windows
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
needs: build
|
needs: build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
lua: [lua53, luajit]
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: msys2 {0}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: msys2/setup-msys2@v2
|
||||||
- name: Install Rust
|
- uses: actions/checkout@v2
|
||||||
run: rustup update stable --no-self-update && rustup default stable
|
- name: Install Rust & Lua
|
||||||
shell: bash
|
run: |
|
||||||
- name: Run tests (Lua 5.3 vendored)
|
pacman -S --noconfirm mingw-w64-x86_64-rust mingw-w64-x86_64-lua mingw-w64-x86_64-luajit mingw-w64-x86_64-pkg-config
|
||||||
run: cargo test --release --no-default-features --features "lua53 vendored"
|
- name: Run ${{ matrix.lua }} module tests
|
||||||
shell: bash
|
run: |
|
||||||
- name: Run tests (Lua 5.2 vendored)
|
(cd examples/module && cargo build --release --features "${{ matrix.lua }}")
|
||||||
run: cargo test --release --no-default-features --features "lua52 vendored"
|
(cd tests/module && cargo test --release --features "${{ matrix.lua }}")
|
||||||
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:
|
rustfmt:
|
||||||
name: Rustfmt
|
name: Rustfmt
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-18.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v2
|
||||||
- name: Install Rust
|
- uses: actions-rs/toolchain@v1
|
||||||
run: rustup update stable && rustup default stable && rustup component add rustfmt
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
components: rustfmt
|
||||||
|
override: true
|
||||||
- run: cargo fmt -- --check
|
- run: cargo fmt -- --check
|
||||||
|
|
||||||
|
clippy:
|
||||||
|
name: Clippy check
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: nightly
|
||||||
|
components: clippy
|
||||||
|
override: true
|
||||||
|
- uses: actions-rs/clippy-check@v1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
args: --features "${{ matrix.lua }},vendored,async,send,serialize
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
## v0.5.2
|
||||||
|
|
||||||
|
- Some performance optimisations (callbacks)
|
||||||
|
- `ToLua` implementation for `Cow<str>` and `Cow<CStr>`
|
||||||
|
- Fixed bug with `Scope` destruction of partially polled futures
|
||||||
|
|
||||||
|
## v0.5.1
|
||||||
|
|
||||||
|
- Support cross compilation that should work well for vendored builds (including LuaJIT with some restrictions)
|
||||||
|
- Fix numeric types conversion for 32bit Lua
|
||||||
|
- Update tokio to 1.0 for async examples
|
||||||
|
|
||||||
|
## v0.5.0
|
||||||
|
|
||||||
|
- Serde support under `serialize` feature flag.
|
||||||
|
- Re-export `mlua_derive`.
|
||||||
|
- impl `ToLua` and `FromLua` for `HashSet` and `BTreeSet`
|
||||||
|
|
||||||
|
## v0.4.2
|
||||||
|
|
||||||
|
- Added `Function::dump()` to dump lua function to a binary chunk
|
||||||
|
- Added `ChunkMode` enum to mark chunks as text or binary
|
||||||
|
- Updated `set_memory_limit` doc
|
||||||
|
|
||||||
|
## v0.4.0
|
||||||
|
|
||||||
|
- Lua 5.4 support with `MetaMethod::Close`.
|
||||||
|
- `lua53` feature is disabled by default. Now preferred Lua version have to be chosen explicitly.
|
||||||
|
- Provide safety guaraness for Lua state, which means that potenially unsafe operations, like loading C modules (using `require` or `package.loadlib`) are disabled. Equalient for the previous `Lua::new()` function is `Lua::unsafe_new()`.
|
||||||
|
- New `send` feature to require `Send`.
|
||||||
|
- New `module` feature, that disables linking to Lua Core Libraries. Required for modules.
|
||||||
|
- Don't allow `'callback` outlive `'lua` in `Lua::create_function()` to fix [the unsoundness](tests/compile/static_callback_args.rs).
|
||||||
|
- Added `Lua::into_static()` to make `'static` Lua state. This is useful to spawn async Lua threads that requires `'static`.
|
||||||
|
- New function `Lua::set_memory_limit()` (similar to `rlua`) to enable memory restrictions in Lua VM (requires Lua >= 5.2).
|
||||||
|
- `Scope`, temporary removed in v0.3, is back with async support.
|
||||||
|
- Removed deprecated `Table::call()` function.
|
||||||
|
- Added hooks support (backported from rlua 0.17).
|
||||||
|
- New `AnyUserData::has_metamethod()` function.
|
||||||
|
- LuaJIT 2.0.5 (the latest stable) support.
|
||||||
|
- Various bug fixes and improvements.
|
||||||
|
|||||||
+55
-14
@@ -1,52 +1,93 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mlua"
|
name = "mlua"
|
||||||
version = "0.2.2"
|
version = "0.5.2" # remember to update html_root_url and mlua_derive
|
||||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@chucklefish.org>"]
|
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@chucklefish.org>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
repository = "https://github.com/khvzak/mlua"
|
repository = "https://github.com/khvzak/mlua"
|
||||||
documentation = "https://docs.rs/mlua"
|
documentation = "https://docs.rs/mlua"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["lua", "luajit"]
|
keywords = ["lua", "luajit", "async", "futures", "scripting"]
|
||||||
categories = ["api-bindings"]
|
categories = ["api-bindings", "asynchronous"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
links = "lua"
|
links = "lua"
|
||||||
build = "build/main.rs"
|
build = "build/main.rs"
|
||||||
description = """
|
description = """
|
||||||
High level bindings to Lua 5.1/5.2/5.3 (including LuaJIT)
|
High level bindings to Lua 5.4/5.3/5.2/5.1 (including LuaJIT)
|
||||||
with support of writing native lua modules in Rust.
|
with async/await features and support of writing native lua modules in Rust.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
[badges]
|
[package.metadata.docs.rs]
|
||||||
# github-actions = { repository = "khvzak/mlua", workflow = "CI" }
|
features = ["lua53", "async", "send", "serialize"]
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"mlua_derive",
|
"mlua_derive",
|
||||||
|
"examples/module",
|
||||||
|
"tests/module",
|
||||||
]
|
]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["lua53"]
|
lua54 = []
|
||||||
lua53 = []
|
lua53 = []
|
||||||
lua52 = []
|
lua52 = []
|
||||||
lua51 = []
|
lua51 = []
|
||||||
luajit = []
|
luajit = []
|
||||||
vendored = ["lua-src", "luajit-src"]
|
vendored = ["lua-src", "luajit-src"]
|
||||||
|
module = ["mlua_derive"]
|
||||||
|
async = ["futures-core", "futures-task", "futures-util"]
|
||||||
|
send = []
|
||||||
|
serialize = ["serde", "erased-serde"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
num-traits = { version = "0.2.6" }
|
mlua_derive = { version = "0.5", optional = true, path = "mlua_derive" }
|
||||||
bstr = { version = "0.2", features = ["std"], default_features = false }
|
bstr = { version = "0.2", features = ["std"], default_features = false }
|
||||||
|
lazy_static = { version = "1.4" }
|
||||||
|
num-traits = { version = "0.2.14" }
|
||||||
|
futures-core = { version = "0.3.5", optional = true }
|
||||||
|
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 }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cc = { version = "1.0" }
|
cc = { version = "1.0" }
|
||||||
pkg-config = { version = "0.3.11" }
|
pkg-config = { version = "0.3.17" }
|
||||||
lua-src = { version = "535.0.1", optional = true }
|
lua-src = { version = ">= 540.0.0, < 550.0.0", optional = true }
|
||||||
luajit-src = { version = "210.0.0", optional = true }
|
luajit-src = { version = ">= 210.1.2, < 220.0.0", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rustyline = "5.0"
|
rustyline = "7.0"
|
||||||
criterion = "0.2.0"
|
criterion = { version = "0.3.4", features = ["html_reports", "async_tokio"] }
|
||||||
trybuild = "1.0"
|
trybuild = "1.0"
|
||||||
|
futures = "0.3.5"
|
||||||
|
hyper = { version = "0.14", features = ["client", "server"] }
|
||||||
|
reqwest = { version = "0.11", features = ["json"] }
|
||||||
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
|
futures-timer = "3.0"
|
||||||
|
serde_json = "1.0"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "benchmark"
|
name = "benchmark"
|
||||||
harness = false
|
harness = false
|
||||||
|
required-features = ["async"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "async_http_client"
|
||||||
|
required-features = ["async"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "async_http_reqwest"
|
||||||
|
required-features = ["async", "serialize"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "async_http_server"
|
||||||
|
required-features = ["async", "send"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "async_tcp_server"
|
||||||
|
required-features = ["async"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "serialize"
|
||||||
|
required-features = ["serialize"]
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ below:
|
|||||||
|
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2019 A. Orlenko
|
Copyright (c) 2019-2021 A. Orlenko
|
||||||
Copyright (c) 2017 rlua
|
Copyright (c) 2017 rlua
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# mlua
|
# mlua
|
||||||
[![Build Status]][github-actions] [![Latest Version]][crates.io] [![API Documentation]][docs.rs]
|
[![Build Status]][github-actions] [![Latest Version]][crates.io] [![API Documentation]][docs.rs] [![Coverage Status]][codecov.io]
|
||||||
|
|
||||||
[Build Status]: https://github.com/khvzak/mlua/workflows/CI/badge.svg
|
[Build Status]: https://github.com/khvzak/mlua/workflows/CI/badge.svg
|
||||||
[github-actions]: https://github.com/khvzak/mlua/actions
|
[github-actions]: https://github.com/khvzak/mlua/actions
|
||||||
@@ -7,22 +7,75 @@
|
|||||||
[crates.io]: https://crates.io/crates/mlua
|
[crates.io]: https://crates.io/crates/mlua
|
||||||
[API Documentation]: https://docs.rs/mlua/badge.svg
|
[API Documentation]: https://docs.rs/mlua/badge.svg
|
||||||
[docs.rs]: https://docs.rs/mlua
|
[docs.rs]: https://docs.rs/mlua
|
||||||
|
[Coverage Status]: https://codecov.io/gh/khvzak/mlua/branch/master/graph/badge.svg?token=99339FS1CG
|
||||||
|
[codecov.io]: https://codecov.io/gh/khvzak/mlua
|
||||||
|
|
||||||
[Guided Tour](examples/guided_tour.rs)
|
[Guided Tour](examples/guided_tour.rs)
|
||||||
|
|
||||||
A fork of [rlua 0.15](https://github.com/kyren/rlua/tree/0.15.3) which provides a high level
|
`mlua` is bindings to [Lua](https://www.lua.org) programming language for Rust with a goal to provide
|
||||||
interface between Rust and Lua. Unlike `rlua` , `mlua` supports Lua 5.1 (including LuaJIT), 5.2 and 5.3.
|
_safe_ (as far as it's possible), high level, easy to use, practical and flexible API.
|
||||||
The `mlua` goal is to be an easy to use, practical and flexible API between Rust and Lua but
|
|
||||||
*__not__* always 100% safe due to the Lua VM nature. Also, `mlua` provides a way to write native lua
|
Started as [rlua](https://github.com/amethyst/rlua/tree/0.15.3) fork, `mlua` supports Lua 5.4, 5.3, 5.2 and 5.1 including LuaJIT (2.0.5 and 2.1 beta) and allows to write native Lua modules in Rust as well as use Lua in a standalone mode.
|
||||||
modules in Rust.
|
|
||||||
|
`mlua` tested on Windows/macOS/Linux including module mode in [GitHub Actions] on `x86_64` platform and cross-compilation to `aarch64` (other targes are also supported).
|
||||||
|
|
||||||
|
[GitHub Actions]: https://github.com/khvzak/mlua/actions
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Choosing Lua version
|
### Feature flags
|
||||||
|
|
||||||
The following features could be used to choose Lua version: `lua53` (default), `lua52`, `lua51` and `luajit`.
|
`mlua` uses feature flags to reduce the amount of depenendies, compiled code and allow to choose only required set of features.
|
||||||
|
Below is a list of the available feature flags. By default `mlua` does not enable any features.
|
||||||
|
|
||||||
By default mlua uses `pkg-config` tool to find lua includes and lib.
|
* `lua54`: activate Lua [5.4] support
|
||||||
|
* `lua53`: activate Lua [5.3] support
|
||||||
|
* `lua52`: activate Lua [5.2] support
|
||||||
|
* `lua51`: activate Lua [5.1] support
|
||||||
|
* `luajit`: activate [LuaJIT] support
|
||||||
|
* `vendored`: build static Lua(JIT) library from sources during `mlua` compilation using [lua-src] or [luajit-src] crates
|
||||||
|
* `module`: enable module mode (building loadable `cdylib` library for Lua)
|
||||||
|
* `async`: enable async/await support (any executor can be used, eg. [tokio] or [async-std])
|
||||||
|
* `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 usign [serde] framework
|
||||||
|
|
||||||
|
[5.4]: https://www.lua.org/manual/5.4/manual.html
|
||||||
|
[5.3]: https://www.lua.org/manual/5.3/manual.html
|
||||||
|
[5.2]: https://www.lua.org/manual/5.2/manual.html
|
||||||
|
[5.1]: https://www.lua.org/manual/5.1/manual.html
|
||||||
|
[LuaJIT]: https://luajit.org/
|
||||||
|
[lua-src]: https://github.com/khvzak/lua-src-rs
|
||||||
|
[luajit-src]: https://github.com/khvzak/luajit-src-rs
|
||||||
|
[tokio]: https://github.com/tokio-rs/tokio
|
||||||
|
[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
|
||||||
|
|
||||||
|
### Async/await support
|
||||||
|
|
||||||
|
`mlua` supports async/await for all Lua versions. This works using Lua [coroutines](https://www.lua.org/manual/5.3/manual.html#2.6) and require running [Thread](https://docs.rs/mlua/latest/mlua/struct.Thread.html) along with enabling `feature = "async"` in `Cargo.toml`.
|
||||||
|
|
||||||
|
**Examples**:
|
||||||
|
- [HTTP Client](examples/async_http_client.rs)
|
||||||
|
- [HTTP Client (json)](examples/async_http_reqwest.rs)
|
||||||
|
- [HTTP Server](examples/async_http_server.rs)
|
||||||
|
- [TCP Server](examples/async_tcp_server.rs)
|
||||||
|
|
||||||
|
### Serialization (serde) support
|
||||||
|
|
||||||
|
With `serialize` feature flag enabled, `mlua` allows you to serialize/deserialize any type that implements [`serde::Serialize`] and [`serde::Deserialize`] into/from [`mlua::Value`]. In addition `mlua` provides [`serde::Serialize`] trait implementation for it (including `UserData` support).
|
||||||
|
|
||||||
|
[Example](examples/serialize.rs)
|
||||||
|
|
||||||
|
[`serde::Serialize`]: https://docs.serde.rs/serde/ser/trait.Serialize.html
|
||||||
|
[`serde::Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html
|
||||||
|
[`mlua::Value`]: https://docs.rs/mlua/latest/mlua/enum.Value.html
|
||||||
|
|
||||||
|
### Compiling
|
||||||
|
|
||||||
|
You have to enable one of the features `lua54`, `lua53`, `lua52`, `lua51` or `luajit`, according to the choosen Lua version.
|
||||||
|
|
||||||
|
By default `mlua` uses `pkg-config` tool to find lua includes and libraries for the chosen Lua version.
|
||||||
In most cases it works as desired, although sometimes could be more preferable to use a custom lua library.
|
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.
|
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).
|
`LUA_LINK` is optional and may be `dylib` (a dynamic library) or `static` (a static library, `.a` archive).
|
||||||
@@ -34,14 +87,16 @@ my_project $ LUA_INC=$HOME/tmp/lua-5.2.4/src LUA_LIB=$HOME/tmp/lua-5.2.4/src LUA
|
|||||||
|
|
||||||
`mlua` also supports vendored lua/luajit using the auxilary crates [lua-src](https://crates.io/crates/lua-src) and
|
`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).
|
[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.
|
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
|
### Standalone mode
|
||||||
|
In a standalone mode `mlua` allows to add to your application scripting support with a gently configured Lua runtime to ensure safety and soundness.
|
||||||
|
|
||||||
Add to `Cargo.toml` :
|
Add to `Cargo.toml` :
|
||||||
|
|
||||||
``` toml
|
``` toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mlua = "0.2"
|
mlua = { version = "0.5", features = ["lua53", "vendored"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
`main.rs`
|
`main.rs`
|
||||||
@@ -65,6 +120,9 @@ fn main() -> LuaResult<()> {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Module mode
|
### Module mode
|
||||||
|
In a module mode `mlua` allows to create a compiled Lua module that can be loaded from Lua code using [`require`](https://www.lua.org/manual/5.3/manual.html#pdf-require). In this case `mlua` uses an external Lua runtime which could lead to potential unsafety due to unpredictability of the Lua environment and usage of libraries such as [`debug`](https://www.lua.org/manual/5.3/manual.html#6.10).
|
||||||
|
|
||||||
|
[Example](examples/module)
|
||||||
|
|
||||||
Add to `Cargo.toml` :
|
Add to `Cargo.toml` :
|
||||||
|
|
||||||
@@ -73,15 +131,12 @@ Add to `Cargo.toml` :
|
|||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mlua = "0.2"
|
mlua = { version = "0.5", features = ["lua53", "vendored", "module"] }
|
||||||
mlua_derive = "0.2"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`lib.rs` :
|
`lib.rs` :
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[macro_use]
|
|
||||||
extern crate mlua_derive;
|
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
|
|
||||||
fn hello(_: &Lua, name: String) -> LuaResult<()> {
|
fn hello(_: &Lua, name: String) -> LuaResult<()> {
|
||||||
@@ -89,7 +144,7 @@ fn hello(_: &Lua, name: String) -> LuaResult<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[lua_module]
|
#[mlua::lua_module]
|
||||||
fn my_module(lua: &Lua) -> LuaResult<LuaTable> {
|
fn my_module(lua: &Lua) -> LuaResult<LuaTable> {
|
||||||
let exports = lua.create_table()?;
|
let exports = lua.create_table()?;
|
||||||
exports.set("hello", lua.create_function(hello)?)?;
|
exports.set("hello", lua.create_function(hello)?)?;
|
||||||
@@ -97,27 +152,48 @@ fn my_module(lua: &Lua) -> LuaResult<LuaTable> {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
And then (macos example):
|
And then (**macOS** example):
|
||||||
|
|
||||||
``` sh
|
``` sh
|
||||||
$ cargo build
|
$ cargo rustc -- -C link-arg=-undefined -C link-arg=dynamic_lookup
|
||||||
$ ln -s ./target/debug/libmy_module.dylib ./my_module.so
|
$ ln -s ./target/debug/libmy_module.dylib ./my_module.so
|
||||||
$ lua5.3 -e 'require("my_module").hello("world")'
|
$ lua5.3 -e 'require("my_module").hello("world")'
|
||||||
hello, world!
|
hello, world!
|
||||||
```
|
```
|
||||||
|
|
||||||
|
On macOS, you need to set additional linker arguments. One option is to compile with `cargo rustc --release -- -C link-arg=-undefined -C link-arg=dynamic_lookup`, the other is to create a `.cargo/config` with the following content:
|
||||||
|
``` toml
|
||||||
|
[target.x86_64-apple-darwin]
|
||||||
|
rustflags = [
|
||||||
|
"-C", "link-arg=-undefined",
|
||||||
|
"-C", "link-arg=dynamic_lookup",
|
||||||
|
]
|
||||||
|
|
||||||
|
[target.aarch64-apple-darwin]
|
||||||
|
rustflags = [
|
||||||
|
"-C", "link-arg=-undefined",
|
||||||
|
"-C", "link-arg=dynamic_lookup",
|
||||||
|
]
|
||||||
|
```
|
||||||
|
On Linux you can build modules normally with `cargo build --release`.
|
||||||
|
Vendored and non-vendored builds are supported for these OS.
|
||||||
|
|
||||||
|
On Windows `vendored` mode for modules is not supported since you need to link to a Lua dll.
|
||||||
|
Easiest way is to use either MinGW64 (as part of [MSYS2](https://github.com/msys2/msys2) package) with `pkg-config` or
|
||||||
|
MSVC with `LUA_INC` / `LUA_LIB` / `LUA_LIB_NAME` environment variables.
|
||||||
|
|
||||||
|
More details about compiling and linking Lua modules can be found on the [Building Modules](http://lua-users.org/wiki/BuildingModules) page.
|
||||||
|
|
||||||
## Safety
|
## Safety
|
||||||
|
|
||||||
One of the `mlua` goals is to provide *safe* API between Rust and Lua.
|
One of the `mlua` goals is to provide *safe* API between Rust and Lua.
|
||||||
Every place where the Lua C API may trigger an error longjmp
|
Every place where the Lua C API may trigger an error longjmp in any way is protected by `lua_pcall`,
|
||||||
in any way is protected by `lua_pcall` , and the user of the library is protected
|
and the user of the library is protected from directly interacting with unsafe things like the Lua stack,
|
||||||
from directly interacting with unsafe things like the Lua stack, and there is
|
and there is overhead associated with this safety.
|
||||||
overhead associated with this safety.
|
|
||||||
|
|
||||||
Unfortunately, `mlua` does not provide absolute safety even without using `unsafe` .
|
Unfortunately, `mlua` does not provide absolute safety even without using `unsafe` .
|
||||||
This library contains a huge amount of unsafe code. There are almost
|
This library contains a huge amount of unsafe code. There are almost certainly bugs still lurking in this library!
|
||||||
certainly bugs still lurking in this library! It is surprisingly, fiendishly
|
It is surprisingly, fiendishly difficult to use the Lua C API without the potential for unsafety.
|
||||||
difficult to use the Lua C API without the potential for unsafety.
|
|
||||||
|
|
||||||
## Panic handling
|
## Panic handling
|
||||||
|
|
||||||
@@ -141,10 +217,9 @@ let _ = lua.load(r#"
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
```
|
```
|
||||||
|
|
||||||
`mlua` should also be panic safe in another way as well, which is that any `Lua`
|
`mlua` should also be panic safe in another way as well, which is that any `Lua` instances or handles
|
||||||
instances or handles remains usable after a user generated panic, and such
|
remains usable after a user generated panic, and such panics should not break internal invariants or
|
||||||
panics should not break internal invariants or leak Lua stack space. This is
|
leak Lua stack space. This is mostly important to safely use `mlua` types in Drop impls, as you should not be
|
||||||
mostly important to safely use `mlua` types in Drop impls, as you should not be
|
|
||||||
using panics for general error handling.
|
using panics for general error handling.
|
||||||
|
|
||||||
Below is a list of `mlua` behaviors that should be considered a bug.
|
Below is a list of `mlua` behaviors that should be considered a bug.
|
||||||
|
|||||||
+169
-100
@@ -5,18 +5,29 @@
|
|||||||
|
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
|
||||||
link_args = "-pagezero_size 10000 -image_base 100000000"
|
link_args = "-pagezero_size 10000 -image_base 100000000",
|
||||||
|
allow(unused_attributes)
|
||||||
)]
|
)]
|
||||||
extern "system" {}
|
extern "system" {}
|
||||||
|
|
||||||
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
|
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
|
||||||
|
use std::time::Duration;
|
||||||
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
|
|
||||||
|
fn collect_gc_twice(lua: &Lua) {
|
||||||
|
lua.gc_collect().unwrap();
|
||||||
|
lua.gc_collect().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
fn create_table(c: &mut Criterion) {
|
fn create_table(c: &mut Criterion) {
|
||||||
c.bench_function("create table", |b| {
|
let lua = Lua::new();
|
||||||
b.iter_batched_ref(
|
|
||||||
|| Lua::new(),
|
c.bench_function("create [table empty]", |b| {
|
||||||
|lua| {
|
b.iter_batched(
|
||||||
|
|| collect_gc_twice(&lua),
|
||||||
|
|_| {
|
||||||
lua.create_table().unwrap();
|
lua.create_table().unwrap();
|
||||||
},
|
},
|
||||||
BatchSize::SmallInput,
|
BatchSize::SmallInput,
|
||||||
@@ -25,12 +36,14 @@ fn create_table(c: &mut Criterion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_array(c: &mut Criterion) {
|
fn create_array(c: &mut Criterion) {
|
||||||
c.bench_function("create array 10", |b| {
|
let lua = Lua::new();
|
||||||
b.iter_batched_ref(
|
|
||||||
|| Lua::new(),
|
c.bench_function("create [array] 10", |b| {
|
||||||
|lua| {
|
b.iter_batched(
|
||||||
|
|| collect_gc_twice(&lua),
|
||||||
|
|_| {
|
||||||
let table = lua.create_table().unwrap();
|
let table = lua.create_table().unwrap();
|
||||||
for i in 1..11 {
|
for i in 1..=10 {
|
||||||
table.set(i, i).unwrap();
|
table.set(i, i).unwrap();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -40,10 +53,12 @@ fn create_array(c: &mut Criterion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_string_table(c: &mut Criterion) {
|
fn create_string_table(c: &mut Criterion) {
|
||||||
c.bench_function("create string table 10", |b| {
|
let lua = Lua::new();
|
||||||
b.iter_batched_ref(
|
|
||||||
|| Lua::new(),
|
c.bench_function("create [table string] 10", |b| {
|
||||||
|lua| {
|
b.iter_batched(
|
||||||
|
|| collect_gc_twice(&lua),
|
||||||
|
|_| {
|
||||||
let table = lua.create_table().unwrap();
|
let table = lua.create_table().unwrap();
|
||||||
for &s in &["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] {
|
for &s in &["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] {
|
||||||
let s = lua.create_string(s).unwrap();
|
let s = lua.create_string(s).unwrap();
|
||||||
@@ -55,30 +70,20 @@ fn create_string_table(c: &mut Criterion) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_add_function(c: &mut Criterion) {
|
fn call_lua_function(c: &mut Criterion) {
|
||||||
c.bench_function("call add function 3 10", |b| {
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
c.bench_function("call Lua function [sum] 3 10", |b| {
|
||||||
b.iter_batched_ref(
|
b.iter_batched_ref(
|
||||||
|| {
|
|| {
|
||||||
let lua = Lua::new();
|
collect_gc_twice(&lua);
|
||||||
let f = {
|
lua.load("function(a, b, c) return a + b + c end")
|
||||||
let f: LuaFunction = lua
|
.eval::<LuaFunction>()
|
||||||
.load(
|
.unwrap()
|
||||||
r#"
|
|
||||||
function(a, b, c)
|
|
||||||
return a + b + c
|
|
||||||
end
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.eval()
|
|
||||||
.unwrap();
|
|
||||||
lua.create_registry_value(f).unwrap()
|
|
||||||
};
|
|
||||||
(lua, f)
|
|
||||||
},
|
},
|
||||||
|(lua, f)| {
|
|function| {
|
||||||
let add_function: LuaFunction = lua.registry_value(f).unwrap();
|
|
||||||
for i in 0..10 {
|
for i in 0..10 {
|
||||||
let _result: i64 = add_function.call((i, i + 1, i + 2)).unwrap();
|
let _result: i64 = function.call((i, i + 1, i + 2)).unwrap();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
BatchSize::SmallInput,
|
BatchSize::SmallInput,
|
||||||
@@ -86,72 +91,72 @@ fn call_add_function(c: &mut Criterion) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_add_callback(c: &mut Criterion) {
|
fn call_sum_callback(c: &mut Criterion) {
|
||||||
c.bench_function("call callback add 2 10", |b| {
|
let lua = Lua::new();
|
||||||
|
let callback = lua
|
||||||
|
.create_function(|_, (a, b, c): (i64, i64, i64)| Ok(a + b + c))
|
||||||
|
.unwrap();
|
||||||
|
lua.globals().set("callback", callback).unwrap();
|
||||||
|
|
||||||
|
c.bench_function("call Rust callback [sum] 3 10", |b| {
|
||||||
b.iter_batched_ref(
|
b.iter_batched_ref(
|
||||||
|| {
|
|| {
|
||||||
let lua = Lua::new();
|
collect_gc_twice(&lua);
|
||||||
let f = {
|
lua.load("function() for i = 1,10 do callback(i, i+1, i+2) end end")
|
||||||
let c: LuaFunction = lua
|
.eval::<LuaFunction>()
|
||||||
.create_function(|_, (a, b, c): (i64, i64, i64)| Ok(a + b + c))
|
.unwrap()
|
||||||
.unwrap();
|
|
||||||
lua.globals().set("callback", c).unwrap();
|
|
||||||
let f: LuaFunction = lua
|
|
||||||
.load(
|
|
||||||
r#"
|
|
||||||
function()
|
|
||||||
for i = 1,10 do
|
|
||||||
callback(i, i, i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.eval()
|
|
||||||
.unwrap();
|
|
||||||
lua.create_registry_value(f).unwrap()
|
|
||||||
};
|
|
||||||
(lua, f)
|
|
||||||
},
|
},
|
||||||
|(lua, f)| {
|
|function| {
|
||||||
let entry_function: LuaFunction = lua.registry_value(f).unwrap();
|
function.call::<_, ()>(()).unwrap();
|
||||||
entry_function.call::<_, ()>(()).unwrap();
|
|
||||||
},
|
},
|
||||||
BatchSize::SmallInput,
|
BatchSize::SmallInput,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_append_callback(c: &mut Criterion) {
|
fn call_async_sum_callback(c: &mut Criterion) {
|
||||||
c.bench_function("call callback append 10", |b| {
|
let lua = Lua::new();
|
||||||
|
let callback = lua
|
||||||
|
.create_async_function(|_, (a, b, c): (i64, i64, i64)| async move { Ok(a + b + c) })
|
||||||
|
.unwrap();
|
||||||
|
lua.globals().set("callback", callback).unwrap();
|
||||||
|
|
||||||
|
c.bench_function("call async Rust callback [sum] 3 10", |b| {
|
||||||
|
let rt = Runtime::new().unwrap();
|
||||||
|
b.to_async(rt).iter_batched(
|
||||||
|
|| {
|
||||||
|
collect_gc_twice(&lua);
|
||||||
|
lua.load("function() for i = 1,10 do callback(i, i+1, i+2) end end")
|
||||||
|
.eval::<LuaFunction>()
|
||||||
|
.unwrap()
|
||||||
|
},
|
||||||
|
|function| async move {
|
||||||
|
function.call_async::<_, ()>(()).await.unwrap();
|
||||||
|
},
|
||||||
|
BatchSize::SmallInput,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_concat_callback(c: &mut Criterion) {
|
||||||
|
let lua = Lua::new();
|
||||||
|
let callback = lua
|
||||||
|
.create_function(|_, (a, b): (LuaString, LuaString)| {
|
||||||
|
Ok(format!("{}{}", a.to_str()?, b.to_str()?))
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
lua.globals().set("callback", callback).unwrap();
|
||||||
|
|
||||||
|
c.bench_function("call Rust callback [concat string] 10", |b| {
|
||||||
b.iter_batched_ref(
|
b.iter_batched_ref(
|
||||||
|| {
|
|| {
|
||||||
let lua = Lua::new();
|
collect_gc_twice(&lua);
|
||||||
let f = {
|
lua.load("function() for i = 1,10 do callback('a', tostring(i)) end end")
|
||||||
let c: LuaFunction = lua
|
.eval::<LuaFunction>()
|
||||||
.create_function(|_, (a, b): (LuaString, LuaString)| {
|
.unwrap()
|
||||||
Ok(format!("{}{}", a.to_str()?, b.to_str()?))
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
lua.globals().set("callback", c).unwrap();
|
|
||||||
let f: LuaFunction = lua
|
|
||||||
.load(
|
|
||||||
r#"
|
|
||||||
function()
|
|
||||||
for _ = 1,10 do
|
|
||||||
callback("a", "b")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.eval()
|
|
||||||
.unwrap();
|
|
||||||
lua.create_registry_value(f).unwrap()
|
|
||||||
};
|
|
||||||
(lua, f)
|
|
||||||
},
|
},
|
||||||
|(lua, f)| {
|
|function| {
|
||||||
let entry_function: LuaFunction = lua.registry_value(f).unwrap();
|
function.call::<_, ()>(()).unwrap();
|
||||||
entry_function.call::<_, ()>(()).unwrap();
|
|
||||||
},
|
},
|
||||||
BatchSize::SmallInput,
|
BatchSize::SmallInput,
|
||||||
);
|
);
|
||||||
@@ -159,10 +164,12 @@ fn call_append_callback(c: &mut Criterion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_registry_values(c: &mut Criterion) {
|
fn create_registry_values(c: &mut Criterion) {
|
||||||
c.bench_function("create registry 10", |b| {
|
let lua = Lua::new();
|
||||||
b.iter_batched_ref(
|
|
||||||
|| Lua::new(),
|
c.bench_function("create [registry value] 10", |b| {
|
||||||
|lua| {
|
b.iter_batched(
|
||||||
|
|| collect_gc_twice(&lua),
|
||||||
|
|_| {
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
lua.create_registry_value(lua.pack(true).unwrap()).unwrap();
|
lua.create_registry_value(lua.pack(true).unwrap()).unwrap();
|
||||||
}
|
}
|
||||||
@@ -177,10 +184,12 @@ fn create_userdata(c: &mut Criterion) {
|
|||||||
struct UserData(i64);
|
struct UserData(i64);
|
||||||
impl LuaUserData for UserData {}
|
impl LuaUserData for UserData {}
|
||||||
|
|
||||||
c.bench_function("create userdata 10", |b| {
|
let lua = Lua::new();
|
||||||
b.iter_batched_ref(
|
|
||||||
|| Lua::new(),
|
c.bench_function("create [table userdata] 10", |b| {
|
||||||
|lua| {
|
b.iter_batched(
|
||||||
|
|| collect_gc_twice(&lua),
|
||||||
|
|_| {
|
||||||
let table: LuaTable = lua.create_table().unwrap();
|
let table: LuaTable = lua.create_table().unwrap();
|
||||||
for i in 1..11 {
|
for i in 1..11 {
|
||||||
table.set(i, UserData(i)).unwrap();
|
table.set(i, UserData(i)).unwrap();
|
||||||
@@ -191,20 +200,80 @@ fn create_userdata(c: &mut Criterion) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn call_userdata_method(c: &mut Criterion) {
|
||||||
|
struct UserData(i64);
|
||||||
|
impl LuaUserData for UserData {
|
||||||
|
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
methods.add_method("method", |_, this, ()| Ok(this.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let lua = Lua::new();
|
||||||
|
lua.globals().set("userdata", UserData(10)).unwrap();
|
||||||
|
|
||||||
|
c.bench_function("call [userdata method] 10", |b| {
|
||||||
|
b.iter_batched_ref(
|
||||||
|
|| {
|
||||||
|
collect_gc_twice(&lua);
|
||||||
|
lua.load("function() for i = 1,10 do userdata:method() end end")
|
||||||
|
.eval::<LuaFunction>()
|
||||||
|
.unwrap()
|
||||||
|
},
|
||||||
|
|function| {
|
||||||
|
function.call::<_, ()>(()).unwrap();
|
||||||
|
},
|
||||||
|
BatchSize::SmallInput,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_async_userdata_method(c: &mut Criterion) {
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct UserData(i64);
|
||||||
|
impl LuaUserData for UserData {
|
||||||
|
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
methods.add_async_method("method", |_, this, ()| async move { Ok(this.0) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let lua = Lua::new();
|
||||||
|
lua.globals().set("userdata", UserData(10)).unwrap();
|
||||||
|
|
||||||
|
c.bench_function("call async [userdata method] 10", |b| {
|
||||||
|
let rt = Runtime::new().unwrap();
|
||||||
|
b.to_async(rt).iter_batched(
|
||||||
|
|| {
|
||||||
|
collect_gc_twice(&lua);
|
||||||
|
lua.load("function() for i = 1,10 do userdata:method() end end")
|
||||||
|
.eval::<LuaFunction>()
|
||||||
|
.unwrap()
|
||||||
|
},
|
||||||
|
|function| async move {
|
||||||
|
function.call_async::<_, ()>(()).await.unwrap();
|
||||||
|
},
|
||||||
|
BatchSize::SmallInput,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
criterion_group! {
|
criterion_group! {
|
||||||
name = benches;
|
name = benches;
|
||||||
config = Criterion::default()
|
config = Criterion::default()
|
||||||
.sample_size(200)
|
.sample_size(300)
|
||||||
|
.measurement_time(Duration::from_secs(10))
|
||||||
.noise_threshold(0.02);
|
.noise_threshold(0.02);
|
||||||
targets =
|
targets =
|
||||||
create_table,
|
create_table,
|
||||||
create_array,
|
create_array,
|
||||||
create_string_table,
|
create_string_table,
|
||||||
call_add_function,
|
call_lua_function,
|
||||||
call_add_callback,
|
call_sum_callback,
|
||||||
call_append_callback,
|
call_async_sum_callback,
|
||||||
|
call_concat_callback,
|
||||||
create_registry_values,
|
create_registry_values,
|
||||||
create_userdata,
|
create_userdata,
|
||||||
|
call_userdata_method,
|
||||||
|
call_async_userdata_method,
|
||||||
}
|
}
|
||||||
|
|
||||||
criterion_main!(benches);
|
criterion_main!(benches);
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub fn probe_lua() -> PathBuf {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
+59
-27
@@ -1,73 +1,103 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::OsString;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufRead, BufReader, Result};
|
use std::io::{BufRead, BufReader, Result};
|
||||||
use std::ops::Bound;
|
use std::ops::Bound;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
pub fn probe_lua() -> PathBuf {
|
pub fn probe_lua() -> PathBuf {
|
||||||
let include_dir = env::var_os("LUA_INC").unwrap_or(OsString::new());
|
let include_dir = env::var_os("LUA_INC").unwrap_or_default();
|
||||||
let lib_dir = env::var_os("LUA_LIB").unwrap_or(OsString::new());
|
let lib_dir = env::var_os("LUA_LIB").unwrap_or_default();
|
||||||
let lua_lib = env::var_os("LUA_LIB_NAME").unwrap_or(OsString::new());
|
let lua_lib = env::var_os("LUA_LIB_NAME").unwrap_or_default();
|
||||||
|
|
||||||
println!("cargo:rerun-if-env-changed=LUA_INC");
|
println!("cargo:rerun-if-env-changed=LUA_INC");
|
||||||
println!("cargo:rerun-if-env-changed=LUA_LIB");
|
println!("cargo:rerun-if-env-changed=LUA_LIB");
|
||||||
println!("cargo:rerun-if-env-changed=LUA_LIB_NAME");
|
println!("cargo:rerun-if-env-changed=LUA_LIB_NAME");
|
||||||
println!("cargo:rerun-if-env-changed=LUA_LINK");
|
println!("cargo:rerun-if-env-changed=LUA_LINK");
|
||||||
|
|
||||||
if include_dir != "" && lib_dir != "" && lua_lib != "" {
|
let need_lua_lib = cfg!(any(not(feature = "module"), target_os = "windows"));
|
||||||
|
|
||||||
|
if include_dir != "" && (!need_lua_lib || lib_dir != "") {
|
||||||
|
if lua_lib == "" {
|
||||||
|
panic!("LUA_LIB_NAME is not set");
|
||||||
|
}
|
||||||
let _version = use_custom_lua(&include_dir, &lib_dir, &lua_lib).unwrap();
|
let _version = use_custom_lua(&include_dir, &lib_dir, &lua_lib).unwrap();
|
||||||
return PathBuf::from(include_dir);
|
return PathBuf::from(include_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find using via pkg-config
|
// Find using `pkg-config`
|
||||||
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
{
|
||||||
|
let mut lua = pkg_config::Config::new()
|
||||||
|
.range_version((Bound::Included("5.4"), Bound::Excluded("5.5")))
|
||||||
|
.cargo_metadata(need_lua_lib)
|
||||||
|
.probe("lua");
|
||||||
|
|
||||||
|
if lua.is_err() {
|
||||||
|
lua = pkg_config::Config::new()
|
||||||
|
.cargo_metadata(need_lua_lib)
|
||||||
|
.probe("lua5.4");
|
||||||
|
}
|
||||||
|
|
||||||
|
lua.unwrap().include_paths[0].clone()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(feature = "lua53")]
|
||||||
{
|
{
|
||||||
let mut lua = pkg_config::Config::new()
|
let mut lua = pkg_config::Config::new()
|
||||||
.range_version((Bound::Included("5.3"), Bound::Excluded("5.4")))
|
.range_version((Bound::Included("5.3"), Bound::Excluded("5.4")))
|
||||||
|
.cargo_metadata(need_lua_lib)
|
||||||
.probe("lua");
|
.probe("lua");
|
||||||
|
|
||||||
if lua.is_err() {
|
if lua.is_err() {
|
||||||
lua = pkg_config::Config::new().probe("lua5.3");
|
lua = pkg_config::Config::new()
|
||||||
|
.cargo_metadata(need_lua_lib)
|
||||||
|
.probe("lua5.3");
|
||||||
}
|
}
|
||||||
|
|
||||||
return lua.unwrap().include_paths[0].clone();
|
lua.unwrap().include_paths[0].clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lua52")]
|
#[cfg(feature = "lua52")]
|
||||||
{
|
{
|
||||||
let mut lua = pkg_config::Config::new()
|
let mut lua = pkg_config::Config::new()
|
||||||
.range_version((Bound::Included("5.2"), Bound::Excluded("5.3")))
|
.range_version((Bound::Included("5.2"), Bound::Excluded("5.3")))
|
||||||
|
.cargo_metadata(need_lua_lib)
|
||||||
.probe("lua");
|
.probe("lua");
|
||||||
|
|
||||||
if lua.is_err() {
|
if lua.is_err() {
|
||||||
lua = pkg_config::Config::new().probe("lua5.2");
|
lua = pkg_config::Config::new()
|
||||||
|
.cargo_metadata(need_lua_lib)
|
||||||
|
.probe("lua5.2");
|
||||||
}
|
}
|
||||||
|
|
||||||
return lua.unwrap().include_paths[0].clone();
|
lua.unwrap().include_paths[0].clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lua51")]
|
#[cfg(feature = "lua51")]
|
||||||
{
|
{
|
||||||
let mut lua = pkg_config::Config::new()
|
let mut lua = pkg_config::Config::new()
|
||||||
.range_version((Bound::Included("5.1"), Bound::Excluded("5.2")))
|
.range_version((Bound::Included("5.1"), Bound::Excluded("5.2")))
|
||||||
|
.cargo_metadata(need_lua_lib)
|
||||||
.probe("lua");
|
.probe("lua");
|
||||||
|
|
||||||
if lua.is_err() {
|
if lua.is_err() {
|
||||||
lua = pkg_config::Config::new().probe("lua5.1");
|
lua = pkg_config::Config::new()
|
||||||
|
.cargo_metadata(need_lua_lib)
|
||||||
|
.probe("lua5.1");
|
||||||
}
|
}
|
||||||
|
|
||||||
return lua.unwrap().include_paths[0].clone();
|
lua.unwrap().include_paths[0].clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "luajit")]
|
#[cfg(feature = "luajit")]
|
||||||
{
|
{
|
||||||
let lua = pkg_config::Config::new()
|
let lua = pkg_config::Config::new()
|
||||||
.range_version((Bound::Included("2.1.0"), Bound::Unbounded))
|
.range_version((Bound::Included("2.0.5"), Bound::Unbounded))
|
||||||
|
.cargo_metadata(need_lua_lib)
|
||||||
.probe("luajit");
|
.probe("luajit");
|
||||||
|
|
||||||
return lua.unwrap().include_paths[0].clone();
|
lua.unwrap().include_paths[0].clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,20 +117,22 @@ fn use_custom_lua<S: AsRef<Path>>(include_dir: &S, lib_dir: &S, lua_lib: &S) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut link_lib = String::new();
|
let link_lib = match env::var("LUA_LINK") {
|
||||||
if env::var("LUA_LINK").unwrap_or(String::new()) == "static" {
|
Ok(s) if s == "static" => "static=",
|
||||||
link_lib = "static=".to_string();
|
_ => "",
|
||||||
}
|
};
|
||||||
|
|
||||||
println!(
|
if cfg!(any(not(feature = "module"), target_os = "windows")) {
|
||||||
"cargo:rustc-link-search=native={}",
|
println!(
|
||||||
lib_dir.as_ref().display()
|
"cargo:rustc-link-search=native={}",
|
||||||
);
|
lib_dir.as_ref().display()
|
||||||
println!(
|
);
|
||||||
"cargo:rustc-link-lib={}{}",
|
println!(
|
||||||
link_lib,
|
"cargo:rustc-link-lib={}{}",
|
||||||
lua_lib.as_ref().display()
|
link_lib,
|
||||||
);
|
lua_lib.as_ref().display()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(version_found)
|
Ok(version_found)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
use std::path::PathBuf;
|
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 {
|
pub fn probe_lua() -> PathBuf {
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
let artifacts = lua_src::Build::new().build(lua_src::Lua54);
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(feature = "lua53")]
|
||||||
let artifacts = lua_src::Build::new().build(lua_src::Lua53);
|
let artifacts = lua_src::Build::new().build(lua_src::Lua53);
|
||||||
#[cfg(feature = "lua52")]
|
#[cfg(feature = "lua52")]
|
||||||
@@ -15,6 +12,8 @@ pub fn probe_lua() -> PathBuf {
|
|||||||
#[cfg(feature = "luajit")]
|
#[cfg(feature = "luajit")]
|
||||||
let artifacts = luajit_src::Build::new().build();
|
let artifacts = luajit_src::Build::new().build();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "module"))]
|
||||||
artifacts.print_cargo_metadata();
|
artifacts.print_cargo_metadata();
|
||||||
|
|
||||||
artifacts.include_dir().to_owned()
|
artifacts.include_dir().to_owned()
|
||||||
}
|
}
|
||||||
|
|||||||
+164
-10
@@ -1,12 +1,47 @@
|
|||||||
#![allow(unreachable_code)]
|
#![allow(unreachable_code)]
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io::{Error, ErrorKind, Result};
|
use std::fs::File;
|
||||||
|
use std::io::{Error, ErrorKind, Result, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
#[cfg_attr(feature = "vendored", path = "find_vendored.rs")]
|
#[cfg_attr(
|
||||||
#[cfg_attr(not(feature = "vendored"), path = "find_normal.rs")]
|
all(
|
||||||
|
feature = "vendored",
|
||||||
|
any(
|
||||||
|
feature = "lua54",
|
||||||
|
feature = "lua53",
|
||||||
|
feature = "lua52",
|
||||||
|
feature = "lua51",
|
||||||
|
feature = "luajit"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
path = "find_vendored.rs"
|
||||||
|
)]
|
||||||
|
#[cfg_attr(
|
||||||
|
all(
|
||||||
|
not(feature = "vendored"),
|
||||||
|
any(
|
||||||
|
feature = "lua54",
|
||||||
|
feature = "lua53",
|
||||||
|
feature = "lua52",
|
||||||
|
feature = "lua51",
|
||||||
|
feature = "luajit"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
path = "find_normal.rs"
|
||||||
|
)]
|
||||||
|
#[cfg_attr(
|
||||||
|
not(any(
|
||||||
|
feature = "lua54",
|
||||||
|
feature = "lua53",
|
||||||
|
feature = "lua52",
|
||||||
|
feature = "lua51",
|
||||||
|
feature = "luajit"
|
||||||
|
)),
|
||||||
|
path = "find_dummy.rs"
|
||||||
|
)]
|
||||||
mod find;
|
mod find;
|
||||||
|
|
||||||
trait CommandExt {
|
trait CommandExt {
|
||||||
@@ -57,30 +92,149 @@ fn build_glue<P: AsRef<Path> + std::fmt::Debug>(include_path: &P) {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When cross-compiling, we cannot use `build_glue` as we cannot run the generated
|
||||||
|
// executable. Instead, let's take a stab at synthesizing the likely values.
|
||||||
|
// If you're cross-compiling and using a non-vendored library then there is a chance
|
||||||
|
// that the values selected here may be incorrect, but we have no way to determine
|
||||||
|
// that here.
|
||||||
|
fn generate_glue() -> Result<()> {
|
||||||
|
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||||
|
let mut glue = File::create(build_dir.join("glue.rs"))?;
|
||||||
|
writeln!(
|
||||||
|
glue,
|
||||||
|
"/* This file was generated by build/main.rs; do not modify by hand */"
|
||||||
|
)?;
|
||||||
|
writeln!(glue, "use std::os::raw::*;")?;
|
||||||
|
|
||||||
|
writeln!(glue, "/* luaconf.h */")?;
|
||||||
|
let pointer_bit_width: usize = env::var("CARGO_CFG_TARGET_POINTER_WIDTH")
|
||||||
|
.unwrap()
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
|
writeln!(
|
||||||
|
glue,
|
||||||
|
"pub const LUA_EXTRASPACE: c_int = {} / 8;",
|
||||||
|
pointer_bit_width
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// This is generally hardcoded to this size
|
||||||
|
writeln!(glue, "pub const LUA_IDSIZE: c_int = 60;")?;
|
||||||
|
|
||||||
|
// Unless the target is restricted, the defaults are 64 bit
|
||||||
|
writeln!(glue, "pub type LUA_NUMBER = c_double;")?;
|
||||||
|
writeln!(glue, "pub type LUA_INTEGER = i64;")?;
|
||||||
|
writeln!(glue, "pub type LUA_UNSIGNED = u64;")?;
|
||||||
|
|
||||||
|
writeln!(glue, "/* lua.h */")?;
|
||||||
|
let version = if cfg!(any(feature = "luajit", feature = "lua51")) {
|
||||||
|
(5, 1, 0)
|
||||||
|
} else if cfg!(feature = "lua52") {
|
||||||
|
(5, 2, 0)
|
||||||
|
} else if cfg!(feature = "lua53") {
|
||||||
|
(5, 3, 0)
|
||||||
|
} else if cfg!(feature = "lua54") {
|
||||||
|
(5, 4, 0)
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
writeln!(
|
||||||
|
glue,
|
||||||
|
"pub const LUA_VERSION_NUM: c_int = {};",
|
||||||
|
(version.0 * 100) + version.1
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let max_stack = if pointer_bit_width >= 32 {
|
||||||
|
1_000_000
|
||||||
|
} else {
|
||||||
|
15_000
|
||||||
|
};
|
||||||
|
writeln!(
|
||||||
|
glue,
|
||||||
|
"pub const LUA_REGISTRYINDEX: c_int = -{} - 1000;",
|
||||||
|
max_stack
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// These two are only defined in lua 5.1
|
||||||
|
writeln!(glue, "pub const LUA_ENVIRONINDEX: c_int = -10001;")?;
|
||||||
|
writeln!(glue, "pub const LUA_GLOBALSINDEX: c_int = -10002;")?;
|
||||||
|
|
||||||
|
writeln!(glue, "/* lauxlib.h */")?;
|
||||||
|
// This is only defined in lua 5.3 and up, but we can always generate its value here,
|
||||||
|
// even if we don't use it.
|
||||||
|
// This matches the default definition in lauxlib.h
|
||||||
|
writeln!(glue, "pub const LUAL_NUMSIZES: c_int = std::mem::size_of::<LUA_INTEGER>() as c_int * 16 + std::mem::size_of::<LUA_NUMBER>() as c_int;")?;
|
||||||
|
|
||||||
|
writeln!(glue, "/* lualib.h */")?;
|
||||||
|
write!(
|
||||||
|
glue,
|
||||||
|
r#"
|
||||||
|
#[cfg(feature = "luajit")]
|
||||||
|
pub const LUA_BITLIBNAME: &str = "bit";
|
||||||
|
#[cfg(not(feature = "luajit"))]
|
||||||
|
pub const LUA_BITLIBNAME: &str = "bit32";
|
||||||
|
|
||||||
|
pub const LUA_COLIBNAME: &str = "coroutine";
|
||||||
|
pub const LUA_DBLIBNAME: &str = "debug";
|
||||||
|
pub const LUA_IOLIBNAME: &str = "io";
|
||||||
|
pub const LUA_LOADLIBNAME: &str = "package";
|
||||||
|
pub const LUA_MATHLIBNAME: &str = "math";
|
||||||
|
pub const LUA_OSLIBNAME: &str = "os";
|
||||||
|
pub const LUA_STRLIBNAME: &str = "string";
|
||||||
|
pub const LUA_TABLIBNAME: &str = "table";
|
||||||
|
pub const LUA_UTF8LIBNAME: &str = "utf8";
|
||||||
|
|
||||||
|
pub const LUA_JITLIBNAME: &str = "jit";
|
||||||
|
pub const LUA_FFILIBNAME: &str = "ffi";
|
||||||
|
"#
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(
|
||||||
|
feature = "lua54",
|
||||||
feature = "lua53",
|
feature = "lua53",
|
||||||
feature = "lua52",
|
feature = "lua52",
|
||||||
feature = "lua51",
|
feature = "lua51",
|
||||||
feature = "luajit"
|
feature = "luajit"
|
||||||
)))]
|
)))]
|
||||||
panic!("You must enable one of the features: lua53, lua52, lua51, luajit");
|
compile_error!("You must enable one of the features: lua54, lua53, lua52, lua51, luajit");
|
||||||
|
|
||||||
|
#[cfg(all(
|
||||||
|
feature = "lua54",
|
||||||
|
any(
|
||||||
|
feature = "lua53",
|
||||||
|
feature = "lua52",
|
||||||
|
feature = "lua51",
|
||||||
|
feature = "luajit"
|
||||||
|
)
|
||||||
|
))]
|
||||||
|
compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit");
|
||||||
|
|
||||||
#[cfg(all(
|
#[cfg(all(
|
||||||
feature = "lua53",
|
feature = "lua53",
|
||||||
any(feature = "lua52", feature = "lua51", feature = "luajit")
|
any(feature = "lua52", feature = "lua51", feature = "luajit")
|
||||||
))]
|
))]
|
||||||
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
|
compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit");
|
||||||
|
|
||||||
#[cfg(all(feature = "lua52", any(feature = "lua51", feature = "luajit")))]
|
#[cfg(all(feature = "lua52", any(feature = "lua51", feature = "luajit")))]
|
||||||
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
|
compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit");
|
||||||
|
|
||||||
#[cfg(all(feature = "lua51", feature = "luajit"))]
|
#[cfg(all(feature = "lua51", feature = "luajit"))]
|
||||||
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
|
compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit");
|
||||||
|
|
||||||
#[cfg(all(feature = "lua51", feature = "luajit"))]
|
// We don't support "vendored module" mode on windows
|
||||||
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
|
#[cfg(all(feature = "vendored", feature = "module", target_os = "windows"))]
|
||||||
|
compile_error!(
|
||||||
|
"Vendored (static) builds are not supported for modules on Windows.\n"
|
||||||
|
+ "Please, use `pkg-config` or custom mode to link to a Lua dll."
|
||||||
|
);
|
||||||
|
|
||||||
let include_dir = find::probe_lua();
|
let include_dir = find::probe_lua();
|
||||||
build_glue(&include_dir);
|
if env::var("TARGET").unwrap() != env::var("HOST").unwrap() {
|
||||||
|
generate_glue().unwrap();
|
||||||
|
} else {
|
||||||
|
build_glue(&include_dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use bstr::BString;
|
||||||
|
use hyper::body::{Body as HyperBody, HttpBody as _};
|
||||||
|
use hyper::Client as HyperClient;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
use mlua::{Error, Lua, Result, UserData, UserDataMethods};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct BodyReader(Arc<Mutex<HyperBody>>);
|
||||||
|
|
||||||
|
impl BodyReader {
|
||||||
|
fn new(body: HyperBody) -> Self {
|
||||||
|
BodyReader(Arc::new(Mutex::new(body)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserData for BodyReader {
|
||||||
|
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
methods.add_async_method("read", |_, reader, ()| async move {
|
||||||
|
let mut reader = reader.0.lock().await;
|
||||||
|
if let Some(bytes) = reader.data().await {
|
||||||
|
let bytes = bytes.map_err(Error::external)?;
|
||||||
|
return Ok(Some(BString::from(bytes.as_ref())));
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
let fetch_url = lua.create_async_function(|lua, uri: String| async move {
|
||||||
|
let client = HyperClient::new();
|
||||||
|
let uri = uri.parse().map_err(Error::external)?;
|
||||||
|
let resp = client.get(uri).await.map_err(Error::external)?;
|
||||||
|
|
||||||
|
let lua_resp = lua.create_table()?;
|
||||||
|
lua_resp.set("status", resp.status().as_u16())?;
|
||||||
|
|
||||||
|
let mut headers = HashMap::new();
|
||||||
|
for (key, value) in resp.headers().iter() {
|
||||||
|
headers
|
||||||
|
.entry(key.as_str())
|
||||||
|
.or_insert(Vec::new())
|
||||||
|
.push(value.to_str().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_resp.set("headers", headers)?;
|
||||||
|
lua_resp.set("body", BodyReader::new(resp.into_body()))?;
|
||||||
|
|
||||||
|
Ok(lua_resp)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let globals = lua.globals();
|
||||||
|
globals.set("fetch_url", fetch_url)?;
|
||||||
|
|
||||||
|
let f = lua
|
||||||
|
.load(
|
||||||
|
r#"
|
||||||
|
local res = fetch_url(...)
|
||||||
|
print(res.status)
|
||||||
|
for key, vals in pairs(res.headers) do
|
||||||
|
for _, val in ipairs(vals) do
|
||||||
|
print(key..": "..val)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
repeat
|
||||||
|
local body = res.body:read()
|
||||||
|
if body then
|
||||||
|
print(body)
|
||||||
|
end
|
||||||
|
until not body
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.into_function()?;
|
||||||
|
|
||||||
|
f.call_async("http://httpbin.org/ip").await
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
use mlua::{Error, Lua, LuaSerdeExt, Result};
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
let globals = lua.globals();
|
||||||
|
globals.set("null", lua.null()?)?;
|
||||||
|
|
||||||
|
let fetch_json = lua.create_async_function(|lua, uri: String| async move {
|
||||||
|
let resp = reqwest::get(&uri)
|
||||||
|
.await
|
||||||
|
.and_then(|resp| resp.error_for_status())
|
||||||
|
.map_err(Error::external)?;
|
||||||
|
let json = resp
|
||||||
|
.json::<serde_json::Value>()
|
||||||
|
.await
|
||||||
|
.map_err(Error::external)?;
|
||||||
|
lua.to_value(&json)
|
||||||
|
})?;
|
||||||
|
globals.set("fetch_json", fetch_json)?;
|
||||||
|
|
||||||
|
let f = lua
|
||||||
|
.load(
|
||||||
|
r#"
|
||||||
|
function print_r(t, indent)
|
||||||
|
local indent = indent or ''
|
||||||
|
for k, v in pairs(t) do
|
||||||
|
io.write(indent, tostring(k))
|
||||||
|
if type(v) == "table" then io.write(':\n') print_r(v, indent..' ')
|
||||||
|
else io.write(': ', v == null and "null" or tostring(v), '\n') end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local res = fetch_json(...)
|
||||||
|
print_r(res)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.into_function()?;
|
||||||
|
|
||||||
|
f.call_async("https://httpbin.org/anything?arg0=val0").await
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
use std::net::SocketAddr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use hyper::server::conn::AddrStream;
|
||||||
|
use hyper::service::{make_service_fn, service_fn};
|
||||||
|
use hyper::{Body, Request, Response, Server};
|
||||||
|
|
||||||
|
use mlua::{Error, Function, Lua, Result, Table, UserData, UserDataMethods};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct LuaRequest(Arc<(SocketAddr, Request<Body>)>);
|
||||||
|
|
||||||
|
impl UserData for LuaRequest {
|
||||||
|
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
methods.add_method("remote_addr", |_lua, req, ()| Ok((req.0).0.to_string()));
|
||||||
|
methods.add_method("method", |_lua, req, ()| Ok((req.0).1.method().to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_server(handler: Function<'static>) -> Result<()> {
|
||||||
|
let make_svc = make_service_fn(|socket: &AddrStream| {
|
||||||
|
let remote_addr = socket.remote_addr();
|
||||||
|
let handler = handler.clone();
|
||||||
|
async move {
|
||||||
|
Ok::<_, Error>(service_fn(move |req: Request<Body>| {
|
||||||
|
let handler = handler.clone();
|
||||||
|
async move {
|
||||||
|
let lua_req = LuaRequest(Arc::new((remote_addr, req)));
|
||||||
|
let lua_resp: Table = handler.call_async(lua_req).await?;
|
||||||
|
let body = lua_resp
|
||||||
|
.get::<_, Option<String>>("body")?
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let mut resp = Response::builder()
|
||||||
|
.status(lua_resp.get::<_, Option<u16>>("status")?.unwrap_or(200));
|
||||||
|
|
||||||
|
if let Some(headers) = lua_resp.get::<_, Option<Table>>("headers")? {
|
||||||
|
for pair in headers.pairs::<String, String>() {
|
||||||
|
let (h, v) = pair?;
|
||||||
|
resp = resp.header(&h, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok::<_, Error>(resp.body(Body::from(body)).unwrap())
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let addr = ([127, 0, 0, 1], 3000).into();
|
||||||
|
let server = Server::bind(&addr).executor(LocalExec).serve(make_svc);
|
||||||
|
|
||||||
|
println!("Listening on http://{}", addr);
|
||||||
|
|
||||||
|
tokio::task::LocalSet::new()
|
||||||
|
.run_until(server)
|
||||||
|
.await
|
||||||
|
.map_err(Error::external)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
|
let lua = Lua::new().into_static();
|
||||||
|
|
||||||
|
let handler: Function = lua
|
||||||
|
.load(
|
||||||
|
r#"
|
||||||
|
function(req)
|
||||||
|
return {
|
||||||
|
status = 200,
|
||||||
|
headers = {
|
||||||
|
["X-Req-Method"] = req:method(),
|
||||||
|
["X-Remote-Addr"] = req:remote_addr(),
|
||||||
|
},
|
||||||
|
body = "Hello, World!"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.eval()?;
|
||||||
|
|
||||||
|
run_server(handler).await?;
|
||||||
|
|
||||||
|
// Consume the static reference and drop it.
|
||||||
|
// This is safe as long as we don't hold any other references to Lua
|
||||||
|
// or alive resources.
|
||||||
|
unsafe { Lua::from_static(lua) };
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
struct LocalExec;
|
||||||
|
|
||||||
|
impl<F> hyper::rt::Executor<F> for LocalExec
|
||||||
|
where
|
||||||
|
F: std::future::Future + 'static, // not requiring `Send`
|
||||||
|
{
|
||||||
|
fn execute(&self, fut: F) {
|
||||||
|
tokio::task::spawn_local(fut);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use bstr::BString;
|
||||||
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
use tokio::task;
|
||||||
|
|
||||||
|
use mlua::{Function, Lua, Result, UserData, UserDataMethods};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct LuaTcp;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct LuaTcpListener(Arc<Mutex<TcpListener>>);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct LuaTcpStream(Arc<Mutex<TcpStream>>);
|
||||||
|
|
||||||
|
impl UserData for LuaTcp {
|
||||||
|
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
methods.add_async_function("bind", |_, addr: String| async move {
|
||||||
|
let listener = TcpListener::bind(addr).await?;
|
||||||
|
Ok(LuaTcpListener(Arc::new(Mutex::new(listener))))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserData for LuaTcpListener {
|
||||||
|
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
methods.add_async_method("accept", |_, listener, ()| async move {
|
||||||
|
let (stream, _) = listener.0.lock().await.accept().await?;
|
||||||
|
Ok(LuaTcpStream(Arc::new(Mutex::new(stream))))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserData for LuaTcpStream {
|
||||||
|
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
methods.add_async_method("peer_addr", |_, stream, ()| async move {
|
||||||
|
Ok(stream.0.lock().await.peer_addr()?.to_string())
|
||||||
|
});
|
||||||
|
|
||||||
|
methods.add_async_method("read", |_, stream, size: usize| async move {
|
||||||
|
let mut buf = vec![0; size];
|
||||||
|
let n = stream.0.lock().await.read(&mut buf).await?;
|
||||||
|
buf.truncate(n);
|
||||||
|
Ok(BString::from(buf))
|
||||||
|
});
|
||||||
|
|
||||||
|
methods.add_async_method("write", |_, stream, data: BString| async move {
|
||||||
|
let n = stream.0.lock().await.write(&data).await?;
|
||||||
|
Ok(n)
|
||||||
|
});
|
||||||
|
|
||||||
|
methods.add_async_method("close", |_, stream, ()| async move {
|
||||||
|
stream.0.lock().await.shutdown().await?;
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_server(lua: &'static Lua) -> Result<()> {
|
||||||
|
let spawn = lua.create_function(move |_, func: Function| {
|
||||||
|
task::spawn_local(async move { func.call_async::<_, ()>(()).await });
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let globals = lua.globals();
|
||||||
|
globals.set("tcp", LuaTcp)?;
|
||||||
|
globals.set("spawn", spawn)?;
|
||||||
|
|
||||||
|
let server = lua
|
||||||
|
.load(
|
||||||
|
r#"
|
||||||
|
local addr = ...
|
||||||
|
local listener = tcp.bind(addr)
|
||||||
|
print("listening on "..addr)
|
||||||
|
|
||||||
|
local accept_new = true
|
||||||
|
while true do
|
||||||
|
local stream = listener:accept()
|
||||||
|
local peer_addr = stream:peer_addr()
|
||||||
|
print("connected from "..peer_addr)
|
||||||
|
|
||||||
|
if not accept_new then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
spawn(function()
|
||||||
|
while true do
|
||||||
|
local data = stream:read(100)
|
||||||
|
data = data:match("^%s*(.-)%s*$") -- trim
|
||||||
|
print("["..peer_addr.."] "..data)
|
||||||
|
if data == "bye" then
|
||||||
|
stream:write("bye bye\n")
|
||||||
|
stream:close()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if data == "exit" then
|
||||||
|
stream:close()
|
||||||
|
accept_new = false
|
||||||
|
return
|
||||||
|
end
|
||||||
|
stream:write("echo: "..data.."\n")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.into_function()?;
|
||||||
|
|
||||||
|
task::LocalSet::new()
|
||||||
|
.run_until(server.call_async::<_, ()>("0.0.0.0:1234"))
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let lua = Lua::new().into_static();
|
||||||
|
|
||||||
|
run_server(lua).await.unwrap();
|
||||||
|
|
||||||
|
// Consume the static reference and drop it.
|
||||||
|
// This is safe as long as we don't hold any other references to Lua
|
||||||
|
// or alive resources.
|
||||||
|
unsafe { Lua::from_static(lua) };
|
||||||
|
}
|
||||||
@@ -164,11 +164,10 @@ fn main() -> Result<()> {
|
|||||||
< f32::EPSILON
|
< f32::EPSILON
|
||||||
);
|
);
|
||||||
|
|
||||||
// Normally, Rust types passed to `Lua` must be `Send`, because `Lua` itself is `Send`, and
|
// Normally, Rust types passed to `Lua` must be `'static`, because there is no way to be
|
||||||
// must be `'static`, because there is no way to be sure of their lifetime inside the Lua
|
// sure of their lifetime inside the Lua state. There is, however, a limited way to lift this
|
||||||
// state. There is, however, a limited way to lift both of these requirements. You can
|
// requirement. You can call `Lua::scope` to create userdata and callbacks types that only live
|
||||||
// call `Lua::scope` to create userdata and callbacks types that only live for as long
|
// for as long as the call to scope, but do not have to be `'static` (and `Send`).
|
||||||
// as the call to scope, but do not have to be `Send` OR `'static`.
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut rust_val = 0;
|
let mut rust_val = 0;
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[target.x86_64-apple-darwin]
|
||||||
|
rustflags = [
|
||||||
|
"-C", "link-arg=-undefined",
|
||||||
|
"-C", "link-arg=dynamic_lookup",
|
||||||
|
]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
name = "rust_module"
|
||||||
|
version = "0.0.0"
|
||||||
|
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
lua54 = ["mlua/lua54"]
|
||||||
|
lua53 = ["mlua/lua53"]
|
||||||
|
lua52 = ["mlua/lua52"]
|
||||||
|
lua51 = ["mlua/lua51"]
|
||||||
|
luajit = ["mlua/luajit"]
|
||||||
|
vendored = ["mlua/vendored"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
mlua = { path = "../..", features = ["module"] }
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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)?)?;
|
||||||
|
Ok(exports)
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
use mlua::{Error, Lua, LuaSerdeExt, Result, UserData, Value};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
enum Transmission {
|
||||||
|
Manual,
|
||||||
|
Automatic,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Engine {
|
||||||
|
v: u32,
|
||||||
|
kw: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Car {
|
||||||
|
active: bool,
|
||||||
|
model: String,
|
||||||
|
transmission: Transmission,
|
||||||
|
engine: Engine,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserData for Car {}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
let globals = lua.globals();
|
||||||
|
|
||||||
|
// Create Car struct from a Lua table
|
||||||
|
let car: Car = lua.from_value(lua.load(r#"
|
||||||
|
{active = true, model = "Volkswagen Golf", transmission = "Automatic", engine = {v = 1499, kw = 90}}
|
||||||
|
"#).eval()?)?;
|
||||||
|
|
||||||
|
// Set it as (serializable) userdata
|
||||||
|
globals.set("null", lua.null()?)?;
|
||||||
|
globals.set("array_mt", lua.array_metatable()?)?;
|
||||||
|
globals.set("car", lua.create_ser_userdata(car)?)?;
|
||||||
|
|
||||||
|
// Create a Lua table with multiple data types
|
||||||
|
let val: Value = lua
|
||||||
|
.load(r#"{driver = "Boris", car = car, price = null, points = setmetatable({}, array_mt)}"#)
|
||||||
|
.eval()?;
|
||||||
|
|
||||||
|
// Serialize the table above to JSON
|
||||||
|
let json_str = serde_json::to_string(&val).map_err(Error::external)?;
|
||||||
|
println!("{}", json_str);
|
||||||
|
|
||||||
|
// Create Lua Value from JSON (or any serializable type)
|
||||||
|
let json = serde_json::json!({
|
||||||
|
"key": "value",
|
||||||
|
"null": null,
|
||||||
|
"array": [],
|
||||||
|
});
|
||||||
|
globals.set("json_value", lua.to_value(&json)?)?;
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
assert(json_value["key"] == "value")
|
||||||
|
assert(json_value["null"] == null)
|
||||||
|
assert(#(json_value["array"]) == 0)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.exec()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mlua_derive"
|
name = "mlua_derive"
|
||||||
version = "0.2.0"
|
version = "0.5.0"
|
||||||
authors = ["Aleksandr Orlenko <zxteam@protonmail.com>"]
|
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "Procedural macros for the mlua crate."
|
description = "Procedural macros for the mlua crate."
|
||||||
repository = "https://github.com/khvzak/mlua"
|
repository = "https://github.com/khvzak/mlua"
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ pub fn lua_module(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
let ext_entrypoint_name = Ident::new(&format!("luaopen_{}", item.sig.ident), Span::call_site());
|
let ext_entrypoint_name = Ident::new(&format!("luaopen_{}", item.sig.ident), Span::call_site());
|
||||||
|
|
||||||
let wrapped = quote_spanned! { span =>
|
let wrapped = quote_spanned! { span =>
|
||||||
|
mlua::require_module_feature!();
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn #ext_entrypoint_name(state: *mut mlua::lua_State) -> std::os::raw::c_int {
|
unsafe extern "C" fn #ext_entrypoint_name(state: *mut mlua::lua_State) -> std::os::raw::c_int {
|
||||||
#item
|
#item
|
||||||
|
|||||||
+123
-10
@@ -1,4 +1,5 @@
|
|||||||
use std::collections::{BTreeMap, HashMap};
|
use std::borrow::Cow;
|
||||||
|
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use std::hash::{BuildHasher, Hash};
|
use std::hash::{BuildHasher, Hash};
|
||||||
use std::string::String as StdString;
|
use std::string::String as StdString;
|
||||||
@@ -12,7 +13,7 @@ use crate::lua::Lua;
|
|||||||
use crate::string::String;
|
use crate::string::String;
|
||||||
use crate::table::Table;
|
use crate::table::Table;
|
||||||
use crate::thread::Thread;
|
use crate::thread::Thread;
|
||||||
use crate::types::{LightUserData, Number};
|
use crate::types::{LightUserData, MaybeSend};
|
||||||
use crate::userdata::{AnyUserData, UserData};
|
use crate::userdata::{AnyUserData, UserData};
|
||||||
use crate::value::{FromLua, Nil, ToLua, Value};
|
use crate::value::{FromLua, Nil, ToLua, Value};
|
||||||
|
|
||||||
@@ -122,7 +123,7 @@ impl<'lua> FromLua<'lua> for AnyUserData<'lua> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua, T: 'static + Send + UserData> ToLua<'lua> for T {
|
impl<'lua, T: 'static + MaybeSend + UserData> ToLua<'lua> for T {
|
||||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
Ok(Value::UserData(lua.create_userdata(self)?))
|
Ok(Value::UserData(lua.create_userdata(self)?))
|
||||||
}
|
}
|
||||||
@@ -167,7 +168,7 @@ impl<'lua> ToLua<'lua> for bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> FromLua<'lua> for bool {
|
impl<'lua> FromLua<'lua> for bool {
|
||||||
fn from_lua(v: Value, _: &'lua Lua) -> Result<Self> {
|
fn from_lua(v: Value<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||||
match v {
|
match v {
|
||||||
Value::Nil => Ok(false),
|
Value::Nil => Ok(false),
|
||||||
Value::Boolean(b) => Ok(b),
|
Value::Boolean(b) => Ok(b),
|
||||||
@@ -183,7 +184,7 @@ impl<'lua> ToLua<'lua> for LightUserData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> FromLua<'lua> for LightUserData {
|
impl<'lua> FromLua<'lua> for LightUserData {
|
||||||
fn from_lua(value: Value, _: &'lua Lua) -> Result<Self> {
|
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||||
match value {
|
match value {
|
||||||
Value::LightUserData(ud) => Ok(ud),
|
Value::LightUserData(ud) => Ok(ud),
|
||||||
_ => Err(Error::FromLuaConversionError {
|
_ => Err(Error::FromLuaConversionError {
|
||||||
@@ -216,12 +217,18 @@ impl<'lua> FromLua<'lua> for StdString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua, 'a> ToLua<'lua> for &'a str {
|
impl<'lua> ToLua<'lua> for &str {
|
||||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
Ok(Value::String(lua.create_string(self)?))
|
Ok(Value::String(lua.create_string(self)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'lua> ToLua<'lua> for Cow<'_, str> {
|
||||||
|
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
|
Ok(Value::String(lua.create_string(self.as_bytes())?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'lua> ToLua<'lua> for CString {
|
impl<'lua> ToLua<'lua> for CString {
|
||||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
Ok(Value::String(lua.create_string(self.as_bytes())?))
|
Ok(Value::String(lua.create_string(self.as_bytes())?))
|
||||||
@@ -250,13 +257,19 @@ impl<'lua> FromLua<'lua> for CString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua, 'a> ToLua<'lua> for &'a CStr {
|
impl<'lua> ToLua<'lua> for &CStr {
|
||||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
Ok(Value::String(lua.create_string(self.to_bytes())?))
|
Ok(Value::String(lua.create_string(self.to_bytes())?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua, 'a> ToLua<'lua> for BString {
|
impl<'lua> ToLua<'lua> for Cow<'_, CStr> {
|
||||||
|
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
|
Ok(Value::String(lua.create_string(self.to_bytes())?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> ToLua<'lua> for BString {
|
||||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
Ok(Value::String(lua.create_string(&self)?))
|
Ok(Value::String(lua.create_string(&self)?))
|
||||||
}
|
}
|
||||||
@@ -278,7 +291,7 @@ impl<'lua> FromLua<'lua> for BString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua, 'a> ToLua<'lua> for &BStr {
|
impl<'lua> ToLua<'lua> for &BStr {
|
||||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
Ok(Value::String(lua.create_string(&self)?))
|
Ok(Value::String(lua.create_string(&self)?))
|
||||||
}
|
}
|
||||||
@@ -345,7 +358,13 @@ macro_rules! lua_convert_float {
|
|||||||
($x:ty) => {
|
($x:ty) => {
|
||||||
impl<'lua> ToLua<'lua> for $x {
|
impl<'lua> ToLua<'lua> for $x {
|
||||||
fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
|
fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
Ok(Value::Number(self as Number))
|
cast(self)
|
||||||
|
.ok_or_else(|| Error::ToLuaConversionError {
|
||||||
|
from: stringify!($x),
|
||||||
|
to: "number",
|
||||||
|
message: Some("out of range".to_string()),
|
||||||
|
})
|
||||||
|
.map(Value::Number)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,6 +392,50 @@ macro_rules! lua_convert_float {
|
|||||||
lua_convert_float!(f32);
|
lua_convert_float!(f32);
|
||||||
lua_convert_float!(f64);
|
lua_convert_float!(f64);
|
||||||
|
|
||||||
|
impl<'lua, T> ToLua<'lua> for &[T]
|
||||||
|
where
|
||||||
|
T: Clone + ToLua<'lua>,
|
||||||
|
{
|
||||||
|
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
|
Ok(Value::Table(
|
||||||
|
lua.create_sequence_from(self.iter().cloned())?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! lua_convert_array {
|
||||||
|
($($N:literal)+) => {
|
||||||
|
$(
|
||||||
|
impl<'lua, T> ToLua<'lua> for [T; $N]
|
||||||
|
where
|
||||||
|
T: Clone + ToLua<'lua>,
|
||||||
|
{
|
||||||
|
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
|
(&self).to_lua(lua)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua, T> ToLua<'lua> for &[T; $N]
|
||||||
|
where
|
||||||
|
T: Clone + ToLua<'lua>,
|
||||||
|
{
|
||||||
|
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
|
Ok(Value::Table(
|
||||||
|
lua.create_sequence_from(self.iter().cloned())?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_convert_array! {
|
||||||
|
0 1 2 3 4 5 6 7 8 9
|
||||||
|
10 11 12 13 14 15 16 17 18 19
|
||||||
|
20 21 22 23 24 25 26 27 28 29
|
||||||
|
30 31 32
|
||||||
|
}
|
||||||
|
|
||||||
impl<'lua, T: ToLua<'lua>> ToLua<'lua> for Vec<T> {
|
impl<'lua, T: ToLua<'lua>> ToLua<'lua> for Vec<T> {
|
||||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
Ok(Value::Table(lua.create_sequence_from(self)?))
|
Ok(Value::Table(lua.create_sequence_from(self)?))
|
||||||
@@ -437,6 +500,56 @@ impl<'lua, K: Ord + FromLua<'lua>, V: FromLua<'lua>> FromLua<'lua> for BTreeMap<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'lua, T: Eq + Hash + ToLua<'lua>, S: BuildHasher> ToLua<'lua> for HashSet<T, S> {
|
||||||
|
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
|
Ok(Value::Table(lua.create_table_from(
|
||||||
|
self.into_iter().map(|val| (val, true)),
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua, T: Eq + Hash + FromLua<'lua>, S: BuildHasher + Default> FromLua<'lua> for HashSet<T, S> {
|
||||||
|
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||||
|
if let Value::Table(table) = value {
|
||||||
|
table
|
||||||
|
.pairs::<T, Value<'lua>>()
|
||||||
|
.map(|res| res.map(|(k, _)| k))
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
Err(Error::FromLuaConversionError {
|
||||||
|
from: value.type_name(),
|
||||||
|
to: "HashSet",
|
||||||
|
message: Some("expected table".to_string()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua, T: Ord + ToLua<'lua>> ToLua<'lua> for BTreeSet<T> {
|
||||||
|
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
|
Ok(Value::Table(lua.create_table_from(
|
||||||
|
self.into_iter().map(|val| (val, true)),
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua, T: Ord + FromLua<'lua>> FromLua<'lua> for BTreeSet<T> {
|
||||||
|
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||||
|
if let Value::Table(table) = value {
|
||||||
|
table
|
||||||
|
.pairs::<T, Value<'lua>>()
|
||||||
|
.map(|res| res.map(|(k, _)| k))
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
Err(Error::FromLuaConversionError {
|
||||||
|
from: value.type_name(),
|
||||||
|
to: "BTreeSet",
|
||||||
|
message: Some("expected table".to_string()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'lua, T: ToLua<'lua>> ToLua<'lua> for Option<T> {
|
impl<'lua, T: ToLua<'lua>> ToLua<'lua> for Option<T> {
|
||||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
+102
-8
@@ -1,6 +1,9 @@
|
|||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::io::Error as IoError;
|
||||||
|
use std::net::AddrParseError;
|
||||||
use std::result::Result as StdResult;
|
use std::result::Result as StdResult;
|
||||||
|
use std::str::Utf8Error;
|
||||||
use std::string::String as StdString;
|
use std::string::String as StdString;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@@ -33,6 +36,18 @@ pub enum Error {
|
|||||||
/// The Lua VM returns this error when there is an error running a `__gc` metamethod.
|
/// The Lua VM returns this error when there is an error running a `__gc` metamethod.
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||||
GarbageCollectorError(StdString),
|
GarbageCollectorError(StdString),
|
||||||
|
/// Potentially unsafe action in safe mode.
|
||||||
|
SafetyError(StdString),
|
||||||
|
/// Setting memory limit is not available.
|
||||||
|
///
|
||||||
|
/// This error can only happen when Lua state was not created by us and does not have the
|
||||||
|
/// custom allocator attached.
|
||||||
|
MemoryLimitNotAvailable,
|
||||||
|
/// Main thread is not available.
|
||||||
|
///
|
||||||
|
/// This error can only happen in Lua5.1/LuaJIT module mode, when module loaded within a coroutine.
|
||||||
|
/// These Lua versions does not have `LUA_RIDX_MAINTHREAD` registry key.
|
||||||
|
MainThreadNotAvailable,
|
||||||
/// A mutable callback has triggered Lua code that has called the same mutable callback again.
|
/// A mutable callback has triggered Lua code that has called the same mutable callback again.
|
||||||
///
|
///
|
||||||
/// This is an error because a mutable callback can only be borrowed mutably once.
|
/// This is an error because a mutable callback can only be borrowed mutably once.
|
||||||
@@ -90,6 +105,13 @@ pub enum Error {
|
|||||||
/// [`AnyUserData`]: struct.AnyUserData.html
|
/// [`AnyUserData`]: struct.AnyUserData.html
|
||||||
/// [`UserDataMethods`]: trait.UserDataMethods.html
|
/// [`UserDataMethods`]: trait.UserDataMethods.html
|
||||||
UserDataTypeMismatch,
|
UserDataTypeMismatch,
|
||||||
|
/// An [`AnyUserData`] borrow failed because it has been destructed.
|
||||||
|
///
|
||||||
|
/// This error can happen either due to to being destructed in a previous __gc, or due to being
|
||||||
|
/// destructed from exiting a `Lua::scope` call.
|
||||||
|
///
|
||||||
|
/// [`AnyUserData`]: struct.AnyUserData.html
|
||||||
|
UserDataDestructed,
|
||||||
/// An [`AnyUserData`] immutable borrow failed because it is already borrowed mutably.
|
/// An [`AnyUserData`] immutable borrow failed because it is already borrowed mutably.
|
||||||
///
|
///
|
||||||
/// This error can occur when a method on a [`UserData`] type calls back into Lua, which then
|
/// This error can occur when a method on a [`UserData`] type calls back into Lua, which then
|
||||||
@@ -117,6 +139,14 @@ pub enum Error {
|
|||||||
/// Original error returned by the Rust code.
|
/// Original error returned by the Rust code.
|
||||||
cause: Arc<Error>,
|
cause: Arc<Error>,
|
||||||
},
|
},
|
||||||
|
/// Serialization error.
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
|
||||||
|
SerializeError(StdString),
|
||||||
|
/// Deserialization error.
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
|
||||||
|
DeserializeError(StdString),
|
||||||
/// A custom error.
|
/// A custom error.
|
||||||
///
|
///
|
||||||
/// This can be used for returning user-defined errors from callbacks.
|
/// This can be used for returning user-defined errors from callbacks.
|
||||||
@@ -124,7 +154,10 @@ pub enum Error {
|
|||||||
/// Returning `Err(ExternalError(...))` from a Rust callback will raise the error as a Lua
|
/// Returning `Err(ExternalError(...))` from a Rust callback will raise the error as a Lua
|
||||||
/// error. The Rust code that originally invoked the Lua code then receives a `CallbackError`,
|
/// error. The Rust code that originally invoked the Lua code then receives a `CallbackError`,
|
||||||
/// from which the original error (and a stack traceback) can be recovered.
|
/// from which the original error (and a stack traceback) can be recovered.
|
||||||
|
#[cfg(feature = "send")]
|
||||||
ExternalError(Arc<dyn StdError + Send + Sync>),
|
ExternalError(Arc<dyn StdError + Send + Sync>),
|
||||||
|
#[cfg(not(feature = "send"))]
|
||||||
|
ExternalError(Arc<dyn StdError>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A specialized `Result` type used by `mlua`'s API.
|
/// A specialized `Result` type used by `mlua`'s API.
|
||||||
@@ -142,6 +175,15 @@ impl fmt::Display for Error {
|
|||||||
Error::GarbageCollectorError(ref msg) => {
|
Error::GarbageCollectorError(ref msg) => {
|
||||||
write!(fmt, "garbage collector error: {}", msg)
|
write!(fmt, "garbage collector error: {}", msg)
|
||||||
}
|
}
|
||||||
|
Error::SafetyError(ref msg) => {
|
||||||
|
write!(fmt, "safety error: {}", msg)
|
||||||
|
},
|
||||||
|
Error::MemoryLimitNotAvailable => {
|
||||||
|
write!(fmt, "setting memory limit is not available")
|
||||||
|
}
|
||||||
|
Error::MainThreadNotAvailable => {
|
||||||
|
write!(fmt, "main thread is not available in Lua 5.1")
|
||||||
|
}
|
||||||
Error::RecursiveMutCallback => write!(fmt, "mutable callback called recursively"),
|
Error::RecursiveMutCallback => write!(fmt, "mutable callback called recursively"),
|
||||||
Error::CallbackDestructed => write!(
|
Error::CallbackDestructed => write!(
|
||||||
fmt,
|
fmt,
|
||||||
@@ -179,15 +221,24 @@ impl fmt::Display for Error {
|
|||||||
}
|
}
|
||||||
Error::CoroutineInactive => write!(fmt, "cannot resume inactive coroutine"),
|
Error::CoroutineInactive => write!(fmt, "cannot resume inactive coroutine"),
|
||||||
Error::UserDataTypeMismatch => write!(fmt, "userdata is not expected type"),
|
Error::UserDataTypeMismatch => write!(fmt, "userdata is not expected type"),
|
||||||
|
Error::UserDataDestructed => write!(fmt, "userdata has been destructed"),
|
||||||
Error::UserDataBorrowError => write!(fmt, "userdata already mutably borrowed"),
|
Error::UserDataBorrowError => write!(fmt, "userdata already mutably borrowed"),
|
||||||
Error::UserDataBorrowMutError => write!(fmt, "userdata already borrowed"),
|
Error::UserDataBorrowMutError => write!(fmt, "userdata already borrowed"),
|
||||||
Error::MismatchedRegistryKey => {
|
Error::MismatchedRegistryKey => {
|
||||||
write!(fmt, "RegistryKey used from different Lua state")
|
write!(fmt, "RegistryKey used from different Lua state")
|
||||||
}
|
}
|
||||||
Error::CallbackError { ref traceback, ref cause } => {
|
Error::CallbackError { ref traceback, .. } => {
|
||||||
write!(fmt, "callback error: {}: {}", cause, traceback)
|
write!(fmt, "callback error: {}", traceback)
|
||||||
}
|
}
|
||||||
Error::ExternalError(ref err) => write!(fmt, "external error: {}", err),
|
#[cfg(feature = "serialize")]
|
||||||
|
Error::SerializeError(ref err) => {
|
||||||
|
write!(fmt, "serialize error: {}", err)
|
||||||
|
},
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
Error::DeserializeError(ref err) => {
|
||||||
|
write!(fmt, "deserialize error: {}", err)
|
||||||
|
},
|
||||||
|
Error::ExternalError(ref err) => write!(fmt, "{}", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,26 +247,37 @@ impl StdError for Error {
|
|||||||
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
||||||
match *self {
|
match *self {
|
||||||
Error::CallbackError { ref cause, .. } => Some(cause.as_ref()),
|
Error::CallbackError { ref cause, .. } => Some(cause.as_ref()),
|
||||||
Error::ExternalError(ref err) => Some(err.as_ref()),
|
Error::ExternalError(ref err) => err.source(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
|
#[cfg(feature = "send")]
|
||||||
pub fn external<T: Into<Box<dyn StdError + Send + Sync>>>(err: T) -> Error {
|
pub fn external<T: Into<Box<dyn StdError + Send + Sync>>>(err: T) -> Error {
|
||||||
Error::ExternalError(err.into().into())
|
Error::ExternalError(err.into().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "send"))]
|
||||||
|
pub fn external<T: Into<Box<dyn StdError>>>(err: T) -> Error {
|
||||||
|
Error::ExternalError(err.into().into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ExternalError {
|
pub trait ExternalError {
|
||||||
fn to_lua_err(self) -> Error;
|
fn to_lua_err(self) -> Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> ExternalError for E
|
#[cfg(feature = "send")]
|
||||||
where
|
impl<E: Into<Box<dyn StdError + Send + Sync>>> ExternalError for E {
|
||||||
E: Into<Box<dyn StdError + Send + Sync>>,
|
fn to_lua_err(self) -> Error {
|
||||||
{
|
Error::external(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "send"))]
|
||||||
|
impl<E: Into<Box<dyn StdError>>> ExternalError for E {
|
||||||
fn to_lua_err(self) -> Error {
|
fn to_lua_err(self) -> Error {
|
||||||
Error::external(self)
|
Error::external(self)
|
||||||
}
|
}
|
||||||
@@ -233,3 +295,35 @@ where
|
|||||||
self.map_err(|e| e.to_lua_err())
|
self.map_err(|e| e.to_lua_err())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<AddrParseError> for Error {
|
||||||
|
fn from(err: AddrParseError) -> Self {
|
||||||
|
Error::external(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<IoError> for Error {
|
||||||
|
fn from(err: IoError) -> Self {
|
||||||
|
Error::external(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<Utf8Error> for Error {
|
||||||
|
fn from(err: Utf8Error) -> Self {
|
||||||
|
Error::external(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
impl serde::ser::Error for Error {
|
||||||
|
fn custom<T: fmt::Display>(msg: T) -> Self {
|
||||||
|
Self::SerializeError(msg.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
impl serde::de::Error for Error {
|
||||||
|
fn custom<T: fmt::Display>(msg: T) -> Self {
|
||||||
|
Self::DeserializeError(msg.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+43
-32
@@ -1,6 +1,6 @@
|
|||||||
// The MIT License (MIT)
|
// The MIT License (MIT)
|
||||||
//
|
//
|
||||||
// Copyright (c) 2019 A. Orlenko
|
// Copyright (c) 2019-2021 A. Orlenko
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
// Based on github.com/keplerproject/lua-compat-5.3
|
// Based on github.com/keplerproject/lua-compat-5.3
|
||||||
|
|
||||||
|
#![allow(clippy::needless_return)]
|
||||||
|
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::raw::{c_char, c_int, c_void};
|
use std::os::raw::{c_char, c_int, c_void};
|
||||||
@@ -42,18 +44,18 @@ use super::lua::{
|
|||||||
lua_createtable, lua_dump_old, lua_error, lua_getfield_old, lua_getstack, lua_gettable_old,
|
lua_createtable, lua_dump_old, lua_error, lua_getfield_old, lua_getstack, lua_gettable_old,
|
||||||
lua_gettop, lua_insert, lua_isstring, lua_istable, lua_newuserdata, lua_pop, lua_pushboolean,
|
lua_gettop, lua_insert, lua_isstring, lua_istable, lua_newuserdata, lua_pop, lua_pushboolean,
|
||||||
lua_pushcfunction, lua_pushfstring, lua_pushinteger, lua_pushliteral, lua_pushlstring_old,
|
lua_pushcfunction, lua_pushfstring, lua_pushinteger, lua_pushliteral, lua_pushlstring_old,
|
||||||
lua_pushnumber, lua_pushthread, lua_pushvalue, lua_rawget_old, lua_rawgeti_old, lua_rawset,
|
lua_pushnil, lua_pushnumber, lua_pushthread, lua_pushvalue, lua_rawget_old, lua_rawgeti_old,
|
||||||
lua_replace, lua_setfield, lua_setglobal, lua_setmetatable, lua_settable, lua_toboolean,
|
lua_rawset, lua_replace, lua_setfield, lua_setglobal, lua_setmetatable, lua_settable,
|
||||||
lua_tointeger, lua_tolstring, lua_tonumber, lua_topointer, lua_tostring, lua_touserdata,
|
lua_toboolean, lua_tointeger, lua_tolstring, lua_tonumber, lua_topointer, lua_tostring,
|
||||||
lua_type, lua_typename,
|
lua_touserdata, lua_type, lua_typename,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
use super::lua::{
|
use super::lua::{
|
||||||
lua_checkstack, lua_concat, lua_equal, lua_getfenv, lua_getinfo, lua_getmetatable,
|
lua_checkstack, lua_concat, lua_equal, lua_getfenv, lua_getinfo, lua_getmetatable,
|
||||||
lua_isnumber, lua_lessthan, lua_newtable, lua_next, lua_objlen, lua_pushcclosure,
|
lua_isnumber, lua_lessthan, lua_newtable, lua_next, lua_objlen, lua_pushcclosure,
|
||||||
lua_pushlightuserdata, lua_pushnil, lua_pushstring_old, lua_rawequal, lua_remove,
|
lua_pushlightuserdata, lua_pushstring_old, lua_rawequal, lua_remove, lua_resume_old,
|
||||||
lua_resume_old, lua_setfenv, lua_settop, LUA_OPADD, LUA_OPUNM,
|
lua_setfenv, lua_settop, LUA_OPADD, LUA_OPUNM,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "lua52")]
|
#[cfg(feature = "lua52")]
|
||||||
@@ -114,7 +116,7 @@ unsafe fn compat53_checkmode(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode != ptr::null() && strchr(mode, *modename) == ptr::null() {
|
if !mode.is_null() && strchr(mode, *modename).is_null() {
|
||||||
lua_pushfstring(
|
lua_pushfstring(
|
||||||
L,
|
L,
|
||||||
cstr!("attempt to load a %s chunk (mode is '%s')"),
|
cstr!("attempt to load a %s chunk (mode is '%s')"),
|
||||||
@@ -234,7 +236,7 @@ pub unsafe fn lua_absindex(L: *mut lua_State, mut idx: c_int) -> c_int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
static COMPAT53_ARITH_CODE: &'static str = r#"
|
static COMPAT53_ARITH_CODE: &str = r#"
|
||||||
local op,a,b=...
|
local op,a,b=...
|
||||||
if op == 0 then return a+b
|
if op == 0 then return a+b
|
||||||
elseif op == 1 then return a-b
|
elseif op == 1 then return a-b
|
||||||
@@ -287,7 +289,7 @@ pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
|
|||||||
if lua_type(L, idx) == lua::LUA_TNUMBER {
|
if lua_type(L, idx) == lua::LUA_TNUMBER {
|
||||||
let n = lua_tonumber(L, idx);
|
let n = lua_tonumber(L, idx);
|
||||||
let i = lua_tointeger(L, idx);
|
let i = lua_tointeger(L, idx);
|
||||||
if i as f64 == n {
|
if (n - i as lua_Number).abs() < lua_Number::EPSILON {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,7 +299,7 @@ pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
|
|||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
pub unsafe fn lua_tonumberx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Number {
|
pub unsafe fn lua_tonumberx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Number {
|
||||||
let n = lua_tonumber(L, i);
|
let n = lua_tonumber(L, i);
|
||||||
if isnum != ptr::null_mut() {
|
if !isnum.is_null() {
|
||||||
*isnum = if n != 0.0 || lua_isnumber(L, i) != 0 {
|
*isnum = if n != 0.0 || lua_isnumber(L, i) != 0 {
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
@@ -312,15 +314,14 @@ pub unsafe fn lua_tonumberx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> l
|
|||||||
pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
|
pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
|
||||||
let mut ok = 0;
|
let mut ok = 0;
|
||||||
let n = lua_tonumberx(L, i, &mut ok);
|
let n = lua_tonumberx(L, i, &mut ok);
|
||||||
if ok != 0 {
|
let n_int = n as lua_Integer;
|
||||||
if n == n as lua_Integer as lua_Number {
|
if ok != 0 && (n - n_int as lua_Number).abs() < lua_Number::EPSILON {
|
||||||
if isnum != ptr::null_mut() {
|
if !isnum.is_null() {
|
||||||
*isnum = 1;
|
*isnum = 1;
|
||||||
}
|
|
||||||
return n as lua_Integer;
|
|
||||||
}
|
}
|
||||||
|
return n_int;
|
||||||
}
|
}
|
||||||
if isnum != ptr::null_mut() {
|
if !isnum.is_null() {
|
||||||
*isnum = 0;
|
*isnum = 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -531,7 +532,7 @@ pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
|
|||||||
let is_main = lua_pushthread(L);
|
let is_main = lua_pushthread(L);
|
||||||
lua_rawget(L, -2);
|
lua_rawget(L, -2);
|
||||||
let mut _ptr = lua_touserdata(L, -1);
|
let mut _ptr = lua_touserdata(L, -1);
|
||||||
if _ptr == ptr::null_mut() {
|
if _ptr.is_null() {
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
_ptr = lua_newuserdata(L, LUA_EXTRASPACE as usize);
|
_ptr = lua_newuserdata(L, LUA_EXTRASPACE as usize);
|
||||||
if is_main != 0 {
|
if is_main != 0 {
|
||||||
@@ -547,7 +548,7 @@ pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
|
|||||||
lua_pushboolean(L, 1);
|
lua_pushboolean(L, 1);
|
||||||
lua_rawget(L, -3);
|
lua_rawget(L, -3);
|
||||||
let mptr = lua_touserdata(L, -1);
|
let mptr = lua_touserdata(L, -1);
|
||||||
if mptr != ptr::null_mut() {
|
if !mptr.is_null() {
|
||||||
ptr::copy_nonoverlapping(mptr, _ptr, LUA_EXTRASPACE as usize)
|
ptr::copy_nonoverlapping(mptr, _ptr, LUA_EXTRASPACE as usize)
|
||||||
} else {
|
} else {
|
||||||
ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE as usize);
|
ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE as usize);
|
||||||
@@ -575,7 +576,7 @@ pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
|
|||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char) {
|
pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char) {
|
||||||
if lua_checkstack(L, sz + lua::LUA_MINSTACK) == 0 {
|
if lua_checkstack(L, sz + lua::LUA_MINSTACK) == 0 {
|
||||||
if msg != ptr::null() {
|
if !msg.is_null() {
|
||||||
luaL_error(L, cstr!("stack overflow (%s)"), msg);
|
luaL_error(L, cstr!("stack overflow (%s)"), msg);
|
||||||
} else {
|
} else {
|
||||||
lua_pushliteral(L, "stack overflow");
|
lua_pushliteral(L, "stack overflow");
|
||||||
@@ -654,7 +655,7 @@ pub unsafe fn luaL_traceback(
|
|||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
if msg != ptr::null() {
|
if !msg.is_null() {
|
||||||
lua_pushfstring(L, cstr!("%s\n"), msg);
|
lua_pushfstring(L, cstr!("%s\n"), msg);
|
||||||
}
|
}
|
||||||
lua_pushliteral(L, "stack traceback:");
|
lua_pushliteral(L, "stack traceback:");
|
||||||
@@ -708,10 +709,8 @@ pub unsafe fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else if lua_isstring(L, -1) == 0 {
|
||||||
if lua_isstring(L, -1) == 0 {
|
luaL_error(L, cstr!("'__tostring' must return a string"));
|
||||||
luaL_error(L, cstr!("'__tostring' must return a string"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
lua_tolstring(L, -1, len)
|
lua_tolstring(L, -1, len)
|
||||||
}
|
}
|
||||||
@@ -727,7 +726,7 @@ pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) {
|
|||||||
pub unsafe fn luaL_testudata(L: *mut lua_State, i: c_int, tname: *const c_char) -> *mut c_void {
|
pub unsafe fn luaL_testudata(L: *mut lua_State, i: c_int, tname: *const c_char) -> *mut c_void {
|
||||||
let mut p = lua_touserdata(L, i);
|
let mut p = lua_touserdata(L, i);
|
||||||
luaL_checkstack(L, 2, cstr!("not enough stack slots"));
|
luaL_checkstack(L, 2, cstr!("not enough stack slots"));
|
||||||
if p == ptr::null_mut() || lua_getmetatable(L, i) == 0 {
|
if p.is_null() || lua_getmetatable(L, i) == 0 {
|
||||||
return ptr::null_mut();
|
return ptr::null_mut();
|
||||||
} else {
|
} else {
|
||||||
luaL_getmetatable(L, tname);
|
luaL_getmetatable(L, tname);
|
||||||
@@ -743,7 +742,7 @@ pub unsafe fn luaL_testudata(L: *mut lua_State, i: c_int, tname: *const c_char)
|
|||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
pub unsafe fn luaL_setfuncs(L: *mut lua_State, mut l: *const luaL_Reg, nup: c_int) {
|
pub unsafe fn luaL_setfuncs(L: *mut lua_State, mut l: *const luaL_Reg, nup: c_int) {
|
||||||
luaL_checkstack(L, nup + 1, cstr!("too many upvalues"));
|
luaL_checkstack(L, nup + 1, cstr!("too many upvalues"));
|
||||||
while (*l).name != ptr::null() {
|
while !(*l).name.is_null() {
|
||||||
// fill the table with given functions
|
// fill the table with given functions
|
||||||
l = l.offset(1);
|
l = l.offset(1);
|
||||||
lua_pushstring(L, (*l).name);
|
lua_pushstring(L, (*l).name);
|
||||||
@@ -786,13 +785,25 @@ pub unsafe fn luaL_requiref(
|
|||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
lua_pushcfunction(L, openf);
|
lua_pushcfunction(L, openf);
|
||||||
lua_pushstring(L, modname);
|
lua_pushstring(L, modname);
|
||||||
lua_call(L, 1, 1);
|
#[cfg(any(feature = "lua52", feature = "lua51"))]
|
||||||
lua_pushvalue(L, -1);
|
{
|
||||||
lua_setfield(L, -3, modname);
|
lua_call(L, 1, 1);
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
lua_setfield(L, -3, modname);
|
||||||
|
}
|
||||||
|
#[cfg(feature = "luajit")]
|
||||||
|
{
|
||||||
|
lua_call(L, 1, 0);
|
||||||
|
lua_getfield(L, -1, modname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if glb != 0 {
|
if cfg!(any(feature = "lua52", feature = "lua51")) && glb != 0 {
|
||||||
lua_pushvalue(L, -1);
|
lua_pushvalue(L, -1);
|
||||||
lua_setglobal(L, modname);
|
lua_setglobal(L, modname);
|
||||||
}
|
}
|
||||||
|
if cfg!(feature = "luajit") && glb == 0 {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_setglobal(L, modname);
|
||||||
|
}
|
||||||
lua_replace(L, -2);
|
lua_replace(L, -2);
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-12
@@ -1,6 +1,6 @@
|
|||||||
// The MIT License (MIT)
|
// The MIT License (MIT)
|
||||||
//
|
//
|
||||||
// Copyright (c) 2019 A. Orlenko
|
// Copyright (c) 2019-2021 A. Orlenko
|
||||||
// Copyright (c) 2014 J.C. Moyer
|
// Copyright (c) 2014 J.C. Moyer
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@@ -53,7 +53,7 @@ typedef struct rs_item {
|
|||||||
#define RS_INT(name, val) \
|
#define RS_INT(name, val) \
|
||||||
{ TY_INT, name, .int_val = val }
|
{ TY_INT, name, .int_val = val }
|
||||||
|
|
||||||
#if LUA_VERSION_NUM == 503
|
#if LUA_VERSION_NUM >= 503
|
||||||
#define TY_LUAINT 1
|
#define TY_LUAINT 1
|
||||||
#define RS_LUAINT(name, val) \
|
#define RS_LUAINT(name, val) \
|
||||||
{ TY_LUAINT, name, .lua_int_val = val }
|
{ TY_LUAINT, name, .lua_int_val = val }
|
||||||
@@ -84,6 +84,8 @@ const char *rs_int_type(int width) {
|
|||||||
return "i32";
|
return "i32";
|
||||||
case 8:
|
case 8:
|
||||||
return "i64";
|
return "i64";
|
||||||
|
case 16:
|
||||||
|
return "i128";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,6 +98,8 @@ const char *rs_uint_type(int width) {
|
|||||||
return "u32";
|
return "u32";
|
||||||
case 8:
|
case 8:
|
||||||
return "u64";
|
return "u64";
|
||||||
|
case 16:
|
||||||
|
return "u128";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +143,7 @@ int write_int_item(FILE *f, const char *name, int value) {
|
|||||||
return fprintf(f, "pub const %s: c_int = %d;\n", name, value);
|
return fprintf(f, "pub const %s: c_int = %d;\n", name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LUA_VERSION_NUM == 503
|
#if LUA_VERSION_NUM >= 503
|
||||||
int write_lua_int_item(FILE *f, const char *name, LUA_INTEGER value) {
|
int write_lua_int_item(FILE *f, const char *name, LUA_INTEGER value) {
|
||||||
return fprintf(f, "pub const %s: LUA_INTEGER = " LUA_INTEGER_FMT ";\n", name,
|
return fprintf(f, "pub const %s: LUA_INTEGER = " LUA_INTEGER_FMT ";\n", name,
|
||||||
value);
|
value);
|
||||||
@@ -152,7 +156,7 @@ int write_str_item(FILE *f, const char *name, const char *value) {
|
|||||||
char *buf = malloc(bufsz);
|
char *buf = malloc(bufsz);
|
||||||
int ret;
|
int ret;
|
||||||
escape(value, buf, bufsz);
|
escape(value, buf, bufsz);
|
||||||
ret = fprintf(f, "pub const %s: &'static str = \"%s\";\n", name, buf);
|
ret = fprintf(f, "pub const %s: &str = \"%s\";\n", name, buf);
|
||||||
free(buf);
|
free(buf);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -171,7 +175,7 @@ int write_item(FILE *f, const rs_item *c) {
|
|||||||
switch (c->type) {
|
switch (c->type) {
|
||||||
case TY_INT:
|
case TY_INT:
|
||||||
return write_int_item(f, c->name, c->int_val);
|
return write_int_item(f, c->name, c->int_val);
|
||||||
#if LUA_VERSION_NUM == 503
|
#if LUA_VERSION_NUM >= 503
|
||||||
case TY_LUAINT:
|
case TY_LUAINT:
|
||||||
return write_lua_int_item(f, c->name, c->lua_int_val);
|
return write_lua_int_item(f, c->name, c->lua_int_val);
|
||||||
#endif
|
#endif
|
||||||
@@ -221,12 +225,8 @@ int main(int argc, const char **argv) {
|
|||||||
// == luaconf.h ==========================================================
|
// == luaconf.h ==========================================================
|
||||||
|
|
||||||
RS_COMMENT("luaconf.h"),
|
RS_COMMENT("luaconf.h"),
|
||||||
RS_STR("LUA_PATH_DEFAULT", LUA_PATH_DEFAULT),
|
|
||||||
RS_STR("LUA_CPATH_DEFAULT", LUA_CPATH_DEFAULT),
|
|
||||||
RS_STR("LUA_DIRSEP", LUA_DIRSEP),
|
|
||||||
RS_INT("LUA_EXTRASPACE", LUA_EXTRASPACE),
|
RS_INT("LUA_EXTRASPACE", LUA_EXTRASPACE),
|
||||||
RS_INT("LUA_IDSIZE", LUA_IDSIZE),
|
RS_INT("LUA_IDSIZE", LUA_IDSIZE),
|
||||||
RS_INT("LUAL_BUFFERSIZE", LUAL_BUFFERSIZE),
|
|
||||||
RS_TYPE("LUA_NUMBER",
|
RS_TYPE("LUA_NUMBER",
|
||||||
sizeof(LUA_NUMBER) > sizeof(float) ? "c_double" : "c_float"),
|
sizeof(LUA_NUMBER) > sizeof(float) ? "c_double" : "c_float"),
|
||||||
RS_TYPE("LUA_INTEGER", rs_int_type(sizeof(LUA_INTEGER))),
|
RS_TYPE("LUA_INTEGER", rs_int_type(sizeof(LUA_INTEGER))),
|
||||||
@@ -240,8 +240,6 @@ int main(int argc, const char **argv) {
|
|||||||
|
|
||||||
RS_COMMENT("lua.h"),
|
RS_COMMENT("lua.h"),
|
||||||
RS_INT("LUA_VERSION_NUM", LUA_VERSION_NUM),
|
RS_INT("LUA_VERSION_NUM", LUA_VERSION_NUM),
|
||||||
RS_STR("LUA_VERSION", LUA_VERSION),
|
|
||||||
RS_STR("LUA_RELEASE", LUA_RELEASE),
|
|
||||||
RS_INT("LUA_REGISTRYINDEX", LUA_REGISTRYINDEX),
|
RS_INT("LUA_REGISTRYINDEX", LUA_REGISTRYINDEX),
|
||||||
#if LUA_VERSION_NUM == 501
|
#if LUA_VERSION_NUM == 501
|
||||||
RS_INT("LUA_ENVIRONINDEX", LUA_ENVIRONINDEX),
|
RS_INT("LUA_ENVIRONINDEX", LUA_ENVIRONINDEX),
|
||||||
@@ -251,7 +249,7 @@ int main(int argc, const char **argv) {
|
|||||||
// == lauxlib.h ==========================================================
|
// == lauxlib.h ==========================================================
|
||||||
|
|
||||||
RS_COMMENT("lauxlib.h"),
|
RS_COMMENT("lauxlib.h"),
|
||||||
#if LUA_VERSION_NUM == 503
|
#if LUA_VERSION_NUM >= 503
|
||||||
RS_INT("LUAL_NUMSIZES", LUAL_NUMSIZES),
|
RS_INT("LUAL_NUMSIZES", LUAL_NUMSIZES),
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+25
-23
@@ -1,6 +1,6 @@
|
|||||||
// The MIT License (MIT)
|
// The MIT License (MIT)
|
||||||
//
|
//
|
||||||
// Copyright (c) 2019 A. Orlenko
|
// Copyright (c) 2019-2021 A. Orlenko
|
||||||
// Copyright (c) 2014 J.C. Moyer
|
// Copyright (c) 2014 J.C. Moyer
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@@ -28,7 +28,7 @@ use std::ptr;
|
|||||||
|
|
||||||
use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State};
|
use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State};
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub use super::glue::LUAL_NUMSIZES;
|
pub use super::glue::LUAL_NUMSIZES;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
@@ -49,10 +49,10 @@ pub struct luaL_Reg {
|
|||||||
pub func: lua_CFunction,
|
pub func: lua_CFunction,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn luaL_checkversion(L: *mut lua_State) {
|
pub unsafe fn luaL_checkversion(L: *mut lua_State) {
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
luaL_checkversion_(
|
luaL_checkversion_(
|
||||||
L,
|
L,
|
||||||
lua::LUA_VERSION_NUM as lua_Number,
|
lua::LUA_VERSION_NUM as lua_Number,
|
||||||
@@ -63,19 +63,19 @@ pub unsafe fn luaL_checkversion(L: *mut lua_State) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number, sz: usize);
|
pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number, sz: usize);
|
||||||
#[cfg(feature = "lua52")]
|
#[cfg(feature = "lua52")]
|
||||||
pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number);
|
pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number);
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
|
pub fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
#[link_name = "luaL_getmetafield"]
|
#[link_name = "luaL_getmetafield"]
|
||||||
pub fn luaL_getmetafield_old(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
|
pub fn luaL_getmetafield_old(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
|
||||||
|
|
||||||
pub fn luaL_callmeta(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
|
pub fn luaL_callmeta(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char;
|
pub fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char;
|
||||||
pub fn luaL_argerror(L: *mut lua_State, arg: c_int, l: *const c_char) -> c_int;
|
pub fn luaL_argerror(L: *mut lua_State, arg: c_int, l: *const c_char) -> c_int;
|
||||||
pub fn luaL_checklstring(L: *mut lua_State, arg: c_int, l: *mut usize) -> *const c_char;
|
pub fn luaL_checklstring(L: *mut lua_State, arg: c_int, l: *mut usize) -> *const c_char;
|
||||||
@@ -90,20 +90,20 @@ extern "C" {
|
|||||||
pub fn luaL_checkinteger(L: *mut lua_State, arg: c_int) -> lua_Integer;
|
pub fn luaL_checkinteger(L: *mut lua_State, arg: c_int) -> lua_Integer;
|
||||||
pub fn luaL_optinteger(L: *mut lua_State, arg: c_int, def: lua_Integer) -> lua_Integer;
|
pub fn luaL_optinteger(L: *mut lua_State, arg: c_int, def: lua_Integer) -> lua_Integer;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char);
|
pub fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char);
|
||||||
pub fn luaL_checktype(L: *mut lua_State, arg: c_int, t: c_int);
|
pub fn luaL_checktype(L: *mut lua_State, arg: c_int, t: c_int);
|
||||||
pub fn luaL_checkany(L: *mut lua_State, arg: c_int);
|
pub fn luaL_checkany(L: *mut lua_State, arg: c_int);
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int;
|
pub fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int;
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
#[link_name = "luaL_newmetatable"]
|
#[link_name = "luaL_newmetatable"]
|
||||||
pub fn luaL_newmetatable_old(L: *mut lua_State, tname: *const c_char) -> c_int;
|
pub fn luaL_newmetatable_old(L: *mut lua_State, tname: *const c_char) -> c_int;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char);
|
pub fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char);
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn luaL_testudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;
|
pub fn luaL_testudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;
|
||||||
pub fn luaL_checkudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;
|
pub fn luaL_checkudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;
|
||||||
|
|
||||||
@@ -118,9 +118,9 @@ extern "C" {
|
|||||||
lst: *const *const c_char,
|
lst: *const *const c_char,
|
||||||
) -> c_int;
|
) -> c_int;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn luaL_fileresult(L: *mut lua_State, stat: c_int, fname: *const c_char) -> c_int;
|
pub fn luaL_fileresult(L: *mut lua_State, stat: c_int, fname: *const c_char) -> c_int;
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn luaL_execresult(L: *mut lua_State, stat: c_int) -> c_int;
|
pub fn luaL_execresult(L: *mut lua_State, stat: c_int) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,21 +132,21 @@ extern "C" {
|
|||||||
pub fn luaL_ref(L: *mut lua_State, t: c_int) -> c_int;
|
pub fn luaL_ref(L: *mut lua_State, t: c_int) -> c_int;
|
||||||
pub fn luaL_unref(L: *mut lua_State, t: c_int, r: c_int);
|
pub fn luaL_unref(L: *mut lua_State, t: c_int, r: c_int);
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn luaL_loadfilex(L: *mut lua_State, filename: *const c_char, mode: *const c_char)
|
pub fn luaL_loadfilex(L: *mut lua_State, filename: *const c_char, mode: *const c_char)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
pub fn luaL_loadfile(L: *mut lua_State, filename: *const c_char) -> c_int;
|
pub fn luaL_loadfile(L: *mut lua_State, filename: *const c_char) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
|
pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
|
||||||
luaL_loadfilex(L, f, ptr::null())
|
luaL_loadfilex(L, f, ptr::null())
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn luaL_loadbufferx(
|
pub fn luaL_loadbufferx(
|
||||||
L: *mut lua_State,
|
L: *mut lua_State,
|
||||||
buff: *const c_char,
|
buff: *const c_char,
|
||||||
@@ -165,9 +165,11 @@ extern "C" {
|
|||||||
|
|
||||||
pub fn luaL_newstate() -> *mut lua_State;
|
pub fn luaL_newstate() -> *mut lua_State;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer;
|
pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer;
|
||||||
|
|
||||||
|
// TODO (lua54): luaL_addgsub
|
||||||
|
|
||||||
pub fn luaL_gsub(
|
pub fn luaL_gsub(
|
||||||
L: *mut lua_State,
|
L: *mut lua_State,
|
||||||
s: *const c_char,
|
s: *const c_char,
|
||||||
@@ -175,17 +177,17 @@ extern "C" {
|
|||||||
r: *const c_char,
|
r: *const c_char,
|
||||||
) -> *const c_char;
|
) -> *const c_char;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn luaL_setfuncs(L: *mut lua_State, l: *const luaL_Reg, nup: c_int);
|
pub fn luaL_setfuncs(L: *mut lua_State, l: *const luaL_Reg, nup: c_int);
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int;
|
pub fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, level: c_int);
|
pub fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, level: c_int);
|
||||||
|
|
||||||
// Skip Lua 5.2 implementation in favor of the compat53 one
|
// Skip Lua 5.2 implementation in favor of the compat53 one
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn luaL_requiref(
|
pub fn luaL_requiref(
|
||||||
L: *mut lua_State,
|
L: *mut lua_State,
|
||||||
modname: *const c_char,
|
modname: *const c_char,
|
||||||
@@ -288,7 +290,7 @@ pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
|
|||||||
|
|
||||||
// luaL_opt would be implemented here but it is undocumented, so it's omitted
|
// luaL_opt would be implemented here but it is undocumented, so it's omitted
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn luaL_loadbuffer(
|
pub unsafe fn luaL_loadbuffer(
|
||||||
L: *mut lua_State,
|
L: *mut lua_State,
|
||||||
@@ -301,4 +303,4 @@ pub unsafe fn luaL_loadbuffer(
|
|||||||
|
|
||||||
// TODO: Add buffer API
|
// TODO: Add buffer API
|
||||||
|
|
||||||
// omitted: old module system compatibility
|
// omitted: old module system compatibility (removed in 5.4)
|
||||||
|
|||||||
+173
-71
@@ -1,6 +1,6 @@
|
|||||||
// The MIT License (MIT)
|
// The MIT License (MIT)
|
||||||
//
|
//
|
||||||
// Copyright (c) 2019 A. Orlenko
|
// Copyright (c) 2019-2021 A. Orlenko
|
||||||
// Copyright (c) 2014 J.C. Moyer
|
// Copyright (c) 2014 J.C. Moyer
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@@ -23,20 +23,23 @@
|
|||||||
|
|
||||||
//! Contains definitions from `lua.h`.
|
//! Contains definitions from `lua.h`.
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
use std::os::raw::c_uchar;
|
use std::os::raw::c_uchar;
|
||||||
use std::os::raw::{c_char, c_int, c_void};
|
use std::os::raw::{c_char, c_int, c_void};
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
use std::os::raw::{c_uint, c_ushort};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use super::luaconf;
|
use super::luaconf;
|
||||||
|
|
||||||
pub use super::glue::{LUA_RELEASE, LUA_VERSION, LUA_VERSION_NUM};
|
|
||||||
|
|
||||||
pub use super::glue::LUA_REGISTRYINDEX;
|
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
pub use super::glue::{LUA_ENVIRONINDEX, LUA_GLOBALSINDEX};
|
pub use super::glue::{LUA_ENVIRONINDEX, LUA_GLOBALSINDEX};
|
||||||
|
pub use super::glue::{LUA_REGISTRYINDEX, LUA_VERSION_NUM};
|
||||||
|
|
||||||
pub const LUA_SIGNATURE: &'static [u8] = b"\x1bLua";
|
#[cfg(not(feature = "luajit"))]
|
||||||
|
pub const LUA_SIGNATURE: &[u8] = b"\x1bLua";
|
||||||
|
#[cfg(feature = "luajit")]
|
||||||
|
pub const LUA_SIGNATURE: &[u8] = b"\x1bLJ";
|
||||||
|
|
||||||
// option for multiple returns in 'lua_pcall' and 'lua_call'
|
// option for multiple returns in 'lua_pcall' and 'lua_call'
|
||||||
pub const LUA_MULTRET: c_int = -1;
|
pub const LUA_MULTRET: c_int = -1;
|
||||||
@@ -51,13 +54,14 @@ pub use super::compat53::{
|
|||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
pub use super::compat53::{
|
pub use super::compat53::{
|
||||||
lua_absindex, lua_arith, lua_compare, lua_copy, lua_len, lua_pushglobaltable, lua_pushstring,
|
lua_absindex, lua_arith, lua_compare, lua_copy, lua_len, lua_pushglobaltable, lua_pushstring,
|
||||||
lua_rawlen, lua_rawsetp, lua_resume, lua_setuservalue, lua_tonumberx, lua_upvalueindex,
|
lua_rawlen, lua_rawsetp, lua_resume as lua_resume_53, lua_setuservalue, lua_tonumberx,
|
||||||
|
lua_upvalueindex,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "lua52")]
|
#[cfg(feature = "lua52")]
|
||||||
pub use super::compat53::lua_getglobal;
|
pub use super::compat53::lua_getglobal;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn lua_upvalueindex(i: c_int) -> c_int {
|
pub fn lua_upvalueindex(i: c_int) -> c_int {
|
||||||
LUA_REGISTRYINDEX - i
|
LUA_REGISTRYINDEX - i
|
||||||
@@ -71,7 +75,7 @@ pub const LUA_ERRSYNTAX: c_int = 3;
|
|||||||
pub const LUA_ERRMEM: c_int = 4;
|
pub const LUA_ERRMEM: c_int = 4;
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||||
pub const LUA_ERRGCMM: c_int = 5;
|
pub const LUA_ERRGCMM: c_int = 5;
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua54", feature = "lua51", feature = "luajit"))]
|
||||||
pub const LUA_ERRERR: c_int = 5;
|
pub const LUA_ERRERR: c_int = 5;
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||||
pub const LUA_ERRERR: c_int = 6;
|
pub const LUA_ERRERR: c_int = 6;
|
||||||
@@ -91,6 +95,8 @@ pub const LUA_TFUNCTION: c_int = 6;
|
|||||||
pub const LUA_TUSERDATA: c_int = 7;
|
pub const LUA_TUSERDATA: c_int = 7;
|
||||||
pub const LUA_TTHREAD: c_int = 8;
|
pub const LUA_TTHREAD: c_int = 8;
|
||||||
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub const LUA_NUMTYPES: c_int = 9;
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||||
pub const LUA_NUMTAGS: c_int = 9;
|
pub const LUA_NUMTAGS: c_int = 9;
|
||||||
|
|
||||||
@@ -98,11 +104,11 @@ pub const LUA_NUMTAGS: c_int = 9;
|
|||||||
pub const LUA_MINSTACK: c_int = 20;
|
pub const LUA_MINSTACK: c_int = 20;
|
||||||
|
|
||||||
// predefined values in the registry
|
// predefined values in the registry
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub const LUA_RIDX_MAINTHREAD: lua_Integer = 1;
|
pub const LUA_RIDX_MAINTHREAD: lua_Integer = 1;
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub const LUA_RIDX_GLOBALS: lua_Integer = 2;
|
pub const LUA_RIDX_GLOBALS: lua_Integer = 2;
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub const LUA_RIDX_LAST: lua_Integer = LUA_RIDX_GLOBALS;
|
pub const LUA_RIDX_LAST: lua_Integer = LUA_RIDX_GLOBALS;
|
||||||
|
|
||||||
/// A Lua number, usually equivalent to `f64`.
|
/// A Lua number, usually equivalent to `f64`.
|
||||||
@@ -115,14 +121,14 @@ pub type lua_Integer = luaconf::LUA_INTEGER;
|
|||||||
pub type lua_Unsigned = luaconf::LUA_UNSIGNED;
|
pub type lua_Unsigned = luaconf::LUA_UNSIGNED;
|
||||||
|
|
||||||
// type for continuation-function contexts
|
// type for continuation-function contexts
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub type lua_KContext = luaconf::LUA_KCONTEXT;
|
pub type lua_KContext = luaconf::LUA_KCONTEXT;
|
||||||
|
|
||||||
/// Type for native functions that can be passed to Lua.
|
/// Type for native functions that can be passed to Lua.
|
||||||
pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int;
|
pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int;
|
||||||
|
|
||||||
// Type for continuation functions
|
// Type for continuation functions
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub type lua_KFunction =
|
pub type lua_KFunction =
|
||||||
unsafe extern "C" fn(L: *mut lua_State, status: c_int, ctx: lua_KContext) -> c_int;
|
unsafe extern "C" fn(L: *mut lua_State, status: c_int, ctx: lua_KContext) -> c_int;
|
||||||
|
|
||||||
@@ -132,7 +138,7 @@ pub type lua_Reader =
|
|||||||
pub type lua_Writer =
|
pub type lua_Writer =
|
||||||
unsafe extern "C" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int;
|
unsafe extern "C" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int;
|
||||||
|
|
||||||
/// Type for memory-allocation functions.
|
// Type for memory-allocation functions.
|
||||||
pub type lua_Alloc = unsafe extern "C" fn(
|
pub type lua_Alloc = unsafe extern "C" fn(
|
||||||
ud: *mut c_void,
|
ud: *mut c_void,
|
||||||
ptr: *mut c_void,
|
ptr: *mut c_void,
|
||||||
@@ -140,19 +146,28 @@ pub type lua_Alloc = unsafe extern "C" fn(
|
|||||||
nsize: usize,
|
nsize: usize,
|
||||||
) -> *mut c_void;
|
) -> *mut c_void;
|
||||||
|
|
||||||
|
// Type for warning functions
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub type lua_WarnFunction =
|
||||||
|
unsafe extern "C" fn(ud: *mut c_void, msg: *const c_char, tocont: c_int);
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
// state manipulation
|
// state manipulation
|
||||||
pub fn lua_newstate(f: lua_Alloc, ud: *mut c_void) -> *mut lua_State;
|
pub fn lua_newstate(f: lua_Alloc, ud: *mut c_void) -> *mut lua_State;
|
||||||
pub fn lua_close(L: *mut lua_State);
|
pub fn lua_close(L: *mut lua_State);
|
||||||
pub fn lua_newthread(L: *mut lua_State) -> *mut lua_State;
|
pub fn lua_newthread(L: *mut lua_State) -> *mut lua_State;
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub fn lua_resetthread(L: *mut lua_State) -> c_int;
|
||||||
|
|
||||||
pub fn lua_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction;
|
pub fn lua_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction;
|
||||||
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub fn lua_version(L: *mut lua_State) -> lua_Number;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(feature = "lua53")]
|
||||||
pub fn lua_version(L: *mut lua_State) -> *const lua_Number;
|
pub fn lua_version(L: *mut lua_State) -> *const lua_Number;
|
||||||
|
|
||||||
// basic stack manipulation
|
// basic stack manipulation
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn lua_absindex(L: *mut lua_State, idx: c_int) -> c_int;
|
pub fn lua_absindex(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
pub fn lua_gettop(L: *mut lua_State) -> c_int;
|
pub fn lua_gettop(L: *mut lua_State) -> c_int;
|
||||||
pub fn lua_settop(L: *mut lua_State, idx: c_int);
|
pub fn lua_settop(L: *mut lua_State, idx: c_int);
|
||||||
@@ -163,9 +178,9 @@ extern "C" {
|
|||||||
pub fn lua_insert(L: *mut lua_State, idx: c_int);
|
pub fn lua_insert(L: *mut lua_State, idx: c_int);
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
pub fn lua_replace(L: *mut lua_State, idx: c_int);
|
pub fn lua_replace(L: *mut lua_State, idx: c_int);
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_rotate(L: *mut lua_State, idx: c_int, n: c_int);
|
pub fn lua_rotate(L: *mut lua_State, idx: c_int, n: c_int);
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int);
|
pub fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int);
|
||||||
pub fn lua_checkstack(L: *mut lua_State, sz: c_int) -> c_int;
|
pub fn lua_checkstack(L: *mut lua_State, sz: c_int) -> c_int;
|
||||||
|
|
||||||
@@ -175,7 +190,7 @@ extern "C" {
|
|||||||
pub fn lua_isnumber(L: *mut lua_State, idx: c_int) -> c_int;
|
pub fn lua_isnumber(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
pub fn lua_isstring(L: *mut lua_State, idx: c_int) -> c_int;
|
pub fn lua_isstring(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
pub fn lua_iscfunction(L: *mut lua_State, idx: c_int) -> c_int;
|
pub fn lua_iscfunction(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int;
|
pub fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
pub fn lua_isuserdata(L: *mut lua_State, idx: c_int) -> c_int;
|
pub fn lua_isuserdata(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
pub fn lua_type(L: *mut lua_State, idx: c_int) -> c_int;
|
pub fn lua_type(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
@@ -183,17 +198,17 @@ extern "C" {
|
|||||||
|
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
pub fn lua_tonumber(L: *mut lua_State, idx: c_int) -> lua_Number;
|
pub fn lua_tonumber(L: *mut lua_State, idx: c_int) -> lua_Number;
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn lua_tonumberx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Number;
|
pub fn lua_tonumberx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Number;
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
pub fn lua_tointeger(L: *mut lua_State, idx: c_int) -> lua_Integer;
|
pub fn lua_tointeger(L: *mut lua_State, idx: c_int) -> lua_Integer;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_tointegerx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Integer;
|
pub fn lua_tointegerx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Integer;
|
||||||
pub fn lua_toboolean(L: *mut lua_State, idx: c_int) -> c_int;
|
pub fn lua_toboolean(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
pub fn lua_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char;
|
pub fn lua_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char;
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
pub fn lua_objlen(L: *mut lua_State, idx: c_int) -> usize;
|
pub fn lua_objlen(L: *mut lua_State, idx: c_int) -> usize;
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize;
|
pub fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize;
|
||||||
pub fn lua_tocfunction(L: *mut lua_State, idx: c_int) -> lua_CFunction;
|
pub fn lua_tocfunction(L: *mut lua_State, idx: c_int) -> lua_CFunction;
|
||||||
pub fn lua_touserdata(L: *mut lua_State, idx: c_int) -> *mut c_void;
|
pub fn lua_touserdata(L: *mut lua_State, idx: c_int) -> *mut c_void;
|
||||||
@@ -215,31 +230,31 @@ pub const LUA_OPPOW: c_int = 5;
|
|||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
pub const LUA_OPUNM: c_int = 6;
|
pub const LUA_OPUNM: c_int = 6;
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub const LUA_OPMOD: c_int = 3;
|
pub const LUA_OPMOD: c_int = 3;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub const LUA_OPPOW: c_int = 4;
|
pub const LUA_OPPOW: c_int = 4;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub const LUA_OPDIV: c_int = 5;
|
pub const LUA_OPDIV: c_int = 5;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub const LUA_OPIDIV: c_int = 6;
|
pub const LUA_OPIDIV: c_int = 6;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub const LUA_OPBAND: c_int = 7;
|
pub const LUA_OPBAND: c_int = 7;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub const LUA_OPBOR: c_int = 8;
|
pub const LUA_OPBOR: c_int = 8;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub const LUA_OPBXOR: c_int = 9;
|
pub const LUA_OPBXOR: c_int = 9;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub const LUA_OPSHL: c_int = 10;
|
pub const LUA_OPSHL: c_int = 10;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub const LUA_OPSHR: c_int = 11;
|
pub const LUA_OPSHR: c_int = 11;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub const LUA_OPUNM: c_int = 12;
|
pub const LUA_OPUNM: c_int = 12;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub const LUA_OPBNOT: c_int = 13;
|
pub const LUA_OPBNOT: c_int = 13;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn lua_arith(L: *mut lua_State, op: c_int);
|
pub fn lua_arith(L: *mut lua_State, op: c_int);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +268,7 @@ extern "C" {
|
|||||||
pub fn lua_rawequal(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
pub fn lua_rawequal(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
pub fn lua_lessthan(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
pub fn lua_lessthan(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn lua_compare(L: *mut lua_State, idx1: c_int, idx2: c_int, op: c_int) -> c_int;
|
pub fn lua_compare(L: *mut lua_State, idx1: c_int, idx2: c_int, op: c_int) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,13 +278,13 @@ extern "C" {
|
|||||||
pub fn lua_pushnumber(L: *mut lua_State, n: lua_Number);
|
pub fn lua_pushnumber(L: *mut lua_State, n: lua_Number);
|
||||||
pub fn lua_pushinteger(L: *mut lua_State, n: lua_Integer);
|
pub fn lua_pushinteger(L: *mut lua_State, n: lua_Integer);
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char;
|
pub fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char;
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
#[link_name = "lua_pushlstring"]
|
#[link_name = "lua_pushlstring"]
|
||||||
pub fn lua_pushlstring_old(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char;
|
pub fn lua_pushlstring_old(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char;
|
pub fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char;
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
#[link_name = "lua_pushstring"]
|
#[link_name = "lua_pushstring"]
|
||||||
@@ -286,49 +301,59 @@ extern "C" {
|
|||||||
|
|
||||||
// get functions (Lua -> stack)
|
// get functions (Lua -> stack)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int;
|
pub fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int;
|
||||||
#[cfg(feature = "lua52")]
|
#[cfg(feature = "lua52")]
|
||||||
#[link_name = "lua_getglobal"]
|
#[link_name = "lua_getglobal"]
|
||||||
pub fn lua_getglobal_old(L: *mut lua_State, var: *const c_char);
|
pub fn lua_getglobal_old(L: *mut lua_State, var: *const c_char);
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int;
|
pub fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
#[link_name = "lua_gettable"]
|
#[link_name = "lua_gettable"]
|
||||||
pub fn lua_gettable_old(L: *mut lua_State, idx: c_int);
|
pub fn lua_gettable_old(L: *mut lua_State, idx: c_int);
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int;
|
pub fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int;
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
#[link_name = "lua_getfield"]
|
#[link_name = "lua_getfield"]
|
||||||
pub fn lua_getfield_old(L: *mut lua_State, idx: c_int, k: *const c_char);
|
pub fn lua_getfield_old(L: *mut lua_State, idx: c_int, k: *const c_char);
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_geti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int;
|
pub fn lua_geti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int;
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int;
|
pub fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
#[link_name = "lua_rawget"]
|
#[link_name = "lua_rawget"]
|
||||||
pub fn lua_rawget_old(L: *mut lua_State, idx: c_int);
|
pub fn lua_rawget_old(L: *mut lua_State, idx: c_int);
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int;
|
pub fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int;
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
#[link_name = "lua_rawgeti"]
|
#[link_name = "lua_rawgeti"]
|
||||||
pub fn lua_rawgeti_old(L: *mut lua_State, idx: c_int, n: lua_Integer);
|
pub fn lua_rawgeti_old(L: *mut lua_State, idx: c_int, n: lua_Integer);
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int;
|
pub fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int;
|
||||||
#[cfg(feature = "lua52")]
|
#[cfg(feature = "lua52")]
|
||||||
#[link_name = "lua_rawgetp"]
|
#[link_name = "lua_rawgetp"]
|
||||||
pub fn lua_rawgetp_old(L: *mut lua_State, idx: c_int, p: *const c_void);
|
pub fn lua_rawgetp_old(L: *mut lua_State, idx: c_int, p: *const c_void);
|
||||||
|
|
||||||
pub fn lua_createtable(L: *mut lua_State, narr: c_int, nrec: c_int);
|
pub fn lua_createtable(L: *mut lua_State, narr: c_int, nrec: c_int);
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub fn lua_newuserdatauv(L: *mut lua_State, sz: usize, nuvalue: c_int) -> *mut c_void;
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "lua53",
|
||||||
|
feature = "lua52",
|
||||||
|
feature = "lua51",
|
||||||
|
feature = "luajit"
|
||||||
|
))]
|
||||||
pub fn lua_newuserdata(L: *mut lua_State, sz: usize) -> *mut c_void;
|
pub fn lua_newuserdata(L: *mut lua_State, sz: usize) -> *mut c_void;
|
||||||
pub fn lua_getmetatable(L: *mut lua_State, objindex: c_int) -> c_int;
|
pub fn lua_getmetatable(L: *mut lua_State, objindex: c_int) -> c_int;
|
||||||
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub fn lua_getiuservalue(L: *mut lua_State, idx: c_int, n: c_int) -> c_int;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(feature = "lua53")]
|
||||||
pub fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int;
|
pub fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
#[cfg(feature = "lua52")]
|
#[cfg(feature = "lua52")]
|
||||||
@@ -338,28 +363,48 @@ extern "C" {
|
|||||||
pub fn lua_getfenv(L: *mut lua_State, idx: c_int);
|
pub fn lua_getfenv(L: *mut lua_State, idx: c_int);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn lua_newuserdata(L: *mut lua_State, sz: usize) -> *mut c_void {
|
||||||
|
lua_newuserdatauv(L, sz, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
|
||||||
|
lua_getiuservalue(L, idx, 1)
|
||||||
|
}
|
||||||
|
|
||||||
// set functions (stack -> Lua)
|
// set functions (stack -> Lua)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn lua_setglobal(L: *mut lua_State, var: *const c_char);
|
pub fn lua_setglobal(L: *mut lua_State, var: *const c_char);
|
||||||
pub fn lua_settable(L: *mut lua_State, idx: c_int);
|
pub fn lua_settable(L: *mut lua_State, idx: c_int);
|
||||||
pub fn lua_setfield(L: *mut lua_State, idx: c_int, k: *const c_char);
|
pub fn lua_setfield(L: *mut lua_State, idx: c_int, k: *const c_char);
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_seti(L: *mut lua_State, idx: c_int, n: lua_Integer);
|
pub fn lua_seti(L: *mut lua_State, idx: c_int, n: lua_Integer);
|
||||||
pub fn lua_rawset(L: *mut lua_State, idx: c_int);
|
pub fn lua_rawset(L: *mut lua_State, idx: c_int);
|
||||||
pub fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer);
|
pub fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer);
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void);
|
pub fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void);
|
||||||
pub fn lua_setmetatable(L: *mut lua_State, objindex: c_int) -> c_int;
|
pub fn lua_setmetatable(L: *mut lua_State, objindex: c_int) -> c_int;
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub fn lua_setiuservalue(L: *mut lua_State, idx: c_int, n: c_int) -> c_int;
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||||
pub fn lua_setuservalue(L: *mut lua_State, idx: c_int);
|
pub fn lua_setuservalue(L: *mut lua_State, idx: c_int);
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
pub fn lua_setfenv(L: *mut lua_State, idx: c_int) -> c_int;
|
pub fn lua_setfenv(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn lua_setuservalue(L: *mut lua_State, idx: c_int) {
|
||||||
|
lua_setiuservalue(L, idx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
// 'load' and 'call' functions (load and run Lua code)
|
// 'load' and 'call' functions (load and run Lua code)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_callk(
|
pub fn lua_callk(
|
||||||
L: *mut lua_State,
|
L: *mut lua_State,
|
||||||
nargs: c_int,
|
nargs: c_int,
|
||||||
@@ -376,7 +421,7 @@ extern "C" {
|
|||||||
k: Option<lua_CFunction>,
|
k: Option<lua_CFunction>,
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_pcallk(
|
pub fn lua_pcallk(
|
||||||
L: *mut lua_State,
|
L: *mut lua_State,
|
||||||
nargs: c_int,
|
nargs: c_int,
|
||||||
@@ -412,7 +457,7 @@ extern "C" {
|
|||||||
mode: *const c_char,
|
mode: *const c_char,
|
||||||
) -> c_int;
|
) -> c_int;
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_dump(
|
pub fn lua_dump(
|
||||||
L: *mut lua_State,
|
L: *mut lua_State,
|
||||||
writer: lua_Writer,
|
writer: lua_Writer,
|
||||||
@@ -424,13 +469,13 @@ extern "C" {
|
|||||||
pub fn lua_dump_old(L: *mut lua_State, writer: lua_Writer, data: *mut c_void) -> c_int;
|
pub fn lua_dump_old(L: *mut lua_State, writer: lua_Writer, data: *mut c_void) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn lua_call(L: *mut lua_State, n: c_int, r: c_int) {
|
pub unsafe fn lua_call(L: *mut lua_State, n: c_int, r: c_int) {
|
||||||
lua_callk(L, n, r, 0, None)
|
lua_callk(L, n, r, 0, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn lua_pcall(L: *mut lua_State, n: c_int, r: c_int, f: c_int) -> c_int {
|
pub unsafe fn lua_pcall(L: *mut lua_State, n: c_int, r: c_int, f: c_int) -> c_int {
|
||||||
lua_pcallk(L, n, r, f, 0, None)
|
lua_pcallk(L, n, r, f, 0, None)
|
||||||
@@ -438,7 +483,7 @@ pub unsafe fn lua_pcall(L: *mut lua_State, n: c_int, r: c_int, f: c_int) -> c_in
|
|||||||
|
|
||||||
// coroutine functions
|
// coroutine functions
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_yieldk(
|
pub fn lua_yieldk(
|
||||||
L: *mut lua_State,
|
L: *mut lua_State,
|
||||||
nresults: c_int,
|
nresults: c_int,
|
||||||
@@ -455,23 +500,57 @@ extern "C" {
|
|||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
pub fn lua_yield(L: *mut lua_State, nresults: c_int) -> c_int;
|
pub fn lua_yield(L: *mut lua_State, nresults: c_int) -> c_int;
|
||||||
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub fn lua_resume(
|
||||||
|
L: *mut lua_State,
|
||||||
|
from: *mut lua_State,
|
||||||
|
narg: c_int,
|
||||||
|
nres: *mut c_int,
|
||||||
|
) -> c_int;
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||||
pub fn lua_resume(L: *mut lua_State, from: *mut lua_State, narg: c_int) -> c_int;
|
#[link_name = "lua_resume"]
|
||||||
|
pub fn lua_resume_53(L: *mut lua_State, from: *mut lua_State, narg: c_int) -> c_int;
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
#[link_name = "lua_resume"]
|
#[link_name = "lua_resume"]
|
||||||
pub fn lua_resume_old(L: *mut lua_State, narg: c_int) -> c_int;
|
pub fn lua_resume_old(L: *mut lua_State, narg: c_int) -> c_int;
|
||||||
|
|
||||||
pub fn lua_status(L: *mut lua_State) -> c_int;
|
pub fn lua_status(L: *mut lua_State) -> c_int;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_isyieldable(L: *mut lua_State) -> c_int;
|
pub fn lua_isyieldable(L: *mut lua_State) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn lua_yield(L: *mut lua_State, n: c_int) -> c_int {
|
pub unsafe fn lua_yield(L: *mut lua_State, n: c_int) -> c_int {
|
||||||
lua_yieldk(L, n, 0, None)
|
lua_yieldk(L, n, 0, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "lua53",
|
||||||
|
feature = "lua52",
|
||||||
|
feature = "lua51",
|
||||||
|
feature = "luajit"
|
||||||
|
))]
|
||||||
|
pub unsafe fn lua_resume(
|
||||||
|
L: *mut lua_State,
|
||||||
|
from: *mut lua_State,
|
||||||
|
narg: c_int,
|
||||||
|
nres: *mut c_int,
|
||||||
|
) -> c_int {
|
||||||
|
let ret = lua_resume_53(L, from, narg);
|
||||||
|
if ret == LUA_OK || ret == LUA_YIELD {
|
||||||
|
*nres = lua_gettop(L);
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// warning-related functions
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
extern "C" {
|
||||||
|
pub fn lua_setwarnf(L: *mut lua_State, f: lua_WarnFunction, ud: *mut c_void);
|
||||||
|
pub fn lua_warning(L: *mut lua_State, msg: *const c_char, tocont: c_int);
|
||||||
|
}
|
||||||
|
|
||||||
// garbage-collection function and options
|
// garbage-collection function and options
|
||||||
pub const LUA_GCSTOP: c_int = 0;
|
pub const LUA_GCSTOP: c_int = 0;
|
||||||
pub const LUA_GCRESTART: c_int = 1;
|
pub const LUA_GCRESTART: c_int = 1;
|
||||||
@@ -481,10 +560,22 @@ pub const LUA_GCCOUNTB: c_int = 4;
|
|||||||
pub const LUA_GCSTEP: c_int = 5;
|
pub const LUA_GCSTEP: c_int = 5;
|
||||||
pub const LUA_GCSETPAUSE: c_int = 6;
|
pub const LUA_GCSETPAUSE: c_int = 6;
|
||||||
pub const LUA_GCSETSTEPMUL: c_int = 7;
|
pub const LUA_GCSETSTEPMUL: c_int = 7;
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub const LUA_GCISRUNNING: c_int = 9;
|
pub const LUA_GCISRUNNING: c_int = 9;
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub const LUA_GCGEN: c_int = 10;
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub const LUA_GCINC: c_int = 11;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub fn lua_gc(L: *mut lua_State, what: c_int, ...) -> c_int;
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "lua53",
|
||||||
|
feature = "lua52",
|
||||||
|
feature = "lua51",
|
||||||
|
feature = "luajit"
|
||||||
|
))]
|
||||||
pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int;
|
pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,29 +584,31 @@ extern "C" {
|
|||||||
pub fn lua_error(L: *mut lua_State) -> !;
|
pub fn lua_error(L: *mut lua_State) -> !;
|
||||||
pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int;
|
pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int;
|
||||||
pub fn lua_concat(L: *mut lua_State, n: c_int);
|
pub fn lua_concat(L: *mut lua_State, n: c_int);
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn lua_len(L: *mut lua_State, idx: c_int);
|
pub fn lua_len(L: *mut lua_State, idx: c_int);
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn lua_stringtonumber(L: *mut lua_State, s: *const c_char) -> usize;
|
pub fn lua_stringtonumber(L: *mut lua_State, s: *const c_char) -> usize;
|
||||||
pub fn lua_getallocf(L: *mut lua_State, ud: *mut *mut c_void) -> lua_Alloc;
|
pub fn lua_getallocf(L: *mut lua_State, ud: *mut *mut c_void) -> lua_Alloc;
|
||||||
pub fn lua_setallocf(L: *mut lua_State, f: lua_Alloc, ud: *mut c_void);
|
pub fn lua_setallocf(L: *mut lua_State, f: lua_Alloc, ud: *mut c_void);
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub fn lua_toclose(L: *mut lua_State, idx: c_int);
|
||||||
}
|
}
|
||||||
|
|
||||||
// some useful macros
|
// some useful macros
|
||||||
// here, implemented as Rust functions
|
// here, implemented as Rust functions
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
|
pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
|
||||||
L.offset(-super::glue::LUA_EXTRASPACE as isize) as *mut c_void
|
L.offset(-super::glue::LUA_EXTRASPACE as isize) as *mut c_void
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number {
|
pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number {
|
||||||
lua_tonumberx(L, i, ptr::null_mut())
|
lua_tonumberx(L, i, ptr::null_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
|
pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
|
||||||
lua_tointegerx(L, i, ptr::null_mut())
|
lua_tointegerx(L, i, ptr::null_mut())
|
||||||
@@ -601,7 +694,7 @@ pub unsafe fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int {
|
|||||||
lua_getfield(L, LUA_GLOBALSINDEX, var)
|
lua_getfield(L, LUA_GLOBALSINDEX, var)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn lua_pushglobaltable(L: *mut lua_State) -> c_int {
|
pub unsafe fn lua_pushglobaltable(L: *mut lua_State) -> c_int {
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
|
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
|
||||||
@@ -612,20 +705,20 @@ pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char {
|
|||||||
lua_tolstring(L, i, ptr::null_mut())
|
lua_tolstring(L, i, ptr::null_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn lua_insert(L: *mut lua_State, idx: c_int) {
|
pub unsafe fn lua_insert(L: *mut lua_State, idx: c_int) {
|
||||||
lua_rotate(L, idx, 1)
|
lua_rotate(L, idx, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn lua_remove(L: *mut lua_State, idx: c_int) {
|
pub unsafe fn lua_remove(L: *mut lua_State, idx: c_int) {
|
||||||
lua_rotate(L, idx, -1);
|
lua_rotate(L, idx, -1);
|
||||||
lua_pop(L, 1)
|
lua_pop(L, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn lua_replace(L: *mut lua_State, idx: c_int) {
|
pub unsafe fn lua_replace(L: *mut lua_State, idx: c_int) {
|
||||||
lua_copy(L, -1, idx);
|
lua_copy(L, -1, idx);
|
||||||
@@ -647,7 +740,7 @@ pub const LUA_MASKLINE: c_int = 1 << (LUA_HOOKLINE as usize);
|
|||||||
pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
|
pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
|
||||||
|
|
||||||
/// Type for functions to be called on debug events.
|
/// Type for functions to be called on debug events.
|
||||||
pub type lua_Hook = extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug);
|
pub type lua_Hook = unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug);
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn lua_getstack(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int;
|
pub fn lua_getstack(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int;
|
||||||
@@ -657,18 +750,21 @@ extern "C" {
|
|||||||
pub fn lua_getupvalue(L: *mut lua_State, funcindex: c_int, n: c_int) -> *const c_char;
|
pub fn lua_getupvalue(L: *mut lua_State, funcindex: c_int, n: c_int) -> *const c_char;
|
||||||
pub fn lua_setupvalue(L: *mut lua_State, funcindex: c_int, n: c_int) -> *const c_char;
|
pub fn lua_setupvalue(L: *mut lua_State, funcindex: c_int, n: c_int) -> *const c_char;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn lua_upvalueid(L: *mut lua_State, fidx: c_int, n: c_int) -> *mut c_void;
|
pub fn lua_upvalueid(L: *mut lua_State, fidx: c_int, n: c_int) -> *mut c_void;
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn lua_upvaluejoin(L: *mut lua_State, fidx1: c_int, n1: c_int, fidx2: c_int, n2: c_int);
|
pub fn lua_upvaluejoin(L: *mut lua_State, fidx1: c_int, n1: c_int, fidx2: c_int, n2: c_int);
|
||||||
|
|
||||||
pub fn lua_sethook(L: *mut lua_State, func: lua_Hook, mask: c_int, count: c_int);
|
pub fn lua_sethook(L: *mut lua_State, func: Option<lua_Hook>, mask: c_int, count: c_int);
|
||||||
pub fn lua_gethook(L: *mut lua_State) -> Option<lua_Hook>;
|
pub fn lua_gethook(L: *mut lua_State) -> Option<lua_Hook>;
|
||||||
pub fn lua_gethookmask(L: *mut lua_State) -> c_int;
|
pub fn lua_gethookmask(L: *mut lua_State) -> c_int;
|
||||||
pub fn lua_gethookcount(L: *mut lua_State) -> c_int;
|
pub fn lua_gethookcount(L: *mut lua_State) -> c_int;
|
||||||
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub fn lua_setcstacklimit(L: *mut lua_State, limit: c_uint) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct lua_Debug {
|
pub struct lua_Debug {
|
||||||
pub event: c_int,
|
pub event: c_int,
|
||||||
@@ -676,6 +772,8 @@ pub struct lua_Debug {
|
|||||||
pub namewhat: *const c_char,
|
pub namewhat: *const c_char,
|
||||||
pub what: *const c_char,
|
pub what: *const c_char,
|
||||||
pub source: *const c_char,
|
pub source: *const c_char,
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub srclen: usize,
|
||||||
pub currentline: c_int,
|
pub currentline: c_int,
|
||||||
pub linedefined: c_int,
|
pub linedefined: c_int,
|
||||||
pub lastlinedefined: c_int,
|
pub lastlinedefined: c_int,
|
||||||
@@ -683,6 +781,10 @@ pub struct lua_Debug {
|
|||||||
pub nparams: c_uchar,
|
pub nparams: c_uchar,
|
||||||
pub isvararg: c_char,
|
pub isvararg: c_char,
|
||||||
pub istailcall: c_char,
|
pub istailcall: c_char,
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub ftransfer: c_ushort,
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub ntransfer: c_ushort,
|
||||||
pub short_src: [c_char; luaconf::LUA_IDSIZE as usize],
|
pub short_src: [c_char; luaconf::LUA_IDSIZE as usize],
|
||||||
// lua.h mentions this is for private use
|
// lua.h mentions this is for private use
|
||||||
i_ci: *mut c_void,
|
i_ci: *mut c_void,
|
||||||
|
|||||||
+3
-4
@@ -1,6 +1,6 @@
|
|||||||
// The MIT License (MIT)
|
// The MIT License (MIT)
|
||||||
//
|
//
|
||||||
// Copyright (c) 2019 A. Orlenko
|
// Copyright (c) 2019-2021 A. Orlenko
|
||||||
// Copyright (c) 2014 J.C. Moyer
|
// Copyright (c) 2014 J.C. Moyer
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@@ -23,15 +23,14 @@
|
|||||||
|
|
||||||
//! Contains definitions from `luaconf.h`.
|
//! Contains definitions from `luaconf.h`.
|
||||||
|
|
||||||
pub use super::glue::LUAL_BUFFERSIZE;
|
|
||||||
pub use super::glue::LUA_INTEGER;
|
pub use super::glue::LUA_INTEGER;
|
||||||
pub use super::glue::LUA_NUMBER;
|
pub use super::glue::LUA_NUMBER;
|
||||||
pub use super::glue::LUA_UNSIGNED;
|
pub use super::glue::LUA_UNSIGNED;
|
||||||
|
|
||||||
pub use super::glue::LUA_IDSIZE;
|
pub use super::glue::LUA_IDSIZE;
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub use super::glue::LUAL_NUMSIZES;
|
pub use super::glue::LUAL_NUMSIZES;
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub type LUA_KCONTEXT = isize; // intptr_t
|
pub type LUA_KCONTEXT = isize; // intptr_t
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
// The MIT License (MIT)
|
// The MIT License (MIT)
|
||||||
//
|
//
|
||||||
// Copyright (c) 2019 A. Orlenko
|
// Copyright (c) 2019-2021 A. Orlenko
|
||||||
// Copyright (c) 2014 J.C. Moyer
|
// Copyright (c) 2014 J.C. Moyer
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@@ -32,7 +32,7 @@ pub use super::glue::{
|
|||||||
LUA_STRLIBNAME, LUA_TABLIBNAME,
|
LUA_STRLIBNAME, LUA_TABLIBNAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub use super::glue::LUA_UTF8LIBNAME;
|
pub use super::glue::LUA_UTF8LIBNAME;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua52", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "luajit"))]
|
||||||
@@ -43,13 +43,13 @@ pub use super::glue::{LUA_FFILIBNAME, LUA_JITLIBNAME};
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn luaopen_base(L: *mut lua_State) -> c_int;
|
pub fn luaopen_base(L: *mut lua_State) -> c_int;
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub fn luaopen_coroutine(L: *mut lua_State) -> c_int;
|
pub fn luaopen_coroutine(L: *mut lua_State) -> c_int;
|
||||||
pub fn luaopen_table(L: *mut lua_State) -> c_int;
|
pub fn luaopen_table(L: *mut lua_State) -> c_int;
|
||||||
pub fn luaopen_io(L: *mut lua_State) -> c_int;
|
pub fn luaopen_io(L: *mut lua_State) -> c_int;
|
||||||
pub fn luaopen_os(L: *mut lua_State) -> c_int;
|
pub fn luaopen_os(L: *mut lua_State) -> c_int;
|
||||||
pub fn luaopen_string(L: *mut lua_State) -> c_int;
|
pub fn luaopen_string(L: *mut lua_State) -> c_int;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub fn luaopen_utf8(L: *mut lua_State) -> c_int;
|
pub fn luaopen_utf8(L: *mut lua_State) -> c_int;
|
||||||
#[cfg(feature = "lua52")]
|
#[cfg(feature = "lua52")]
|
||||||
pub fn luaopen_bit32(L: *mut lua_State) -> c_int;
|
pub fn luaopen_bit32(L: *mut lua_State) -> c_int;
|
||||||
|
|||||||
+50
-12
@@ -1,6 +1,6 @@
|
|||||||
// The MIT License (MIT)
|
// The MIT License (MIT)
|
||||||
//
|
//
|
||||||
// Copyright (c) 2019 A. Orlenko
|
// Copyright (c) 2019-2021 A. Orlenko
|
||||||
// Copyright (c) 2014 J.C. Moyer
|
// Copyright (c) 2014 J.C. Moyer
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@@ -36,11 +36,14 @@ pub use self::lua::{
|
|||||||
lua_Unsigned, lua_Writer,
|
lua_Unsigned, lua_Writer,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(feature = "lua54")]
|
||||||
|
pub use self::lua::lua_WarnFunction;
|
||||||
|
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub use self::lua::{lua_KContext, lua_KFunction};
|
pub use self::lua::{lua_KContext, lua_KFunction};
|
||||||
|
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
pub use self::lua::lua_setfenv;
|
pub use self::lua::{lua_getfenv, lua_setfenv};
|
||||||
|
|
||||||
// C API functions
|
// C API functions
|
||||||
pub use self::lua::{
|
pub use self::lua::{
|
||||||
@@ -155,10 +158,16 @@ pub use self::lua::{
|
|||||||
lua_yield,
|
lua_yield,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(feature = "lua54")]
|
||||||
|
pub use self::lua::{
|
||||||
|
lua_getiuservalue, lua_newuserdatauv, lua_resetthread, lua_setcstacklimit, lua_setiuservalue,
|
||||||
|
lua_setwarnf, lua_toclose, lua_warning,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub use self::lua::{lua_isyieldable, lua_version};
|
pub use self::lua::{lua_isyieldable, lua_version};
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub use self::lua::{lua_callk, lua_pcallk, lua_upvalueid, lua_upvaluejoin, lua_yieldk};
|
pub use self::lua::{lua_callk, lua_pcallk, lua_upvalueid, lua_upvaluejoin, lua_yieldk};
|
||||||
|
|
||||||
// auxiliary library types
|
// auxiliary library types
|
||||||
@@ -177,7 +186,7 @@ pub use self::lauxlib::{
|
|||||||
luaL_where,
|
luaL_where,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
pub use self::lauxlib::{luaL_execresult, luaL_fileresult, luaL_loadfilex};
|
pub use self::lauxlib::{luaL_execresult, luaL_fileresult, luaL_loadfilex};
|
||||||
|
|
||||||
// lualib.h functions
|
// lualib.h functions
|
||||||
@@ -186,7 +195,7 @@ pub use self::lualib::{
|
|||||||
luaopen_package, luaopen_string, luaopen_table,
|
luaopen_package, luaopen_string, luaopen_table,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub use self::lualib::{luaopen_coroutine, luaopen_utf8};
|
pub use self::lualib::{luaopen_coroutine, luaopen_utf8};
|
||||||
|
|
||||||
#[cfg(feature = "lua52")]
|
#[cfg(feature = "lua52")]
|
||||||
@@ -202,17 +211,23 @@ pub use self::lua::{
|
|||||||
LUA_HOOKCOUNT, LUA_HOOKLINE, LUA_HOOKRET, LUA_HOOKTAILCALL, LUA_MASKCALL, LUA_MASKCOUNT,
|
LUA_HOOKCOUNT, LUA_HOOKLINE, LUA_HOOKRET, LUA_HOOKTAILCALL, LUA_MASKCALL, LUA_MASKCOUNT,
|
||||||
LUA_MASKLINE, LUA_MASKRET, LUA_MINSTACK, LUA_MULTRET, LUA_OK, LUA_OPADD, LUA_OPDIV, LUA_OPEQ,
|
LUA_MASKLINE, LUA_MASKRET, LUA_MINSTACK, LUA_MULTRET, LUA_OK, LUA_OPADD, LUA_OPDIV, LUA_OPEQ,
|
||||||
LUA_OPLE, LUA_OPLT, LUA_OPMOD, LUA_OPMUL, LUA_OPPOW, LUA_OPSUB, LUA_OPUNM, LUA_REGISTRYINDEX,
|
LUA_OPLE, LUA_OPLT, LUA_OPMOD, LUA_OPMUL, LUA_OPPOW, LUA_OPSUB, LUA_OPUNM, LUA_REGISTRYINDEX,
|
||||||
LUA_TBOOLEAN, LUA_TFUNCTION, LUA_TLIGHTUSERDATA, LUA_TNIL, LUA_TNONE, LUA_TNUMBER, LUA_TSTRING,
|
LUA_SIGNATURE, LUA_TBOOLEAN, LUA_TFUNCTION, LUA_TLIGHTUSERDATA, LUA_TNIL, LUA_TNONE,
|
||||||
LUA_TTABLE, LUA_TTHREAD, LUA_TUSERDATA, LUA_YIELD,
|
LUA_TNUMBER, LUA_TSTRING, LUA_TTABLE, LUA_TTHREAD, LUA_TUSERDATA, LUA_YIELD,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub use self::lua::{
|
pub use self::lua::{
|
||||||
LUA_OPBAND, LUA_OPBNOT, LUA_OPBOR, LUA_OPBXOR, LUA_OPIDIV, LUA_OPSHL, LUA_OPSHR,
|
LUA_OPBAND, LUA_OPBNOT, LUA_OPBOR, LUA_OPBXOR, LUA_OPIDIV, LUA_OPSHL, LUA_OPSHR,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub use self::lua::{LUA_GCGEN, LUA_GCINC};
|
||||||
|
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
|
pub use self::lua::{LUA_GCISRUNNING, LUA_RIDX_GLOBALS, LUA_RIDX_MAINTHREAD};
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||||
pub use self::lua::{LUA_ERRGCMM, LUA_GCISRUNNING, LUA_RIDX_GLOBALS, LUA_RIDX_MAINTHREAD};
|
pub use self::lua::LUA_ERRGCMM;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
pub use self::lua::{LUA_ENVIRONINDEX, LUA_GLOBALSINDEX};
|
pub use self::lua::{LUA_ENVIRONINDEX, LUA_GLOBALSINDEX};
|
||||||
@@ -226,7 +241,7 @@ pub use self::lualib::{
|
|||||||
LUA_STRLIBNAME, LUA_TABLIBNAME,
|
LUA_STRLIBNAME, LUA_TABLIBNAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
pub use self::lualib::LUA_UTF8LIBNAME;
|
pub use self::lualib::LUA_UTF8LIBNAME;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua52", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "luajit"))]
|
||||||
@@ -238,7 +253,30 @@ pub use self::lualib::{LUA_FFILIBNAME, LUA_JITLIBNAME};
|
|||||||
// Not actually defined in lua.h / luaconf.h
|
// Not actually defined in lua.h / luaconf.h
|
||||||
pub const LUA_MAX_UPVALUES: c_int = 255;
|
pub const LUA_MAX_UPVALUES: c_int = 255;
|
||||||
|
|
||||||
|
// Copied from https://github.com/rust-lang/rust/blob/master/src/libstd/sys_common/alloc.rs
|
||||||
|
#[cfg(all(any(
|
||||||
|
target_arch = "x86",
|
||||||
|
target_arch = "arm",
|
||||||
|
target_arch = "mips",
|
||||||
|
target_arch = "powerpc",
|
||||||
|
target_arch = "powerpc64",
|
||||||
|
target_arch = "asmjs",
|
||||||
|
target_arch = "wasm32",
|
||||||
|
target_arch = "hexagon"
|
||||||
|
)))]
|
||||||
|
pub const SYS_MIN_ALIGN: usize = 8;
|
||||||
|
#[cfg(all(any(
|
||||||
|
target_arch = "x86_64",
|
||||||
|
target_arch = "aarch64",
|
||||||
|
target_arch = "mips64",
|
||||||
|
target_arch = "s390x",
|
||||||
|
target_arch = "sparc64",
|
||||||
|
target_arch = "riscv64"
|
||||||
|
)))]
|
||||||
|
pub const SYS_MIN_ALIGN: usize = 16;
|
||||||
|
|
||||||
#[allow(unused_imports, dead_code, non_camel_case_types)]
|
#[allow(unused_imports, dead_code, non_camel_case_types)]
|
||||||
|
#[allow(clippy::unreadable_literal)]
|
||||||
mod glue {
|
mod glue {
|
||||||
include!(concat!(env!("OUT_DIR"), "/glue.rs"));
|
include!(concat!(env!("OUT_DIR"), "/glue.rs"));
|
||||||
}
|
}
|
||||||
|
|||||||
+85
-2
@@ -1,5 +1,5 @@
|
|||||||
use std::os::raw::c_int;
|
use std::os::raw::{c_int, c_void};
|
||||||
use std::ptr;
|
use std::{ptr, slice};
|
||||||
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
@@ -9,6 +9,9 @@ use crate::util::{
|
|||||||
};
|
};
|
||||||
use crate::value::{FromLuaMulti, MultiValue, ToLuaMulti};
|
use crate::value::{FromLuaMulti, MultiValue, ToLuaMulti};
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
use {futures_core::future::LocalBoxFuture, futures_util::future};
|
||||||
|
|
||||||
/// Handle to an internal Lua function.
|
/// Handle to an internal Lua function.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Function<'lua>(pub(crate) LuaRef<'lua>);
|
pub struct Function<'lua>(pub(crate) LuaRef<'lua>);
|
||||||
@@ -86,6 +89,50 @@ impl<'lua> Function<'lua> {
|
|||||||
R::from_lua_multi(results, lua)
|
R::from_lua_multi(results, lua)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a Feature that, when polled, calls `self`, passing `args` as function arguments,
|
||||||
|
/// and drives the execution.
|
||||||
|
///
|
||||||
|
/// Internaly it wraps the function to an [`AsyncThread`].
|
||||||
|
///
|
||||||
|
/// Requires `feature = "async"`
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::time::Duration;
|
||||||
|
/// use futures_timer::Delay;
|
||||||
|
/// # use mlua::{Lua, Result};
|
||||||
|
/// # #[tokio::main]
|
||||||
|
/// # async fn main() -> Result<()> {
|
||||||
|
/// # let lua = Lua::new();
|
||||||
|
///
|
||||||
|
/// let sleep = lua.create_async_function(move |_lua, n: u64| async move {
|
||||||
|
/// Delay::new(Duration::from_millis(n)).await;
|
||||||
|
/// Ok(())
|
||||||
|
/// })?;
|
||||||
|
///
|
||||||
|
/// sleep.call_async(10).await?;
|
||||||
|
///
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`AsyncThread`]: struct.AsyncThread.html
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||||
|
pub fn call_async<'fut, A, R>(&self, args: A) -> LocalBoxFuture<'fut, Result<R>>
|
||||||
|
where
|
||||||
|
'lua: 'fut,
|
||||||
|
A: ToLuaMulti<'lua>,
|
||||||
|
R: FromLuaMulti<'lua> + 'fut,
|
||||||
|
{
|
||||||
|
let lua = self.0.lua;
|
||||||
|
match lua.create_thread(self.clone()) {
|
||||||
|
Ok(t) => Box::pin(t.into_async(args)),
|
||||||
|
Err(e) => Box::pin(future::err(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a function that, when called, calls `self`, passing `args` as the first set of
|
/// Returns a function that, when called, calls `self`, passing `args` as the first set of
|
||||||
/// arguments.
|
/// arguments.
|
||||||
///
|
///
|
||||||
@@ -159,6 +206,42 @@ impl<'lua> Function<'lua> {
|
|||||||
Ok(Function(lua.pop_ref()))
|
Ok(Function(lua.pop_ref()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Dumps the function as a binary chunk.
|
||||||
|
///
|
||||||
|
/// If `strip` is true, the binary representation may not include all debug information
|
||||||
|
/// about the function, to save space.
|
||||||
|
pub fn dump(&self, strip: bool) -> Result<Vec<u8>> {
|
||||||
|
unsafe extern "C" fn writer(
|
||||||
|
_state: *mut ffi::lua_State,
|
||||||
|
buf: *const c_void,
|
||||||
|
buf_len: usize,
|
||||||
|
data: *mut c_void,
|
||||||
|
) -> c_int {
|
||||||
|
let data = &mut *(data as *mut Vec<u8>);
|
||||||
|
let buf = slice::from_raw_parts(buf as *const u8, buf_len);
|
||||||
|
data.extend_from_slice(buf);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
let lua = self.0.lua;
|
||||||
|
let mut data: Vec<u8> = Vec::new();
|
||||||
|
unsafe {
|
||||||
|
let _sg = StackGuard::new(lua.state);
|
||||||
|
assert_stack(lua.state, 1);
|
||||||
|
lua.push_ref(&self.0);
|
||||||
|
let strip = if strip { 1 } else { 0 };
|
||||||
|
ffi::lua_dump(
|
||||||
|
lua.state,
|
||||||
|
writer,
|
||||||
|
&mut data as *mut Vec<u8> as *mut c_void,
|
||||||
|
strip,
|
||||||
|
);
|
||||||
|
ffi::lua_pop(lua.state, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> PartialEq for Function<'lua> {
|
impl<'lua> PartialEq for Function<'lua> {
|
||||||
|
|||||||
+195
@@ -0,0 +1,195 @@
|
|||||||
|
use std::ffi::CStr;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::os::raw::{c_char, c_int};
|
||||||
|
|
||||||
|
use crate::ffi::{self, lua_Debug, lua_State};
|
||||||
|
use crate::lua::Lua;
|
||||||
|
use crate::util::callback_error;
|
||||||
|
|
||||||
|
/// Contains information about currently executing Lua code.
|
||||||
|
///
|
||||||
|
/// The `Debug` structure is provided as a parameter to the hook function set with
|
||||||
|
/// [`Lua::set_hook`]. You may call the methods on this structure to retrieve information about the
|
||||||
|
/// Lua code executing at the time that the hook function was called. Further information can be
|
||||||
|
/// found in the [Lua 5.3 documentaton][lua_doc].
|
||||||
|
///
|
||||||
|
/// [lua_doc]: https://www.lua.org/manual/5.3/manual.html#lua_Debug
|
||||||
|
/// [`Lua::set_hook`]: struct.Lua.html#method.set_hook
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Debug<'a> {
|
||||||
|
ar: *mut lua_Debug,
|
||||||
|
state: *mut lua_State,
|
||||||
|
_phantom: PhantomData<&'a ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Debug<'a> {
|
||||||
|
/// Corresponds to the `n` what mask.
|
||||||
|
pub fn names(&self) -> DebugNames<'a> {
|
||||||
|
unsafe {
|
||||||
|
mlua_assert!(
|
||||||
|
ffi::lua_getinfo(self.state, cstr!("n"), self.ar) != 0,
|
||||||
|
"lua_getinfo failed with `n`"
|
||||||
|
);
|
||||||
|
DebugNames {
|
||||||
|
name: ptr_to_str((*self.ar).name),
|
||||||
|
name_what: ptr_to_str((*self.ar).namewhat),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Corresponds to the `S` what mask.
|
||||||
|
pub fn source(&self) -> DebugSource<'a> {
|
||||||
|
unsafe {
|
||||||
|
mlua_assert!(
|
||||||
|
ffi::lua_getinfo(self.state, cstr!("S"), self.ar) != 0,
|
||||||
|
"lua_getinfo failed with `S`"
|
||||||
|
);
|
||||||
|
DebugSource {
|
||||||
|
source: ptr_to_str((*self.ar).source),
|
||||||
|
short_src: ptr_to_str((*self.ar).short_src.as_ptr()),
|
||||||
|
line_defined: (*self.ar).linedefined as i32,
|
||||||
|
last_line_defined: (*self.ar).lastlinedefined as i32,
|
||||||
|
what: ptr_to_str((*self.ar).what),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Corresponds to the `l` what mask. Returns the current line.
|
||||||
|
pub fn curr_line(&self) -> i32 {
|
||||||
|
unsafe {
|
||||||
|
mlua_assert!(
|
||||||
|
ffi::lua_getinfo(self.state, cstr!("l"), self.ar) != 0,
|
||||||
|
"lua_getinfo failed with `l`"
|
||||||
|
);
|
||||||
|
(*self.ar).currentline as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Corresponds to the `t` what mask. Returns true if the hook is in a function tail call, false
|
||||||
|
/// otherwise.
|
||||||
|
pub fn is_tail_call(&self) -> bool {
|
||||||
|
unsafe {
|
||||||
|
mlua_assert!(
|
||||||
|
ffi::lua_getinfo(self.state, cstr!("t"), self.ar) != 0,
|
||||||
|
"lua_getinfo failed with `t`"
|
||||||
|
);
|
||||||
|
(*self.ar).currentline != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Corresponds to the `u` what mask.
|
||||||
|
pub fn stack(&self) -> DebugStack {
|
||||||
|
unsafe {
|
||||||
|
mlua_assert!(
|
||||||
|
ffi::lua_getinfo(self.state, cstr!("u"), self.ar) != 0,
|
||||||
|
"lua_getinfo failed with `u`"
|
||||||
|
);
|
||||||
|
DebugStack {
|
||||||
|
num_ups: (*self.ar).nups as i32,
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
|
num_params: (*self.ar).nparams as i32,
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
|
is_vararg: (*self.ar).isvararg != 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct DebugNames<'a> {
|
||||||
|
pub name: Option<&'a [u8]>,
|
||||||
|
pub name_what: Option<&'a [u8]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct DebugSource<'a> {
|
||||||
|
pub source: Option<&'a [u8]>,
|
||||||
|
pub short_src: Option<&'a [u8]>,
|
||||||
|
pub line_defined: i32,
|
||||||
|
pub last_line_defined: i32,
|
||||||
|
pub what: Option<&'a [u8]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct DebugStack {
|
||||||
|
pub num_ups: i32,
|
||||||
|
/// Requires `feature = "lua54/lua53/lua52"`
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", doc))]
|
||||||
|
pub num_params: i32,
|
||||||
|
/// Requires `feature = "lua54/lua53/lua52"`
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", doc))]
|
||||||
|
pub is_vararg: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines when a hook function will be called by Lua.
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
pub struct HookTriggers {
|
||||||
|
/// Before a function call.
|
||||||
|
pub on_calls: bool,
|
||||||
|
/// When Lua returns from a function.
|
||||||
|
pub on_returns: bool,
|
||||||
|
/// Before executing a new line, or returning from a function call.
|
||||||
|
pub every_line: bool,
|
||||||
|
/// After a certain number of VM instructions have been executed. When set to `Some(count)`,
|
||||||
|
/// `count` is the number of VM instructions to execute before calling the hook.
|
||||||
|
///
|
||||||
|
/// # Performance
|
||||||
|
///
|
||||||
|
/// Setting this option to a low value can incur a very high overhead.
|
||||||
|
pub every_nth_instruction: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HookTriggers {
|
||||||
|
// Compute the mask to pass to `lua_sethook`.
|
||||||
|
pub(crate) fn mask(&self) -> c_int {
|
||||||
|
let mut mask: c_int = 0;
|
||||||
|
if self.on_calls {
|
||||||
|
mask |= ffi::LUA_MASKCALL
|
||||||
|
}
|
||||||
|
if self.on_returns {
|
||||||
|
mask |= ffi::LUA_MASKRET
|
||||||
|
}
|
||||||
|
if self.every_line {
|
||||||
|
mask |= ffi::LUA_MASKLINE
|
||||||
|
}
|
||||||
|
if self.every_nth_instruction.is_some() {
|
||||||
|
mask |= ffi::LUA_MASKCOUNT
|
||||||
|
}
|
||||||
|
mask
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the `count` parameter to pass to `lua_sethook`, if applicable. Otherwise, zero is
|
||||||
|
// returned.
|
||||||
|
pub(crate) fn count(&self) -> c_int {
|
||||||
|
self.every_nth_instruction.unwrap_or(0) as c_int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe extern "C" fn hook_proc(state: *mut lua_State, ar: *mut lua_Debug) {
|
||||||
|
callback_error(state, |_| {
|
||||||
|
let debug = Debug {
|
||||||
|
ar,
|
||||||
|
state,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
|
let lua = Lua::make_from_ptr(state);
|
||||||
|
let hook_cb = mlua_expect!(lua.hook_callback(), "no hook callback set in hook_proc");
|
||||||
|
|
||||||
|
#[allow(clippy::match_wild_err_arm)]
|
||||||
|
match hook_cb.try_borrow_mut() {
|
||||||
|
Ok(mut b) => (&mut *b)(&lua, debug),
|
||||||
|
Err(_) => mlua_panic!("Lua should not allow hooks to be called within another hook"),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
+58
-2
@@ -24,6 +24,30 @@
|
|||||||
//! The [`UserData`] trait can be implemented by user-defined types to make them available to Lua.
|
//! The [`UserData`] trait can be implemented by user-defined types to make them available to Lua.
|
||||||
//! Methods and operators to be used from Lua can be added using the [`UserDataMethods`] API.
|
//! Methods and operators to be used from Lua can be added using the [`UserDataMethods`] API.
|
||||||
//!
|
//!
|
||||||
|
//! # Serde support
|
||||||
|
//!
|
||||||
|
//! The [`LuaSerdeExt`] trait implemented for [`Lua`] allows conversion from Rust types to Lua values
|
||||||
|
//! and vice versa using serde. Any user defined data type that implements [`serde::Serialize`] or
|
||||||
|
//! [`serde::Deserialize`] can be converted.
|
||||||
|
//! For convenience, additional functionality to handle `NULL` values and arrays is provided.
|
||||||
|
//!
|
||||||
|
//! The [`Value`] enum implements [`serde::Serialize`] trait to support serializing Lua values
|
||||||
|
//! (including [`UserData`]) into Rust values.
|
||||||
|
//!
|
||||||
|
//! Requires `feature = "serialize"`.
|
||||||
|
//!
|
||||||
|
//! # Async/await support
|
||||||
|
//!
|
||||||
|
//! The [`create_async_function`] allows creating non-blocking functions that returns [`Future`].
|
||||||
|
//! Lua code with async capabilities can be executed by [`call_async`] family of functions or polling
|
||||||
|
//! [`AsyncThread`] using any runtime (eg. Tokio).
|
||||||
|
//!
|
||||||
|
//! Requires `feature = "async"`.
|
||||||
|
//!
|
||||||
|
//! # `Send` requirement
|
||||||
|
//! By default `mlua` is `!Send`. This can be changed by enabling `feature = "send"` that adds `Send` requirement
|
||||||
|
//! to [`Function`]s and [`UserData`].
|
||||||
|
//!
|
||||||
//! [Lua programming language]: https://www.lua.org/
|
//! [Lua programming language]: https://www.lua.org/
|
||||||
//! [`Lua`]: struct.Lua.html
|
//! [`Lua`]: struct.Lua.html
|
||||||
//! [executing]: struct.Lua.html#method.exec
|
//! [executing]: struct.Lua.html#method.exec
|
||||||
@@ -33,12 +57,24 @@
|
|||||||
//! [`FromLua`]: trait.FromLua.html
|
//! [`FromLua`]: trait.FromLua.html
|
||||||
//! [`ToLuaMulti`]: trait.ToLuaMulti.html
|
//! [`ToLuaMulti`]: trait.ToLuaMulti.html
|
||||||
//! [`FromLuaMulti`]: trait.FromLuaMulti.html
|
//! [`FromLuaMulti`]: trait.FromLuaMulti.html
|
||||||
|
//! [`Function`]: struct.Function.html
|
||||||
//! [`UserData`]: trait.UserData.html
|
//! [`UserData`]: trait.UserData.html
|
||||||
//! [`UserDataMethods`]: trait.UserDataMethods.html
|
//! [`UserDataMethods`]: trait.UserDataMethods.html
|
||||||
|
//! [`LuaSerdeExt`]: serde/trait.LuaSerdeExt.html
|
||||||
|
//! [`Value`]: enum.Value.html
|
||||||
|
//! [`create_async_function`]: struct.Lua.html#method.create_async_function
|
||||||
|
//! [`call_async`]: struct.Function.html#method.call_async
|
||||||
|
//! [`AsyncThread`]: struct.AsyncThread.html
|
||||||
|
//! [`Future`]: ../futures_core/future/trait.Future.html
|
||||||
|
//! [`serde::Serialize`]: https://docs.serde.rs/serde/ser/trait.Serialize.html
|
||||||
|
//! [`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.5.2")]
|
||||||
// Deny warnings inside doc tests / examples. When this isn't present, rustdoc doesn't show *any*
|
// Deny warnings inside doc tests / examples. When this isn't present, rustdoc doesn't show *any*
|
||||||
// warnings at all.
|
// warnings at all.
|
||||||
#![doc(test(attr(deny(warnings))))]
|
#![doc(test(attr(deny(warnings))))]
|
||||||
|
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
@@ -47,6 +83,7 @@ mod conversion;
|
|||||||
mod error;
|
mod error;
|
||||||
mod ffi;
|
mod ffi;
|
||||||
mod function;
|
mod function;
|
||||||
|
mod hook;
|
||||||
mod lua;
|
mod lua;
|
||||||
mod multi;
|
mod multi;
|
||||||
mod scope;
|
mod scope;
|
||||||
@@ -63,15 +100,34 @@ pub use crate::ffi::lua_State;
|
|||||||
|
|
||||||
pub use crate::error::{Error, ExternalError, ExternalResult, Result};
|
pub use crate::error::{Error, ExternalError, ExternalResult, Result};
|
||||||
pub use crate::function::Function;
|
pub use crate::function::Function;
|
||||||
pub use crate::lua::{Chunk, Lua};
|
pub use crate::hook::{Debug, DebugNames, DebugSource, DebugStack, HookTriggers};
|
||||||
|
pub use crate::lua::{Chunk, ChunkMode, GCMode, Lua};
|
||||||
pub use crate::multi::Variadic;
|
pub use crate::multi::Variadic;
|
||||||
pub use crate::scope::Scope;
|
pub use crate::scope::Scope;
|
||||||
pub use crate::stdlib::StdLib;
|
pub use crate::stdlib::StdLib;
|
||||||
pub use crate::string::String;
|
pub use crate::string::String;
|
||||||
pub use crate::table::{Table, TablePairs, TableSequence};
|
pub use crate::table::{Table, TableExt, TablePairs, TableSequence};
|
||||||
pub use crate::thread::{Thread, ThreadStatus};
|
pub use crate::thread::{Thread, ThreadStatus};
|
||||||
pub use crate::types::{Integer, LightUserData, Number, RegistryKey};
|
pub use crate::types::{Integer, LightUserData, Number, RegistryKey};
|
||||||
pub use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataMethods};
|
pub use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataMethods};
|
||||||
pub use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value};
|
pub use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value};
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub use crate::thread::AsyncThread;
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
pub use crate::serde::LuaSerdeExt;
|
||||||
|
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
|
||||||
|
pub mod serde;
|
||||||
|
|
||||||
|
// Re-export #[mlua_derive::lua_module].
|
||||||
|
#[cfg(feature = "mlua_derive")]
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate mlua_derive;
|
||||||
|
#[cfg(feature = "mlua_derive")]
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub use mlua_derive::*;
|
||||||
|
|||||||
+1141
-223
File diff suppressed because it is too large
Load Diff
@@ -78,3 +78,19 @@ macro_rules! mlua_expect {
|
|||||||
mlua_expect!($res, $msg)
|
mlua_expect!($res, $msg)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "module")]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! require_module_feature {
|
||||||
|
() => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "module"))]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! require_module_feature {
|
||||||
|
() => {
|
||||||
|
compile_error!("Feature `module` must be enabled in the `mlua` crate");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
+2
-2
@@ -34,7 +34,7 @@ impl<'lua, T: ToLua<'lua>> ToLuaMulti<'lua> for T {
|
|||||||
|
|
||||||
impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for T {
|
impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for T {
|
||||||
fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
|
fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||||
Ok(T::from_lua(values.pop_front().unwrap_or(Nil), lua)?)
|
T::from_lua(values.pop_front().unwrap_or(Nil), lua)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ macro_rules! impl_tuple {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> FromLuaMulti<'lua> for () {
|
impl<'lua> FromLuaMulti<'lua> for () {
|
||||||
fn from_lua_multi(_: MultiValue, _: &'lua Lua) -> Result<Self> {
|
fn from_lua_multi(_: MultiValue<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-6
@@ -3,10 +3,14 @@
|
|||||||
pub use crate::{
|
pub use crate::{
|
||||||
AnyUserData as LuaAnyUserData, Chunk as LuaChunk, Error as LuaError,
|
AnyUserData as LuaAnyUserData, Chunk as LuaChunk, Error as LuaError,
|
||||||
ExternalError as LuaExternalError, ExternalResult as LuaExternalResult, FromLua, FromLuaMulti,
|
ExternalError as LuaExternalError, ExternalResult as LuaExternalResult, FromLua, FromLuaMulti,
|
||||||
Function as LuaFunction, Integer as LuaInteger, LightUserData as LuaLightUserData, Lua,
|
Function as LuaFunction, GCMode as LuaGCMode, Integer as LuaInteger,
|
||||||
MetaMethod as LuaMetaMethod, MultiValue as LuaMultiValue, Nil as LuaNil, Number as LuaNumber,
|
LightUserData as LuaLightUserData, Lua, MetaMethod as LuaMetaMethod,
|
||||||
RegistryKey as LuaRegistryKey, Result as LuaResult, Scope as LuaScope, String as LuaString,
|
MultiValue as LuaMultiValue, Nil as LuaNil, Number as LuaNumber, RegistryKey as LuaRegistryKey,
|
||||||
Table as LuaTable, TablePairs as LuaTablePairs, TableSequence as LuaTableSequence,
|
Result as LuaResult, String as LuaString, Table as LuaTable, TableExt as LuaTableExt,
|
||||||
Thread as LuaThread, ThreadStatus as LuaThreadStatus, ToLua, ToLuaMulti,
|
TablePairs as LuaTablePairs, TableSequence as LuaTableSequence, Thread as LuaThread,
|
||||||
UserData as LuaUserData, UserDataMethods as LuaUserDataMethods, Value as LuaValue,
|
ThreadStatus as LuaThreadStatus, ToLua, ToLuaMulti, UserData as LuaUserData,
|
||||||
|
UserDataMethods as LuaUserDataMethods, Value as LuaValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub use crate::AsyncThread as LuaAsyncThread;
|
||||||
|
|||||||
+214
-50
@@ -1,32 +1,42 @@
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::Cell;
|
use std::cell::{Cell, Ref, RefCell, RefMut};
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
use crate::function::Function;
|
use crate::function::Function;
|
||||||
use crate::lua::Lua;
|
use crate::lua::Lua;
|
||||||
use crate::types::{Callback, LuaRef};
|
use crate::types::{Callback, LuaRef, MaybeSend, UserDataCell};
|
||||||
use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataMethods};
|
use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataMethods, UserDataWrapped};
|
||||||
use crate::util::{
|
use crate::util::{
|
||||||
assert_stack, init_userdata_metatable, protect_lua_closure, push_string, push_userdata,
|
assert_stack, init_userdata_metatable, protect_lua_closure, push_string, push_userdata,
|
||||||
take_userdata, StackGuard,
|
take_userdata, StackGuard,
|
||||||
};
|
};
|
||||||
use crate::value::{FromLuaMulti, MultiValue, ToLuaMulti, Value};
|
use crate::value::{FromLuaMulti, MultiValue, ToLuaMulti, Value};
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
use {
|
||||||
|
crate::types::AsyncCallback,
|
||||||
|
futures_core::future::{Future, LocalBoxFuture},
|
||||||
|
futures_util::future::{self, TryFutureExt},
|
||||||
|
};
|
||||||
|
|
||||||
/// Constructed by the [`Lua::scope`] method, allows temporarily creating Lua userdata and
|
/// Constructed by the [`Lua::scope`] method, allows temporarily creating Lua userdata and
|
||||||
/// callbacks that are not required to be Send or 'static.
|
/// callbacks that are not required to be Send or 'static.
|
||||||
///
|
///
|
||||||
/// See [`Lua::scope`] for more details.
|
/// See [`Lua::scope`] for more details.
|
||||||
///
|
///
|
||||||
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
pub struct Scope<'lua, 'scope> {
|
pub struct Scope<'lua, 'scope> {
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
destructors: RefCell<Vec<(LuaRef<'lua>, fn(LuaRef<'lua>) -> Box<dyn Any>)>>,
|
destructors: RefCell<Vec<(LuaRef<'lua>, fn(LuaRef<'lua>) -> Vec<Box<dyn Any>>)>>,
|
||||||
_scope_invariant: PhantomData<Cell<&'scope ()>>,
|
_scope_invariant: PhantomData<Cell<&'scope ()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,15 +103,76 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wraps a Rust async function or closure, creating a callable Lua function handle to it.
|
||||||
|
///
|
||||||
|
/// This is a version of [`Lua::create_async_function`] that creates a callback which expires on
|
||||||
|
/// scope drop. See [`Lua::scope`] and [`Lua::async_scope`] for more details.
|
||||||
|
///
|
||||||
|
/// Requires `feature = "async"`
|
||||||
|
///
|
||||||
|
/// [`Lua::create_async_function`]: struct.Lua.html#method.create_async_function
|
||||||
|
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
||||||
|
/// [`Lua::async_scope`]: struct.Lua.html#method.async_scope
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||||
|
pub fn create_async_function<'callback, A, R, F, FR>(
|
||||||
|
&'callback self,
|
||||||
|
func: F,
|
||||||
|
) -> Result<Function<'lua>>
|
||||||
|
where
|
||||||
|
A: FromLuaMulti<'callback>,
|
||||||
|
R: ToLuaMulti<'callback>,
|
||||||
|
F: 'scope + Fn(&'callback Lua, A) -> FR,
|
||||||
|
FR: 'callback + Future<Output = Result<R>>,
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
self.create_async_callback(Box::new(move |lua, args| {
|
||||||
|
let args = match A::from_lua_multi(args, lua) {
|
||||||
|
Ok(args) => args,
|
||||||
|
Err(e) => return Box::pin(future::err(e)),
|
||||||
|
};
|
||||||
|
Box::pin(func(lua, args).and_then(move |ret| future::ready(ret.to_lua_multi(lua))))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a Lua userdata object from a custom userdata type.
|
/// Create a Lua userdata object from a custom userdata type.
|
||||||
///
|
///
|
||||||
/// This is a version of [`Lua::create_userdata`] that creates a userdata which expires on
|
/// This is a version of [`Lua::create_userdata`] that creates a userdata which expires on
|
||||||
/// scope drop, and does not require that the userdata type be Send (but still requires that the
|
/// scope drop, and does not require that the userdata type be Send (but still requires that the
|
||||||
/// UserData be 'static). See [`Lua::scope`] for more details.
|
/// UserData be 'static).
|
||||||
|
/// See [`Lua::scope`] for more details.
|
||||||
///
|
///
|
||||||
/// [`Lua::create_userdata`]: struct.Lua.html#method.create_userdata
|
/// [`Lua::create_userdata`]: struct.Lua.html#method.create_userdata
|
||||||
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
||||||
pub fn create_static_userdata<T>(&self, data: T) -> Result<AnyUserData<'lua>>
|
pub fn create_userdata<T>(&self, data: T) -> Result<AnyUserData<'lua>>
|
||||||
|
where
|
||||||
|
T: 'static + UserData,
|
||||||
|
{
|
||||||
|
self.create_userdata_inner(UserDataWrapped::new(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a Lua userdata object from a custom serializable userdata type.
|
||||||
|
///
|
||||||
|
/// This is a version of [`Lua::create_ser_userdata`] that creates a userdata which expires on
|
||||||
|
/// scope drop, and does not require that the userdata type be Send (but still requires that the
|
||||||
|
/// UserData be 'static).
|
||||||
|
/// See [`Lua::scope`] for more details.
|
||||||
|
///
|
||||||
|
/// Requires `feature = "serialize"`
|
||||||
|
///
|
||||||
|
/// [`Lua::create_ser_userdata`]: struct.Lua.html#method.create_ser_userdata
|
||||||
|
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
|
||||||
|
pub fn create_ser_userdata<T>(&self, data: T) -> Result<AnyUserData<'lua>>
|
||||||
|
where
|
||||||
|
T: 'static + UserData + Serialize,
|
||||||
|
{
|
||||||
|
self.create_userdata_inner(UserDataWrapped::new_ser(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_userdata_inner<T>(&self, data: UserDataWrapped<T>) -> Result<AnyUserData<'lua>>
|
||||||
where
|
where
|
||||||
T: 'static + UserData,
|
T: 'static + UserData,
|
||||||
{
|
{
|
||||||
@@ -115,7 +186,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||||||
u.lua.push_ref(&u);
|
u.lua.push_ref(&u);
|
||||||
// We know the destructor has not run yet because we hold a reference to the
|
// We know the destructor has not run yet because we hold a reference to the
|
||||||
// userdata.
|
// userdata.
|
||||||
Box::new(take_userdata::<RefCell<T>>(state))
|
vec![Box::new(take_userdata::<UserDataCell<T>>(state))]
|
||||||
}));
|
}));
|
||||||
Ok(u)
|
Ok(u)
|
||||||
}
|
}
|
||||||
@@ -129,7 +200,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||||||
///
|
///
|
||||||
/// Lifting the requirement that the UserData type be 'static comes with some important
|
/// Lifting the requirement that the UserData type be 'static comes with some important
|
||||||
/// limitations, so if you only need to eliminate the Send requirement, it is probably better to
|
/// limitations, so if you only need to eliminate the Send requirement, it is probably better to
|
||||||
/// use [`Scope::create_static_userdata`] instead.
|
/// use [`Scope::create_userdata`] instead.
|
||||||
///
|
///
|
||||||
/// The main limitation that comes from using non-'static userdata is that the produced userdata
|
/// The main limitation that comes from using non-'static userdata is that the produced userdata
|
||||||
/// will no longer have a `TypeId` associated with it, becuase `TypeId` can only work for
|
/// will no longer have a `TypeId` associated with it, becuase `TypeId` can only work for
|
||||||
@@ -140,7 +211,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||||||
/// a single metatable for multiple non-'static types, so there is a higher cost associated with
|
/// a single metatable for multiple non-'static types, so there is a higher cost associated with
|
||||||
/// creating the userdata metatable each time a new userdata is created.
|
/// creating the userdata metatable each time a new userdata is created.
|
||||||
///
|
///
|
||||||
/// [`create_static_userdata`]: #method.create_static_userdata
|
/// [`Scope::create_userdata`]: #method.create_userdata
|
||||||
/// [`Lua::create_userdata`]: struct.Lua.html#method.create_userdata
|
/// [`Lua::create_userdata`]: struct.Lua.html#method.create_userdata
|
||||||
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
||||||
/// [`UserDataMethods`]: trait.UserDataMethods.html
|
/// [`UserDataMethods`]: trait.UserDataMethods.html
|
||||||
@@ -148,7 +219,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||||||
where
|
where
|
||||||
T: 'scope + UserData,
|
T: 'scope + UserData,
|
||||||
{
|
{
|
||||||
let data = Rc::new(RefCell::new(data));
|
let data = Rc::new(RefCell::new(UserDataWrapped::new(data)));
|
||||||
|
|
||||||
// 'callback outliving 'scope is a lie to make the types work out, required due to the
|
// 'callback outliving 'scope is a lie to make the types work out, required due to the
|
||||||
// inability to work with the more correct callback type that is universally quantified over
|
// inability to work with the more correct callback type that is universally quantified over
|
||||||
@@ -157,7 +228,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||||||
// parameters.
|
// parameters.
|
||||||
fn wrap_method<'scope, 'lua, 'callback: 'scope, T: 'scope>(
|
fn wrap_method<'scope, 'lua, 'callback: 'scope, T: 'scope>(
|
||||||
scope: &Scope<'lua, 'scope>,
|
scope: &Scope<'lua, 'scope>,
|
||||||
data: Rc<RefCell<T>>,
|
data: Rc<UserDataCell<T>>,
|
||||||
method: NonStaticMethod<'callback, T>,
|
method: NonStaticMethod<'callback, T>,
|
||||||
) -> Result<Function<'lua>> {
|
) -> Result<Function<'lua>> {
|
||||||
// On methods that actually receive the userdata, we fake a type check on the passed in
|
// On methods that actually receive the userdata, we fake a type check on the passed in
|
||||||
@@ -169,21 +240,18 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||||||
// first argument).
|
// first argument).
|
||||||
let check_data = data.clone();
|
let check_data = data.clone();
|
||||||
let check_ud_type = move |lua: &'callback Lua, value| {
|
let check_ud_type = move |lua: &'callback Lua, value| {
|
||||||
if let Some(value) = value {
|
if let Some(Value::UserData(ud)) = value {
|
||||||
if let Value::UserData(u) = value {
|
unsafe {
|
||||||
unsafe {
|
assert_stack(lua.state, 1);
|
||||||
assert_stack(lua.state, 1);
|
lua.push_ref(&ud.0);
|
||||||
lua.push_ref(&u.0);
|
ffi::lua_getuservalue(lua.state, -1);
|
||||||
ffi::lua_getuservalue(lua.state, -1);
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
{
|
||||||
{
|
ffi::lua_rawgeti(lua.state, -1, 1);
|
||||||
ffi::lua_pushinteger(lua.state, 1);
|
ffi::lua_remove(lua.state, -2);
|
||||||
ffi::lua_gettable(lua.state, -2);
|
|
||||||
ffi::lua_remove(lua.state, -2);
|
|
||||||
}
|
|
||||||
return ffi::lua_touserdata(lua.state, -1)
|
|
||||||
== check_data.as_ptr() as *mut c_void;
|
|
||||||
}
|
}
|
||||||
|
return ffi::lua_touserdata(lua.state, -1)
|
||||||
|
== check_data.as_ptr() as *mut c_void;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,13 +260,13 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||||||
|
|
||||||
match method {
|
match method {
|
||||||
NonStaticMethod::Method(method) => {
|
NonStaticMethod::Method(method) => {
|
||||||
let method_data = data.clone();
|
|
||||||
let f = Box::new(move |lua, mut args: MultiValue<'callback>| {
|
let f = Box::new(move |lua, mut args: MultiValue<'callback>| {
|
||||||
if !check_ud_type(lua, args.pop_front()) {
|
if !check_ud_type(lua, args.pop_front()) {
|
||||||
return Err(Error::UserDataTypeMismatch);
|
return Err(Error::UserDataTypeMismatch);
|
||||||
}
|
}
|
||||||
let data = method_data
|
let data = data
|
||||||
.try_borrow()
|
.try_borrow()
|
||||||
|
.map(|cell| Ref::map(cell, AsRef::as_ref))
|
||||||
.map_err(|_| Error::UserDataBorrowError)?;
|
.map_err(|_| Error::UserDataBorrowError)?;
|
||||||
method(lua, &*data, args)
|
method(lua, &*data, args)
|
||||||
});
|
});
|
||||||
@@ -206,7 +274,6 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||||||
}
|
}
|
||||||
NonStaticMethod::MethodMut(method) => {
|
NonStaticMethod::MethodMut(method) => {
|
||||||
let method = RefCell::new(method);
|
let method = RefCell::new(method);
|
||||||
let method_data = data.clone();
|
|
||||||
let f = Box::new(move |lua, mut args: MultiValue<'callback>| {
|
let f = Box::new(move |lua, mut args: MultiValue<'callback>| {
|
||||||
if !check_ud_type(lua, args.pop_front()) {
|
if !check_ud_type(lua, args.pop_front()) {
|
||||||
return Err(Error::UserDataTypeMismatch);
|
return Err(Error::UserDataTypeMismatch);
|
||||||
@@ -214,8 +281,9 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||||||
let mut method = method
|
let mut method = method
|
||||||
.try_borrow_mut()
|
.try_borrow_mut()
|
||||||
.map_err(|_| Error::RecursiveMutCallback)?;
|
.map_err(|_| Error::RecursiveMutCallback)?;
|
||||||
let mut data = method_data
|
let mut data = data
|
||||||
.try_borrow_mut()
|
.try_borrow_mut()
|
||||||
|
.map(|cell| RefMut::map(cell, AsMut::as_mut))
|
||||||
.map_err(|_| Error::UserDataBorrowMutError)?;
|
.map_err(|_| Error::UserDataBorrowMutError)?;
|
||||||
(&mut *method)(lua, &mut *data, args)
|
(&mut *method)(lua, &mut *data, args)
|
||||||
});
|
});
|
||||||
@@ -245,15 +313,14 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||||||
assert_stack(lua.state, 6);
|
assert_stack(lua.state, 6);
|
||||||
|
|
||||||
push_userdata(lua.state, ())?;
|
push_userdata(lua.state, ())?;
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
ffi::lua_pushlightuserdata(lua.state, data.as_ptr() as *mut c_void);
|
ffi::lua_pushlightuserdata(lua.state, data.as_ptr() as *mut c_void);
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
protect_lua_closure(lua.state, 0, 1, |state| {
|
protect_lua_closure(lua.state, 0, 1, |state| {
|
||||||
// Lua 5.2/5.1 allows to store only table. Then we will wrap the value.
|
// Lua 5.2/5.1 allows to store only table. Then we will wrap the value.
|
||||||
ffi::lua_createtable(state, 1, 0);
|
ffi::lua_createtable(state, 1, 0);
|
||||||
ffi::lua_pushinteger(state, 1);
|
|
||||||
ffi::lua_pushlightuserdata(state, data.as_ptr() as *mut c_void);
|
ffi::lua_pushlightuserdata(state, data.as_ptr() as *mut c_void);
|
||||||
ffi::lua_settable(state, -3);
|
ffi::lua_rawseti(state, -2, 1);
|
||||||
})?;
|
})?;
|
||||||
ffi::lua_setuservalue(lua.state, -2);
|
ffi::lua_setuservalue(lua.state, -2);
|
||||||
|
|
||||||
@@ -312,18 +379,85 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||||||
assert_stack(state, 3);
|
assert_stack(state, 3);
|
||||||
f.lua.push_ref(&f);
|
f.lua.push_ref(&f);
|
||||||
|
|
||||||
ffi::lua_getupvalue(state, -1, 1);
|
|
||||||
// We know the destructor has not run yet because we hold a reference to the callback.
|
// We know the destructor has not run yet because we hold a reference to the callback.
|
||||||
let ud = take_userdata::<Callback>(state);
|
|
||||||
|
|
||||||
|
ffi::lua_getupvalue(state, -1, 1);
|
||||||
|
let ud1 = take_userdata::<Callback>(state);
|
||||||
ffi::lua_pushnil(state);
|
ffi::lua_pushnil(state);
|
||||||
ffi::lua_setupvalue(state, -2, 1);
|
ffi::lua_setupvalue(state, -2, 1);
|
||||||
|
|
||||||
|
ffi::lua_getupvalue(state, -1, 2);
|
||||||
|
let ud2 = take_userdata::<Lua>(state);
|
||||||
|
ffi::lua_pushnil(state);
|
||||||
|
ffi::lua_setupvalue(state, -2, 2);
|
||||||
|
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
Box::new(ud)
|
vec![Box::new(ud1), Box::new(ud2)]
|
||||||
}));
|
}));
|
||||||
Ok(f)
|
Ok(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
unsafe fn create_async_callback<'callback>(
|
||||||
|
&self,
|
||||||
|
f: AsyncCallback<'callback, 'scope>,
|
||||||
|
) -> Result<Function<'lua>> {
|
||||||
|
let f = mem::transmute::<AsyncCallback<'callback, 'scope>, AsyncCallback<'lua, 'static>>(f);
|
||||||
|
let f = self.lua.create_async_callback(f)?;
|
||||||
|
|
||||||
|
let mut destructors = self.destructors.borrow_mut();
|
||||||
|
destructors.push((f.0.clone(), |f| {
|
||||||
|
let state = f.lua.state;
|
||||||
|
assert_stack(state, 4);
|
||||||
|
f.lua.push_ref(&f);
|
||||||
|
|
||||||
|
// We know the destructor has not run yet because we hold a reference to the callback.
|
||||||
|
|
||||||
|
// First, get the environment table
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
|
ffi::lua_getupvalue(state, -1, 1);
|
||||||
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
|
ffi::lua_getfenv(state, -1);
|
||||||
|
|
||||||
|
// Second, get the `get_poll()` closure using the corresponding key
|
||||||
|
ffi::lua_pushstring(state, cstr!("get_poll"));
|
||||||
|
ffi::lua_rawget(state, -2);
|
||||||
|
|
||||||
|
// Destroy all upvalues
|
||||||
|
ffi::lua_getupvalue(state, -1, 1);
|
||||||
|
let ud1 = take_userdata::<AsyncCallback>(state);
|
||||||
|
ffi::lua_pushnil(state);
|
||||||
|
ffi::lua_setupvalue(state, -2, 1);
|
||||||
|
|
||||||
|
ffi::lua_getupvalue(state, -1, 2);
|
||||||
|
let ud2 = take_userdata::<Lua>(state);
|
||||||
|
ffi::lua_pushnil(state);
|
||||||
|
ffi::lua_setupvalue(state, -2, 2);
|
||||||
|
|
||||||
|
ffi::lua_pop(state, 1);
|
||||||
|
let mut data: Vec<Box<dyn Any>> = vec![Box::new(ud1), Box::new(ud2)];
|
||||||
|
|
||||||
|
// Finally, get polled future and destroy it
|
||||||
|
ffi::lua_pushstring(state, cstr!("poll"));
|
||||||
|
if ffi::lua_rawget(state, -2) == ffi::LUA_TFUNCTION {
|
||||||
|
ffi::lua_getupvalue(state, -1, 1);
|
||||||
|
let ud3 = take_userdata::<LocalBoxFuture<Result<MultiValue>>>(state);
|
||||||
|
ffi::lua_pushnil(state);
|
||||||
|
ffi::lua_setupvalue(state, -2, 1);
|
||||||
|
data.push(Box::new(ud3));
|
||||||
|
|
||||||
|
ffi::lua_getupvalue(state, -1, 2);
|
||||||
|
let ud4 = take_userdata::<Lua>(state);
|
||||||
|
ffi::lua_pushnil(state);
|
||||||
|
ffi::lua_setupvalue(state, -2, 2);
|
||||||
|
data.push(Box::new(ud4));
|
||||||
|
}
|
||||||
|
|
||||||
|
data
|
||||||
|
}));
|
||||||
|
|
||||||
|
Ok(f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua, 'scope> Drop for Scope<'lua, 'scope> {
|
impl<'lua, 'scope> Drop for Scope<'lua, 'scope> {
|
||||||
@@ -337,7 +471,7 @@ impl<'lua, 'scope> Drop for Scope<'lua, 'scope> {
|
|||||||
.destructors
|
.destructors
|
||||||
.get_mut()
|
.get_mut()
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.map(|(r, dest)| dest(r))
|
.flat_map(|(r, dest)| dest(r))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
drop(to_drop);
|
drop(to_drop);
|
||||||
@@ -368,10 +502,10 @@ impl<'lua, T: UserData> Default for NonStaticUserDataMethods<'lua, T> {
|
|||||||
impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'lua, T> {
|
impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'lua, T> {
|
||||||
fn add_method<S, A, R, M>(&mut self, name: &S, method: M)
|
fn add_method<S, A, R, M>(&mut self, name: &S, method: M)
|
||||||
where
|
where
|
||||||
S: ?Sized + AsRef<[u8]>,
|
S: AsRef<[u8]> + ?Sized,
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
M: 'static + Send + Fn(&'lua Lua, &T, A) -> Result<R>,
|
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
|
||||||
{
|
{
|
||||||
self.methods.push((
|
self.methods.push((
|
||||||
name.as_ref().to_vec(),
|
name.as_ref().to_vec(),
|
||||||
@@ -383,10 +517,10 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
|
|||||||
|
|
||||||
fn add_method_mut<S, A, R, M>(&mut self, name: &S, mut method: M)
|
fn add_method_mut<S, A, R, M>(&mut self, name: &S, mut method: M)
|
||||||
where
|
where
|
||||||
S: ?Sized + AsRef<[u8]>,
|
S: AsRef<[u8]> + ?Sized,
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
M: 'static + Send + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
||||||
{
|
{
|
||||||
self.methods.push((
|
self.methods.push((
|
||||||
name.as_ref().to_vec(),
|
name.as_ref().to_vec(),
|
||||||
@@ -396,12 +530,27 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_function<S, A, R, F>(&mut self, name: &S, function: F)
|
#[cfg(feature = "async")]
|
||||||
|
fn add_async_method<S, A, R, M, MR>(&mut self, _name: &S, _method: M)
|
||||||
where
|
where
|
||||||
S: ?Sized + AsRef<[u8]>,
|
T: Clone,
|
||||||
|
S: AsRef<[u8]> + ?Sized,
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
F: 'static + Send + Fn(&'lua Lua, A) -> Result<R>,
|
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
|
||||||
|
MR: 'lua + Future<Output = Result<R>>,
|
||||||
|
{
|
||||||
|
// The panic should never happen as async non-static code wouldn't compile
|
||||||
|
// Non-static lifetime must be bounded to 'lua lifetime
|
||||||
|
mlua_panic!("asynchronous methods are not supported for non-static userdata")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_function<S, A, R, F>(&mut self, name: &S, function: F)
|
||||||
|
where
|
||||||
|
S: AsRef<[u8]> + ?Sized,
|
||||||
|
A: FromLuaMulti<'lua>,
|
||||||
|
R: ToLuaMulti<'lua>,
|
||||||
|
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
|
||||||
{
|
{
|
||||||
self.methods.push((
|
self.methods.push((
|
||||||
name.as_ref().to_vec(),
|
name.as_ref().to_vec(),
|
||||||
@@ -413,10 +562,10 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
|
|||||||
|
|
||||||
fn add_function_mut<S, A, R, F>(&mut self, name: &S, mut function: F)
|
fn add_function_mut<S, A, R, F>(&mut self, name: &S, mut function: F)
|
||||||
where
|
where
|
||||||
S: ?Sized + AsRef<[u8]>,
|
S: AsRef<[u8]> + ?Sized,
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
F: 'static + Send + FnMut(&'lua Lua, A) -> Result<R>,
|
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
|
||||||
{
|
{
|
||||||
self.methods.push((
|
self.methods.push((
|
||||||
name.as_ref().to_vec(),
|
name.as_ref().to_vec(),
|
||||||
@@ -426,11 +575,26 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
fn add_async_function<S, A, R, F, FR>(&mut self, _name: &S, _function: F)
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
S: AsRef<[u8]> + ?Sized,
|
||||||
|
A: FromLuaMulti<'lua>,
|
||||||
|
R: ToLuaMulti<'lua>,
|
||||||
|
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
|
||||||
|
FR: 'lua + Future<Output = Result<R>>,
|
||||||
|
{
|
||||||
|
// The panic should never happen as async non-static code wouldn't compile
|
||||||
|
// Non-static lifetime must be bounded to 'lua lifetime
|
||||||
|
mlua_panic!("asynchronous functions are not supported for non-static userdata")
|
||||||
|
}
|
||||||
|
|
||||||
fn add_meta_method<A, R, M>(&mut self, meta: MetaMethod, method: M)
|
fn add_meta_method<A, R, M>(&mut self, meta: MetaMethod, method: M)
|
||||||
where
|
where
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
M: 'static + Send + Fn(&'lua Lua, &T, A) -> Result<R>,
|
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
|
||||||
{
|
{
|
||||||
self.meta_methods.push((
|
self.meta_methods.push((
|
||||||
meta,
|
meta,
|
||||||
@@ -444,7 +608,7 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
|
|||||||
where
|
where
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
M: 'static + Send + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
||||||
{
|
{
|
||||||
self.meta_methods.push((
|
self.meta_methods.push((
|
||||||
meta,
|
meta,
|
||||||
@@ -458,7 +622,7 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
|
|||||||
where
|
where
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
F: 'static + Send + Fn(&'lua Lua, A) -> Result<R>,
|
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
|
||||||
{
|
{
|
||||||
self.meta_methods.push((
|
self.meta_methods.push((
|
||||||
meta,
|
meta,
|
||||||
@@ -472,7 +636,7 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
|
|||||||
where
|
where
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
F: 'static + Send + FnMut(&'lua Lua, A) -> Result<R>,
|
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
|
||||||
{
|
{
|
||||||
self.meta_methods.push((
|
self.meta_methods.push((
|
||||||
meta,
|
meta,
|
||||||
|
|||||||
+329
@@ -0,0 +1,329 @@
|
|||||||
|
use std::string::String as StdString;
|
||||||
|
|
||||||
|
use serde::de::{self, IntoDeserializer};
|
||||||
|
|
||||||
|
use crate::error::{Error, Result};
|
||||||
|
use crate::table::{TablePairs, TableSequence};
|
||||||
|
use crate::value::Value;
|
||||||
|
|
||||||
|
/// A struct for deserializing Lua values into Rust values.
|
||||||
|
pub struct Deserializer<'lua>(pub Value<'lua>);
|
||||||
|
|
||||||
|
impl<'lua, 'de> serde::Deserializer<'de> for Deserializer<'lua> {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
match self.0 {
|
||||||
|
Value::Nil => visitor.visit_unit(),
|
||||||
|
Value::Boolean(b) => visitor.visit_bool(b),
|
||||||
|
#[allow(clippy::useless_conversion)]
|
||||||
|
Value::Integer(i) => visitor.visit_i64(i.into()),
|
||||||
|
#[allow(clippy::useless_conversion)]
|
||||||
|
Value::Number(n) => visitor.visit_f64(n.into()),
|
||||||
|
Value::String(s) => match s.to_str() {
|
||||||
|
Ok(s) => visitor.visit_str(s),
|
||||||
|
Err(_) => visitor.visit_bytes(s.as_bytes()),
|
||||||
|
},
|
||||||
|
Value::Table(ref t) if t.raw_len() > 0 || t.is_array() => self.deserialize_seq(visitor),
|
||||||
|
Value::Table(_) => self.deserialize_map(visitor),
|
||||||
|
Value::LightUserData(ud) if ud.0.is_null() => visitor.visit_none(),
|
||||||
|
Value::Function(_)
|
||||||
|
| Value::Thread(_)
|
||||||
|
| Value::UserData(_)
|
||||||
|
| Value::LightUserData(_)
|
||||||
|
| Value::Error(_) => Err(de::Error::custom("invalid value type")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
match self.0 {
|
||||||
|
Value::Nil => visitor.visit_none(),
|
||||||
|
Value::LightUserData(ud) if ud.0.is_null() => visitor.visit_none(),
|
||||||
|
_ => visitor.visit_some(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deserialize_enum<V>(
|
||||||
|
self,
|
||||||
|
_name: &str,
|
||||||
|
_variants: &'static [&'static str],
|
||||||
|
visitor: V,
|
||||||
|
) -> Result<V::Value>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
let (variant, value) = match self.0 {
|
||||||
|
Value::Table(value) => {
|
||||||
|
let mut iter = value.pairs::<StdString, Value>();
|
||||||
|
let (variant, value) = match iter.next() {
|
||||||
|
Some(v) => v?,
|
||||||
|
None => {
|
||||||
|
return Err(de::Error::invalid_value(
|
||||||
|
de::Unexpected::Map,
|
||||||
|
&"map with a single key",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if iter.next().is_some() {
|
||||||
|
return Err(de::Error::invalid_value(
|
||||||
|
de::Unexpected::Map,
|
||||||
|
&"map with a single key",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
(variant, Some(value))
|
||||||
|
}
|
||||||
|
Value::String(variant) => (variant.to_str()?.to_owned(), None),
|
||||||
|
_ => return Err(de::Error::custom("bad enum value")),
|
||||||
|
};
|
||||||
|
|
||||||
|
visitor.visit_enum(EnumDeserializer { variant, value })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
match self.0 {
|
||||||
|
Value::Table(t) => {
|
||||||
|
let len = t.raw_len() as usize;
|
||||||
|
let mut deserializer = SeqDeserializer(t.raw_sequence_values());
|
||||||
|
let seq = visitor.visit_seq(&mut deserializer)?;
|
||||||
|
if deserializer.0.count() == 0 {
|
||||||
|
Ok(seq)
|
||||||
|
} else {
|
||||||
|
Err(de::Error::invalid_length(
|
||||||
|
len,
|
||||||
|
&"fewer elements in the table",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(de::Error::custom("invalid value type")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
self.deserialize_seq(visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deserialize_tuple_struct<V>(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_len: usize,
|
||||||
|
visitor: V,
|
||||||
|
) -> Result<V::Value>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
self.deserialize_seq(visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
match self.0 {
|
||||||
|
Value::Table(t) => {
|
||||||
|
let mut deserializer = MapDeserializer::new(t.pairs());
|
||||||
|
let map = visitor.visit_map(&mut deserializer)?;
|
||||||
|
let count = deserializer.pairs.count();
|
||||||
|
if count == 0 {
|
||||||
|
Ok(map)
|
||||||
|
} else {
|
||||||
|
Err(de::Error::invalid_length(
|
||||||
|
deserializer.processed + count,
|
||||||
|
&"fewer elements in the table",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(de::Error::custom("invalid value type")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deserialize_struct<V>(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_fields: &'static [&'static str],
|
||||||
|
visitor: V,
|
||||||
|
) -> Result<V::Value>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
self.deserialize_map(visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
serde::forward_to_deserialize_any! {
|
||||||
|
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||||
|
byte_buf unit unit_struct newtype_struct
|
||||||
|
identifier ignored_any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SeqDeserializer<'lua>(TableSequence<'lua, Value<'lua>>);
|
||||||
|
|
||||||
|
impl<'lua, 'de> de::SeqAccess<'de> for SeqDeserializer<'lua> {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
|
||||||
|
where
|
||||||
|
T: de::DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
match self.0.next() {
|
||||||
|
Some(value) => seed.deserialize(Deserializer(value?)).map(Some),
|
||||||
|
None => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> Option<usize> {
|
||||||
|
match self.0.size_hint() {
|
||||||
|
(lower, Some(upper)) if lower == upper => Some(upper),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MapDeserializer<'lua> {
|
||||||
|
pairs: TablePairs<'lua, Value<'lua>, Value<'lua>>,
|
||||||
|
value: Option<Value<'lua>>,
|
||||||
|
processed: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> MapDeserializer<'lua> {
|
||||||
|
fn new(pairs: TablePairs<'lua, Value<'lua>, Value<'lua>>) -> Self {
|
||||||
|
MapDeserializer {
|
||||||
|
pairs,
|
||||||
|
value: None,
|
||||||
|
processed: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua, 'de> de::MapAccess<'de> for MapDeserializer<'lua> {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
|
||||||
|
where
|
||||||
|
T: de::DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
match self.pairs.next() {
|
||||||
|
Some(item) => {
|
||||||
|
let (key, value) = item?;
|
||||||
|
self.processed += 1;
|
||||||
|
self.value = Some(value);
|
||||||
|
let key_de = Deserializer(key);
|
||||||
|
seed.deserialize(key_de).map(Some)
|
||||||
|
}
|
||||||
|
None => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value>
|
||||||
|
where
|
||||||
|
T: de::DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
match self.value.take() {
|
||||||
|
Some(value) => seed.deserialize(Deserializer(value)),
|
||||||
|
None => Err(de::Error::custom("value is missing")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> Option<usize> {
|
||||||
|
match self.pairs.size_hint() {
|
||||||
|
(lower, Some(upper)) if lower == upper => Some(upper),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EnumDeserializer<'lua> {
|
||||||
|
variant: StdString,
|
||||||
|
value: Option<Value<'lua>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua, 'de> de::EnumAccess<'de> for EnumDeserializer<'lua> {
|
||||||
|
type Error = Error;
|
||||||
|
type Variant = VariantDeserializer<'lua>;
|
||||||
|
|
||||||
|
fn variant_seed<T>(self, seed: T) -> Result<(T::Value, Self::Variant)>
|
||||||
|
where
|
||||||
|
T: de::DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
let variant = self.variant.into_deserializer();
|
||||||
|
let variant_access = VariantDeserializer { value: self.value };
|
||||||
|
seed.deserialize(variant).map(|v| (v, variant_access))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VariantDeserializer<'lua> {
|
||||||
|
value: Option<Value<'lua>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua, 'de> de::VariantAccess<'de> for VariantDeserializer<'lua> {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn unit_variant(self) -> Result<()> {
|
||||||
|
match self.value {
|
||||||
|
Some(_) => Err(de::Error::invalid_type(
|
||||||
|
de::Unexpected::NewtypeVariant,
|
||||||
|
&"unit variant",
|
||||||
|
)),
|
||||||
|
None => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
|
||||||
|
where
|
||||||
|
T: de::DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
match self.value {
|
||||||
|
Some(value) => seed.deserialize(Deserializer(value)),
|
||||||
|
None => Err(de::Error::invalid_type(
|
||||||
|
de::Unexpected::UnitVariant,
|
||||||
|
&"newtype variant",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
match self.value {
|
||||||
|
Some(value) => serde::Deserializer::deserialize_seq(Deserializer(value), visitor),
|
||||||
|
None => Err(de::Error::invalid_type(
|
||||||
|
de::Unexpected::UnitVariant,
|
||||||
|
&"tuple variant",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_variant<V>(self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
match self.value {
|
||||||
|
Some(value) => serde::Deserializer::deserialize_map(Deserializer(value), visitor),
|
||||||
|
None => Err(de::Error::invalid_type(
|
||||||
|
de::Unexpected::UnitVariant,
|
||||||
|
&"struct variant",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
//! (De)Serialization support using serde.
|
||||||
|
|
||||||
|
use std::os::raw::{c_int, c_void};
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::error::Result;
|
||||||
|
use crate::ffi;
|
||||||
|
use crate::lua::Lua;
|
||||||
|
use crate::table::Table;
|
||||||
|
use crate::util::{assert_stack, protect_lua, StackGuard};
|
||||||
|
use crate::value::Value;
|
||||||
|
|
||||||
|
pub trait LuaSerdeExt<'lua> {
|
||||||
|
/// A special value (lightuserdata) to encode/decode optional (none) values.
|
||||||
|
///
|
||||||
|
/// Requires `feature = "serialize"`
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::collections::HashMap;
|
||||||
|
/// use mlua::{Lua, Result, LuaSerdeExt};
|
||||||
|
///
|
||||||
|
/// fn main() -> Result<()> {
|
||||||
|
/// let lua = Lua::new();
|
||||||
|
/// lua.globals().set("null", lua.null()?)?;
|
||||||
|
///
|
||||||
|
/// let val = lua.load(r#"{a = null}"#).eval()?;
|
||||||
|
/// let map: HashMap<String, Option<String>> = lua.from_value(val)?;
|
||||||
|
/// assert_eq!(map["a"], None);
|
||||||
|
///
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn null(&'lua self) -> Result<Value<'lua>>;
|
||||||
|
|
||||||
|
/// A metatable attachable to a Lua table to systematically encode it as Array (instead of Map).
|
||||||
|
/// As result, encoded Array will contain only sequence part of the table, with the same length
|
||||||
|
/// as the `#` operator on that table.
|
||||||
|
///
|
||||||
|
/// Requires `feature = "serialize"`
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use mlua::{Lua, Result, LuaSerdeExt};
|
||||||
|
/// use serde_json::Value as JsonValue;
|
||||||
|
///
|
||||||
|
/// fn main() -> Result<()> {
|
||||||
|
/// let lua = Lua::new();
|
||||||
|
/// lua.globals().set("array_mt", lua.array_metatable()?)?;
|
||||||
|
///
|
||||||
|
/// // Encode as an empty array (no sequence part in the lua table)
|
||||||
|
/// let val = lua.load("setmetatable({a = 5}, array_mt)").eval()?;
|
||||||
|
/// let j: JsonValue = lua.from_value(val)?;
|
||||||
|
/// assert_eq!(j.to_string(), "[]");
|
||||||
|
///
|
||||||
|
/// // Encode as object
|
||||||
|
/// let val = lua.load("{a = 5}").eval()?;
|
||||||
|
/// let j: JsonValue = lua.from_value(val)?;
|
||||||
|
/// assert_eq!(j.to_string(), r#"{"a":5}"#);
|
||||||
|
///
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn array_metatable(&'lua self) -> Result<Table<'lua>>;
|
||||||
|
|
||||||
|
/// Converts `T` into a `Value` instance.
|
||||||
|
///
|
||||||
|
/// Requires `feature = "serialize"`
|
||||||
|
///
|
||||||
|
/// [`Value`]: enum.Value.html
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use mlua::{Lua, Result, LuaSerdeExt};
|
||||||
|
/// use serde::Serialize;
|
||||||
|
///
|
||||||
|
/// #[derive(Serialize)]
|
||||||
|
/// struct User {
|
||||||
|
/// name: String,
|
||||||
|
/// age: u8,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() -> Result<()> {
|
||||||
|
/// let lua = Lua::new();
|
||||||
|
/// let u = User {
|
||||||
|
/// name: "John Smith".into(),
|
||||||
|
/// age: 20,
|
||||||
|
/// };
|
||||||
|
/// lua.globals().set("user", lua.to_value(&u)?)?;
|
||||||
|
/// lua.load(r#"
|
||||||
|
/// assert(user["name"] == "John Smith")
|
||||||
|
/// assert(user["age"] == 20)
|
||||||
|
/// "#).exec()
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn to_value<T: Serialize + ?Sized>(&'lua self, t: &T) -> Result<Value<'lua>>;
|
||||||
|
|
||||||
|
/// Deserializes a `Value` into any serde deserializable object.
|
||||||
|
///
|
||||||
|
/// Requires `feature = "serialize"`
|
||||||
|
///
|
||||||
|
/// [`Value`]: enum.Value.html
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use mlua::{Lua, Result, LuaSerdeExt};
|
||||||
|
/// use serde::Deserialize;
|
||||||
|
///
|
||||||
|
/// #[derive(Deserialize, Debug, PartialEq)]
|
||||||
|
/// struct User {
|
||||||
|
/// name: String,
|
||||||
|
/// age: u8,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() -> Result<()> {
|
||||||
|
/// let lua = Lua::new();
|
||||||
|
/// let val = lua.load(r#"{name = "John Smith", age = 20}"#).eval()?;
|
||||||
|
/// let u: User = lua.from_value(val)?;
|
||||||
|
///
|
||||||
|
/// assert_eq!(u, User { name: "John Smith".into(), age: 20 });
|
||||||
|
///
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn from_value<T: Deserialize<'lua>>(&'lua self, value: Value<'lua>) -> Result<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> LuaSerdeExt<'lua> for Lua {
|
||||||
|
fn null(&'lua self) -> Result<Value<'lua>> {
|
||||||
|
unsafe {
|
||||||
|
let _sg = StackGuard::new(self.state);
|
||||||
|
assert_stack(self.state, 3);
|
||||||
|
|
||||||
|
unsafe extern "C" fn push_null(state: *mut ffi::lua_State) -> c_int {
|
||||||
|
ffi::lua_pushlightuserdata(state, ptr::null_mut());
|
||||||
|
1
|
||||||
|
}
|
||||||
|
protect_lua(self.state, 0, push_null)?;
|
||||||
|
Ok(self.pop_value())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn array_metatable(&'lua self) -> Result<Table<'lua>> {
|
||||||
|
unsafe {
|
||||||
|
let _sg = StackGuard::new(self.state);
|
||||||
|
assert_stack(self.state, 3);
|
||||||
|
|
||||||
|
unsafe extern "C" fn get_array_mt(state: *mut ffi::lua_State) -> c_int {
|
||||||
|
push_array_metatable(state);
|
||||||
|
1
|
||||||
|
}
|
||||||
|
protect_lua(self.state, 0, get_array_mt)?;
|
||||||
|
Ok(Table(self.pop_ref()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_value<T>(&'lua self, t: &T) -> Result<Value<'lua>>
|
||||||
|
where
|
||||||
|
T: Serialize + ?Sized,
|
||||||
|
{
|
||||||
|
t.serialize(ser::Serializer(self))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_value<T>(&'lua self, value: Value<'lua>) -> Result<T>
|
||||||
|
where
|
||||||
|
T: Deserialize<'lua>,
|
||||||
|
{
|
||||||
|
T::deserialize(de::Deserializer(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn init_metatables(state: *mut ffi::lua_State) {
|
||||||
|
ffi::lua_pushlightuserdata(
|
||||||
|
state,
|
||||||
|
&ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void,
|
||||||
|
);
|
||||||
|
ffi::lua_newtable(state);
|
||||||
|
|
||||||
|
ffi::lua_pushstring(state, cstr!("__metatable"));
|
||||||
|
ffi::lua_pushboolean(state, 0);
|
||||||
|
ffi::lua_rawset(state, -3);
|
||||||
|
|
||||||
|
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn push_array_metatable(state: *mut ffi::lua_State) {
|
||||||
|
let key = &ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void;
|
||||||
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ARRAY_METATABLE_REGISTRY_KEY: u8 = 0;
|
||||||
|
|
||||||
|
pub mod de;
|
||||||
|
pub mod ser;
|
||||||
@@ -0,0 +1,366 @@
|
|||||||
|
use std::os::raw::c_int;
|
||||||
|
|
||||||
|
use serde::{ser, Serialize};
|
||||||
|
|
||||||
|
use super::LuaSerdeExt;
|
||||||
|
use crate::error::{Error, Result};
|
||||||
|
use crate::ffi;
|
||||||
|
use crate::lua::Lua;
|
||||||
|
use crate::string::String;
|
||||||
|
use crate::table::Table;
|
||||||
|
use crate::types::Integer;
|
||||||
|
use crate::util::{assert_stack, protect_lua, StackGuard};
|
||||||
|
use crate::value::{ToLua, Value};
|
||||||
|
|
||||||
|
/// A struct for serializing Rust values into Lua values.
|
||||||
|
pub struct Serializer<'lua>(pub &'lua Lua);
|
||||||
|
|
||||||
|
macro_rules! lua_serialize_number {
|
||||||
|
($name:ident, $t:ty) => {
|
||||||
|
#[inline]
|
||||||
|
fn $name(self, value: $t) -> Result<Value<'lua>> {
|
||||||
|
value.to_lua(self.0)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> ser::Serializer for Serializer<'lua> {
|
||||||
|
type Ok = Value<'lua>;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
// Associated types for keeping track of additional state while serializing
|
||||||
|
// compound data structures like sequences and maps.
|
||||||
|
type SerializeSeq = SerializeVec<'lua>;
|
||||||
|
type SerializeTuple = SerializeVec<'lua>;
|
||||||
|
type SerializeTupleStruct = SerializeVec<'lua>;
|
||||||
|
type SerializeTupleVariant = SerializeTupleVariant<'lua>;
|
||||||
|
type SerializeMap = SerializeMap<'lua>;
|
||||||
|
type SerializeStruct = SerializeMap<'lua>;
|
||||||
|
type SerializeStructVariant = SerializeStructVariant<'lua>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_bool(self, value: bool) -> Result<Value<'lua>> {
|
||||||
|
Ok(Value::Boolean(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_serialize_number!(serialize_i8, i8);
|
||||||
|
lua_serialize_number!(serialize_u8, u8);
|
||||||
|
lua_serialize_number!(serialize_i16, i16);
|
||||||
|
lua_serialize_number!(serialize_u16, u16);
|
||||||
|
lua_serialize_number!(serialize_i32, i32);
|
||||||
|
lua_serialize_number!(serialize_u32, u32);
|
||||||
|
lua_serialize_number!(serialize_i64, i64);
|
||||||
|
lua_serialize_number!(serialize_u64, u64);
|
||||||
|
|
||||||
|
lua_serialize_number!(serialize_f32, f32);
|
||||||
|
lua_serialize_number!(serialize_f64, f64);
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_char(self, value: char) -> Result<Value<'lua>> {
|
||||||
|
self.serialize_str(&value.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_str(self, value: &str) -> Result<Value<'lua>> {
|
||||||
|
self.0.create_string(value).map(Value::String)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_bytes(self, value: &[u8]) -> Result<Value<'lua>> {
|
||||||
|
self.0.create_string(value).map(Value::String)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_none(self) -> Result<Value<'lua>> {
|
||||||
|
self.0.null()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_some<T>(self, value: &T) -> Result<Value<'lua>>
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
value.serialize(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_unit(self) -> Result<Value<'lua>> {
|
||||||
|
self.0.null()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_unit_struct(self, _name: &'static str) -> Result<Value<'lua>> {
|
||||||
|
self.0.null()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_unit_variant(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
variant: &'static str,
|
||||||
|
) -> Result<Value<'lua>> {
|
||||||
|
self.serialize_str(variant)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<Value<'lua>>
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
value.serialize(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_newtype_variant<T>(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
variant: &'static str,
|
||||||
|
value: &T,
|
||||||
|
) -> Result<Value<'lua>>
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
let table = self.0.create_table()?;
|
||||||
|
let variant = self.0.create_string(variant)?;
|
||||||
|
let value = self.0.to_value(value)?;
|
||||||
|
table.raw_set(variant, value)?;
|
||||||
|
Ok(Value::Table(table))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
|
||||||
|
let len = len.unwrap_or(0) as c_int;
|
||||||
|
let table = self.0.create_table_with_capacity(len, 0)?;
|
||||||
|
table.set_metatable(Some(self.0.array_metatable()?));
|
||||||
|
Ok(SerializeVec { table })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
|
||||||
|
self.serialize_seq(Some(len))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_tuple_struct(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
len: usize,
|
||||||
|
) -> Result<Self::SerializeTupleStruct> {
|
||||||
|
self.serialize_seq(Some(len))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_tuple_variant(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
variant: &'static str,
|
||||||
|
_len: usize,
|
||||||
|
) -> Result<Self::SerializeTupleVariant> {
|
||||||
|
let name = self.0.create_string(variant)?;
|
||||||
|
let table = self.0.create_table()?;
|
||||||
|
Ok(SerializeTupleVariant { name, table })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
|
||||||
|
let len = len.unwrap_or(0) as c_int;
|
||||||
|
Ok(SerializeMap {
|
||||||
|
key: None,
|
||||||
|
table: self.0.create_table_with_capacity(0, len)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
|
||||||
|
self.serialize_map(Some(len))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_struct_variant(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
variant: &'static str,
|
||||||
|
len: usize,
|
||||||
|
) -> Result<Self::SerializeStructVariant> {
|
||||||
|
let name = self.0.create_string(variant)?;
|
||||||
|
let table = self.0.create_table_with_capacity(0, len as c_int)?;
|
||||||
|
Ok(SerializeStructVariant { name, table })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SerializeVec<'lua> {
|
||||||
|
table: Table<'lua>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> ser::SerializeSeq for SerializeVec<'lua> {
|
||||||
|
type Ok = Value<'lua>;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_element<T>(&mut self, value: &T) -> Result<()>
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
let lua = self.table.0.lua;
|
||||||
|
let value = lua.to_value(value)?;
|
||||||
|
unsafe {
|
||||||
|
let _sg = StackGuard::new(lua.state);
|
||||||
|
assert_stack(lua.state, 4);
|
||||||
|
|
||||||
|
lua.push_ref(&self.table.0);
|
||||||
|
lua.push_value(value)?;
|
||||||
|
|
||||||
|
unsafe extern "C" fn push_to_table(state: *mut ffi::lua_State) -> c_int {
|
||||||
|
let len = ffi::lua_rawlen(state, -2) as Integer;
|
||||||
|
ffi::lua_rawseti(state, -2, len + 1);
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
protect_lua(lua.state, 2, push_to_table)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Value<'lua>> {
|
||||||
|
Ok(Value::Table(self.table))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> ser::SerializeTuple for SerializeVec<'lua> {
|
||||||
|
type Ok = Value<'lua>;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_element<T>(&mut self, value: &T) -> Result<()>
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
ser::SerializeSeq::serialize_element(self, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Value<'lua>> {
|
||||||
|
ser::SerializeSeq::end(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> ser::SerializeTupleStruct for SerializeVec<'lua> {
|
||||||
|
type Ok = Value<'lua>;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_field<T>(&mut self, value: &T) -> Result<()>
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
ser::SerializeSeq::serialize_element(self, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Value<'lua>> {
|
||||||
|
ser::SerializeSeq::end(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SerializeTupleVariant<'lua> {
|
||||||
|
name: String<'lua>,
|
||||||
|
table: Table<'lua>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> ser::SerializeTupleVariant for SerializeTupleVariant<'lua> {
|
||||||
|
type Ok = Value<'lua>;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_field<T>(&mut self, value: &T) -> Result<()>
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
let lua = self.table.0.lua;
|
||||||
|
let idx = self.table.raw_len() + 1;
|
||||||
|
self.table.raw_insert(idx, lua.to_value(value)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Value<'lua>> {
|
||||||
|
let lua = self.table.0.lua;
|
||||||
|
let table = lua.create_table()?;
|
||||||
|
table.raw_set(self.name, self.table)?;
|
||||||
|
Ok(Value::Table(table))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SerializeMap<'lua> {
|
||||||
|
table: Table<'lua>,
|
||||||
|
key: Option<Value<'lua>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> ser::SerializeMap for SerializeMap<'lua> {
|
||||||
|
type Ok = Value<'lua>;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_key<T>(&mut self, key: &T) -> Result<()>
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
let lua = self.table.0.lua;
|
||||||
|
self.key = Some(lua.to_value(key)?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_value<T>(&mut self, value: &T) -> Result<()>
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
let lua = self.table.0.lua;
|
||||||
|
let key = mlua_expect!(
|
||||||
|
self.key.take(),
|
||||||
|
"serialize_value called before serialize_key"
|
||||||
|
);
|
||||||
|
let value = lua.to_value(value)?;
|
||||||
|
self.table.raw_set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Value<'lua>> {
|
||||||
|
Ok(Value::Table(self.table))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> ser::SerializeStruct for SerializeMap<'lua> {
|
||||||
|
type Ok = Value<'lua>;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
ser::SerializeMap::serialize_key(self, key)?;
|
||||||
|
ser::SerializeMap::serialize_value(self, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Value<'lua>> {
|
||||||
|
ser::SerializeMap::end(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SerializeStructVariant<'lua> {
|
||||||
|
name: String<'lua>,
|
||||||
|
table: Table<'lua>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> ser::SerializeStructVariant for SerializeStructVariant<'lua> {
|
||||||
|
type Ok = Value<'lua>;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
let lua = self.table.0.lua;
|
||||||
|
self.table.raw_set(key, lua.to_value(value)?)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Value<'lua>> {
|
||||||
|
let lua = self.table.0.lua;
|
||||||
|
let table = lua.create_table()?;
|
||||||
|
table.raw_set(self.name, self.table)?;
|
||||||
|
Ok(Value::Table(table))
|
||||||
|
}
|
||||||
|
}
|
||||||
+37
-10
@@ -1,31 +1,58 @@
|
|||||||
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign};
|
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign};
|
||||||
use std::u32;
|
use std::u32;
|
||||||
|
|
||||||
/// Flags describing the set of lua modules to load.
|
/// Flags describing the set of lua standard libraries to load.
|
||||||
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
pub struct StdLib(u32);
|
pub struct StdLib(u32);
|
||||||
|
|
||||||
impl StdLib {
|
impl StdLib {
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
/// [`coroutine`](https://www.lua.org/manual/5.3/manual.html#6.2) library
|
||||||
pub const COROUTINE: StdLib = StdLib(1 << 0);
|
///
|
||||||
|
/// Requires `feature = "lua54/lua53/lua52"`
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", doc))]
|
||||||
|
pub const COROUTINE: StdLib = StdLib(1);
|
||||||
|
/// [`table`](https://www.lua.org/manual/5.3/manual.html#6.6) library
|
||||||
pub const TABLE: StdLib = StdLib(1 << 1);
|
pub const TABLE: StdLib = StdLib(1 << 1);
|
||||||
|
/// [`io`](https://www.lua.org/manual/5.3/manual.html#6.8) library
|
||||||
pub const IO: StdLib = StdLib(1 << 2);
|
pub const IO: StdLib = StdLib(1 << 2);
|
||||||
|
/// [`os`](https://www.lua.org/manual/5.3/manual.html#6.9) library
|
||||||
pub const OS: StdLib = StdLib(1 << 3);
|
pub const OS: StdLib = StdLib(1 << 3);
|
||||||
|
/// [`string`](https://www.lua.org/manual/5.3/manual.html#6.4) library
|
||||||
pub const STRING: StdLib = StdLib(1 << 4);
|
pub const STRING: StdLib = StdLib(1 << 4);
|
||||||
#[cfg(feature = "lua53")]
|
/// [`utf8`](https://www.lua.org/manual/5.3/manual.html#6.5) library
|
||||||
|
///
|
||||||
|
/// Requires `feature = "lua54/lua53"`
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||||
pub const UTF8: StdLib = StdLib(1 << 5);
|
pub const UTF8: StdLib = StdLib(1 << 5);
|
||||||
#[cfg(any(feature = "lua52", feature = "luajit"))]
|
/// [`bit`](https://www.lua.org/manual/5.2/manual.html#6.7) library
|
||||||
|
///
|
||||||
|
/// Requires `feature = "lua52/luajit"`
|
||||||
|
#[cfg(any(feature = "lua52", feature = "luajit", doc))]
|
||||||
pub const BIT: StdLib = StdLib(1 << 6);
|
pub const BIT: StdLib = StdLib(1 << 6);
|
||||||
|
/// [`math`](https://www.lua.org/manual/5.3/manual.html#6.7) library
|
||||||
pub const MATH: StdLib = StdLib(1 << 7);
|
pub const MATH: StdLib = StdLib(1 << 7);
|
||||||
|
/// [`package`](https://www.lua.org/manual/5.3/manual.html#6.3) library
|
||||||
pub const PACKAGE: StdLib = StdLib(1 << 8);
|
pub const PACKAGE: StdLib = StdLib(1 << 8);
|
||||||
#[cfg(feature = "luajit")]
|
/// [`jit`](http://luajit.org/ext_jit.html) library
|
||||||
|
///
|
||||||
|
/// Requires `feature = "luajit"`
|
||||||
|
#[cfg(any(feature = "luajit", doc))]
|
||||||
pub const JIT: StdLib = StdLib(1 << 9);
|
pub const JIT: StdLib = StdLib(1 << 9);
|
||||||
#[cfg(feature = "luajit")]
|
|
||||||
pub const FFI: StdLib = StdLib(1 << 10);
|
|
||||||
pub const DEBUG: StdLib = StdLib(1 << 31); // always highest bit
|
|
||||||
|
|
||||||
|
/// (unsafe) [`ffi`](http://luajit.org/ext_ffi.html) library
|
||||||
|
///
|
||||||
|
/// Requires `feature = "luajit"`
|
||||||
|
#[cfg(any(feature = "luajit", doc))]
|
||||||
|
pub const FFI: StdLib = StdLib(1 << 30);
|
||||||
|
/// (unsafe) [`debug`](https://www.lua.org/manual/5.3/manual.html#6.10) library
|
||||||
|
pub const DEBUG: StdLib = StdLib(1 << 31);
|
||||||
|
|
||||||
|
/// No libraries
|
||||||
|
pub const NONE: StdLib = StdLib(0);
|
||||||
|
/// (unsafe) All standard libraries
|
||||||
pub const ALL: StdLib = StdLib(u32::MAX);
|
pub const ALL: StdLib = StdLib(u32::MAX);
|
||||||
pub const ALL_NO_DEBUG: StdLib = StdLib((1 << 31) - 1);
|
/// The safe subset of the standard libraries
|
||||||
|
pub const ALL_SAFE: StdLib = StdLib((1 << 30) - 1);
|
||||||
|
|
||||||
pub fn contains(self, lib: Self) -> bool {
|
pub fn contains(self, lib: Self) -> bool {
|
||||||
(self & lib).0 != 0
|
(self & lib).0 != 0
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
use std::{slice, str};
|
use std::{slice, str};
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
use {
|
||||||
|
serde::ser::{Serialize, Serializer},
|
||||||
|
std::result::Result as StdResult,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
use crate::types::LuaRef;
|
use crate::types::LuaRef;
|
||||||
@@ -105,3 +111,16 @@ where
|
|||||||
self.as_bytes() == other.as_ref()
|
self.as_bytes() == other.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
impl<'lua> Serialize for String<'lua> {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
match self.to_str() {
|
||||||
|
Ok(s) => serializer.serialize_str(s),
|
||||||
|
Err(_) => serializer.serialize_bytes(self.as_bytes()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+212
-42
@@ -1,6 +1,12 @@
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::os::raw::c_int;
|
use std::os::raw::c_int;
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
use {
|
||||||
|
serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer},
|
||||||
|
std::result::Result as StdResult,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
use crate::function::Function;
|
use crate::function::Function;
|
||||||
@@ -8,10 +14,14 @@ use crate::types::{Integer, LuaRef};
|
|||||||
use crate::util::{assert_stack, protect_lua, protect_lua_closure, StackGuard};
|
use crate::util::{assert_stack, protect_lua, protect_lua_closure, StackGuard};
|
||||||
use crate::value::{FromLua, FromLuaMulti, Nil, ToLua, ToLuaMulti, Value};
|
use crate::value::{FromLua, FromLuaMulti, Nil, ToLua, ToLuaMulti, Value};
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
use {futures_core::future::LocalBoxFuture, futures_util::future};
|
||||||
|
|
||||||
/// Handle to an internal Lua table.
|
/// Handle to an internal Lua table.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Table<'lua>(pub(crate) LuaRef<'lua>);
|
pub struct Table<'lua>(pub(crate) LuaRef<'lua>);
|
||||||
|
|
||||||
|
#[allow(clippy::len_without_is_empty)]
|
||||||
impl<'lua> Table<'lua> {
|
impl<'lua> Table<'lua> {
|
||||||
/// Sets a key-value pair in the table.
|
/// Sets a key-value pair in the table.
|
||||||
///
|
///
|
||||||
@@ -133,39 +143,6 @@ impl<'lua> Table<'lua> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the function associated to `key` from the table and executes it,
|
|
||||||
/// passing the table itself as the first argument.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// Execute the table method with name "concat":
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use mlua::{Lua, Result, Table};
|
|
||||||
/// # fn main() -> Result<()> {
|
|
||||||
/// # let lua = Lua::new();
|
|
||||||
/// # let object = lua.create_table()?;
|
|
||||||
/// # let concat = lua.create_function(|_, (_, a, b): (Table, String, String)| Ok(a + &b))?;
|
|
||||||
/// # object.set("concat", concat)?;
|
|
||||||
/// // simiar to: object:concat("param1", "param2")
|
|
||||||
/// object.call("concat", ("param1", "param2"))?;
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// This might invoke the `__index` metamethod.
|
|
||||||
pub fn call<K, A, R>(&self, key: K, args: A) -> Result<R>
|
|
||||||
where
|
|
||||||
K: ToLua<'lua>,
|
|
||||||
A: ToLuaMulti<'lua>,
|
|
||||||
R: FromLuaMulti<'lua>,
|
|
||||||
{
|
|
||||||
let lua = self.0.lua;
|
|
||||||
let mut args = args.to_lua_multi(lua)?;
|
|
||||||
args.push_front(Value::Table(self.clone()));
|
|
||||||
self.get::<_, Function>(key)?.call(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compares two tables for equality.
|
/// Compares two tables for equality.
|
||||||
///
|
///
|
||||||
/// Tables are compared by reference first.
|
/// Tables are compared by reference first.
|
||||||
@@ -262,7 +239,7 @@ impl<'lua> Table<'lua> {
|
|||||||
V::from_lua(value, lua)
|
V::from_lua(value, lua)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts element value at position idx to the table, shifting up the elements from table[idx].
|
/// 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.
|
/// 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<()> {
|
pub fn raw_insert<V: ToLua<'lua>>(&self, idx: Integer, value: V) -> Result<()> {
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
@@ -292,11 +269,11 @@ impl<'lua> Table<'lua> {
|
|||||||
|
|
||||||
/// Removes a key from the table.
|
/// Removes a key from the table.
|
||||||
///
|
///
|
||||||
/// If `key` is an integer, mlua shifts down the elements from table[key+1],
|
/// 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,
|
/// and erases element `table[key]`. The complexity is O(n) in worst case,
|
||||||
/// where n is the table length.
|
/// where n is the table length.
|
||||||
///
|
///
|
||||||
/// For othey key types this is equivalent to setting table[key] = nil.
|
/// For othey key types this is equivalent to setting `table[key] = nil`.
|
||||||
pub fn raw_remove<K: ToLua<'lua>>(&self, key: K) -> Result<()> {
|
pub fn raw_remove<K: ToLua<'lua>>(&self, key: K) -> Result<()> {
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
let key = key.to_lua(lua)?;
|
let key = key.to_lua(lua)?;
|
||||||
@@ -476,9 +453,53 @@ impl<'lua> Table<'lua> {
|
|||||||
TableSequence {
|
TableSequence {
|
||||||
table: self.0,
|
table: self.0,
|
||||||
index: Some(1),
|
index: Some(1),
|
||||||
|
len: None,
|
||||||
|
raw: false,
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consume this table and return an iterator over all values in the sequence part of the table.
|
||||||
|
///
|
||||||
|
/// Unlike the `sequence_values`, does not invoke `__index` metamethod when iterating.
|
||||||
|
///
|
||||||
|
/// [`sequence_values`]: #method.sequence_values
|
||||||
|
pub fn raw_sequence_values<V: FromLua<'lua>>(self) -> TableSequence<'lua, V> {
|
||||||
|
TableSequence {
|
||||||
|
table: self.0,
|
||||||
|
index: Some(1),
|
||||||
|
len: None,
|
||||||
|
raw: true,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
pub(crate) fn raw_sequence_values_by_len<V: FromLua<'lua>>(self) -> TableSequence<'lua, V> {
|
||||||
|
let len = self.raw_len();
|
||||||
|
TableSequence {
|
||||||
|
table: self.0,
|
||||||
|
index: Some(1),
|
||||||
|
len: Some(len),
|
||||||
|
raw: true,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
pub(crate) fn is_array(&self) -> bool {
|
||||||
|
let lua = self.0.lua;
|
||||||
|
unsafe {
|
||||||
|
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 false;
|
||||||
|
}
|
||||||
|
crate::serde::push_array_metatable(lua.state);
|
||||||
|
ffi::lua_rawequal(lua.state, -1, -2) != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> PartialEq for Table<'lua> {
|
impl<'lua> PartialEq for Table<'lua> {
|
||||||
@@ -494,6 +515,148 @@ impl<'lua> AsRef<Table<'lua>> for Table<'lua> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An extension trait for `Table`s that provides a variety of convenient functionality.
|
||||||
|
pub trait TableExt<'lua> {
|
||||||
|
/// Gets the function associated to `key` from the table and executes it,
|
||||||
|
/// passing the table itself along with `args` as function arguments.
|
||||||
|
///
|
||||||
|
/// This is a shortcut for
|
||||||
|
/// `table.get::<_, Function>(key)?.call((table.clone(), arg1, ..., argN))`
|
||||||
|
///
|
||||||
|
/// This might invoke the `__index` metamethod.
|
||||||
|
fn call_method<K, A, R>(&self, key: K, args: A) -> Result<R>
|
||||||
|
where
|
||||||
|
K: ToLua<'lua>,
|
||||||
|
A: ToLuaMulti<'lua>,
|
||||||
|
R: FromLuaMulti<'lua>;
|
||||||
|
|
||||||
|
/// Gets the function associated to `key` from the table and executes it,
|
||||||
|
/// passing `args` as function arguments.
|
||||||
|
///
|
||||||
|
/// This is a shortcut for
|
||||||
|
/// `table.get::<_, Function>(key)?.call(args)`
|
||||||
|
///
|
||||||
|
/// This might invoke the `__index` metamethod.
|
||||||
|
fn call_function<K, A, R>(&self, key: K, args: A) -> Result<R>
|
||||||
|
where
|
||||||
|
K: ToLua<'lua>,
|
||||||
|
A: ToLuaMulti<'lua>,
|
||||||
|
R: FromLuaMulti<'lua>;
|
||||||
|
|
||||||
|
/// Gets the function associated to `key` from the table and asynchronously executes it,
|
||||||
|
/// passing the table itself along with `args` as function arguments and returning Future.
|
||||||
|
///
|
||||||
|
/// Requires `feature = "async"`
|
||||||
|
///
|
||||||
|
/// This might invoke the `__index` metamethod.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||||
|
fn call_async_method<'fut, K, A, R>(&self, key: K, args: A) -> LocalBoxFuture<'fut, Result<R>>
|
||||||
|
where
|
||||||
|
'lua: 'fut,
|
||||||
|
K: ToLua<'lua>,
|
||||||
|
A: ToLuaMulti<'lua>,
|
||||||
|
R: FromLuaMulti<'lua> + 'fut;
|
||||||
|
|
||||||
|
/// Gets the function associated to `key` from the table and asynchronously executes it,
|
||||||
|
/// passing `args` as function arguments and returning Future.
|
||||||
|
///
|
||||||
|
/// Requires `feature = "async"`
|
||||||
|
///
|
||||||
|
/// This might invoke the `__index` metamethod.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||||
|
fn call_async_function<'fut, K, A, R>(
|
||||||
|
&self,
|
||||||
|
key: K,
|
||||||
|
args: A,
|
||||||
|
) -> LocalBoxFuture<'fut, Result<R>>
|
||||||
|
where
|
||||||
|
'lua: 'fut,
|
||||||
|
K: ToLua<'lua>,
|
||||||
|
A: ToLuaMulti<'lua>,
|
||||||
|
R: FromLuaMulti<'lua> + 'fut;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> TableExt<'lua> for Table<'lua> {
|
||||||
|
fn call_method<K, A, R>(&self, key: K, args: A) -> Result<R>
|
||||||
|
where
|
||||||
|
K: ToLua<'lua>,
|
||||||
|
A: ToLuaMulti<'lua>,
|
||||||
|
R: FromLuaMulti<'lua>,
|
||||||
|
{
|
||||||
|
let lua = self.0.lua;
|
||||||
|
let mut args = args.to_lua_multi(lua)?;
|
||||||
|
args.push_front(Value::Table(self.clone()));
|
||||||
|
self.get::<_, Function>(key)?.call(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_function<K, A, R>(&self, key: K, args: A) -> Result<R>
|
||||||
|
where
|
||||||
|
K: ToLua<'lua>,
|
||||||
|
A: ToLuaMulti<'lua>,
|
||||||
|
R: FromLuaMulti<'lua>,
|
||||||
|
{
|
||||||
|
self.get::<_, Function>(key)?.call(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
fn call_async_method<'fut, K, A, R>(&self, key: K, args: A) -> LocalBoxFuture<'fut, Result<R>>
|
||||||
|
where
|
||||||
|
'lua: 'fut,
|
||||||
|
K: ToLua<'lua>,
|
||||||
|
A: ToLuaMulti<'lua>,
|
||||||
|
R: FromLuaMulti<'lua> + 'fut,
|
||||||
|
{
|
||||||
|
let lua = self.0.lua;
|
||||||
|
let mut args = match args.to_lua_multi(lua) {
|
||||||
|
Ok(args) => args,
|
||||||
|
Err(e) => return Box::pin(future::err(e)),
|
||||||
|
};
|
||||||
|
args.push_front(Value::Table(self.clone()));
|
||||||
|
self.call_async_function(key, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
fn call_async_function<'fut, K, A, R>(&self, key: K, args: A) -> LocalBoxFuture<'fut, Result<R>>
|
||||||
|
where
|
||||||
|
'lua: 'fut,
|
||||||
|
K: ToLua<'lua>,
|
||||||
|
A: ToLuaMulti<'lua>,
|
||||||
|
R: FromLuaMulti<'lua> + 'fut,
|
||||||
|
{
|
||||||
|
match self.get::<_, Function>(key) {
|
||||||
|
Ok(func) => func.call_async(args),
|
||||||
|
Err(e) => Box::pin(future::err(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
impl<'lua> Serialize for Table<'lua> {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let len = self.raw_len() as usize;
|
||||||
|
if len > 0 || self.is_array() {
|
||||||
|
let mut seq = serializer.serialize_seq(Some(len))?;
|
||||||
|
for v in self.clone().raw_sequence_values_by_len::<Value>() {
|
||||||
|
let v = v.map_err(serde::ser::Error::custom)?;
|
||||||
|
seq.serialize_element(&v)?;
|
||||||
|
}
|
||||||
|
return seq.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut map = serializer.serialize_map(None)?;
|
||||||
|
for kv in self.clone().pairs::<Value, Value>() {
|
||||||
|
let (k, v) = kv.map_err(serde::ser::Error::custom)?;
|
||||||
|
map.serialize_entry(&k, &v)?;
|
||||||
|
}
|
||||||
|
map.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An iterator over the pairs of a Lua table.
|
/// An iterator over the pairs of a Lua table.
|
||||||
///
|
///
|
||||||
/// This struct is created by the [`Table::pairs`] method.
|
/// This struct is created by the [`Table::pairs`] method.
|
||||||
@@ -524,9 +687,10 @@ where
|
|||||||
lua.push_ref(&self.table);
|
lua.push_ref(&self.table);
|
||||||
lua.push_value(next_key)?;
|
lua.push_value(next_key)?;
|
||||||
|
|
||||||
if protect_lua_closure(lua.state, 2, ffi::LUA_MULTRET, |state| {
|
let next = protect_lua_closure(lua.state, 2, ffi::LUA_MULTRET, |state| {
|
||||||
ffi::lua_next(state, -2) != 0
|
ffi::lua_next(state, -2) != 0
|
||||||
})? {
|
})?;
|
||||||
|
if next {
|
||||||
ffi::lua_pushvalue(lua.state, -2);
|
ffi::lua_pushvalue(lua.state, -2);
|
||||||
let key = lua.pop_value();
|
let key = lua.pop_value();
|
||||||
let value = lua.pop_value();
|
let value = lua.pop_value();
|
||||||
@@ -564,6 +728,8 @@ where
|
|||||||
pub struct TableSequence<'lua, V> {
|
pub struct TableSequence<'lua, V> {
|
||||||
table: LuaRef<'lua>,
|
table: LuaRef<'lua>,
|
||||||
index: Option<Integer>,
|
index: Option<Integer>,
|
||||||
|
len: Option<Integer>,
|
||||||
|
raw: bool,
|
||||||
_phantom: PhantomData<V>,
|
_phantom: PhantomData<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -582,9 +748,13 @@ where
|
|||||||
assert_stack(lua.state, 5);
|
assert_stack(lua.state, 5);
|
||||||
|
|
||||||
lua.push_ref(&self.table);
|
lua.push_ref(&self.table);
|
||||||
match protect_lua_closure(lua.state, 1, 1, |state| ffi::lua_geti(state, -1, index))
|
let lua_geti = if self.raw {
|
||||||
{
|
ffi::lua_rawgeti
|
||||||
Ok(ffi::LUA_TNIL) => None,
|
} else {
|
||||||
|
ffi::lua_geti
|
||||||
|
};
|
||||||
|
match protect_lua_closure(lua.state, 1, 1, |state| lua_geti(state, -1, index)) {
|
||||||
|
Ok(ffi::LUA_TNIL) if index > self.len.unwrap_or(0) => None,
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
let value = lua.pop_value();
|
let value = lua.pop_value();
|
||||||
self.index = Some(index + 1);
|
self.index = Some(index + 1);
|
||||||
|
|||||||
+217
-2
@@ -8,6 +8,24 @@ use crate::util::{
|
|||||||
};
|
};
|
||||||
use crate::value::{FromLuaMulti, MultiValue, ToLuaMulti};
|
use crate::value::{FromLuaMulti, MultiValue, ToLuaMulti};
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
error::ExternalError,
|
||||||
|
lua::{AsyncPollPending, Lua, WAKER_REGISTRY_KEY},
|
||||||
|
util::{get_gc_userdata, push_gc_userdata},
|
||||||
|
value::Value,
|
||||||
|
},
|
||||||
|
futures_core::{future::Future, stream::Stream},
|
||||||
|
std::{
|
||||||
|
cell::RefCell,
|
||||||
|
marker::PhantomData,
|
||||||
|
os::raw::c_void,
|
||||||
|
pin::Pin,
|
||||||
|
task::{Context, Poll, Waker},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/// Status of a Lua thread (or coroutine).
|
/// Status of a Lua thread (or coroutine).
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub enum ThreadStatus {
|
pub enum ThreadStatus {
|
||||||
@@ -27,6 +45,21 @@ pub enum ThreadStatus {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Thread<'lua>(pub(crate) LuaRef<'lua>);
|
pub struct Thread<'lua>(pub(crate) LuaRef<'lua>);
|
||||||
|
|
||||||
|
/// Thread (coroutine) representation as an async [`Future`] or [`Stream`].
|
||||||
|
///
|
||||||
|
/// Requires `feature = "async"`
|
||||||
|
///
|
||||||
|
/// [`Future`]: ../futures_core/future/trait.Future.html
|
||||||
|
/// [`Stream`]: ../futures_core/stream/trait.Stream.html
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AsyncThread<'lua, R> {
|
||||||
|
thread: Thread<'lua>,
|
||||||
|
args0: RefCell<Option<Result<MultiValue<'lua>>>>,
|
||||||
|
ret: PhantomData<R>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'lua> Thread<'lua> {
|
impl<'lua> Thread<'lua> {
|
||||||
/// Resumes execution of this thread.
|
/// Resumes execution of this thread.
|
||||||
///
|
///
|
||||||
@@ -99,7 +132,9 @@ impl<'lua> Thread<'lua> {
|
|||||||
}
|
}
|
||||||
ffi::lua_xmove(lua.state, thread_state, nargs);
|
ffi::lua_xmove(lua.state, thread_state, nargs);
|
||||||
|
|
||||||
let ret = ffi::lua_resume(thread_state, lua.state, nargs);
|
let mut nresults = 0;
|
||||||
|
|
||||||
|
let ret = ffi::lua_resume(thread_state, lua.state, nargs, &mut nresults as *mut c_int);
|
||||||
if ret != ffi::LUA_OK && ret != ffi::LUA_YIELD {
|
if ret != ffi::LUA_OK && ret != ffi::LUA_YIELD {
|
||||||
protect_lua_closure(lua.state, 0, 0, |_| {
|
protect_lua_closure(lua.state, 0, 0, |_| {
|
||||||
error_traceback(thread_state);
|
error_traceback(thread_state);
|
||||||
@@ -108,7 +143,6 @@ impl<'lua> Thread<'lua> {
|
|||||||
return Err(pop_error(thread_state, ret));
|
return Err(pop_error(thread_state, ret));
|
||||||
}
|
}
|
||||||
|
|
||||||
let nresults = ffi::lua_gettop(thread_state);
|
|
||||||
let mut results = MultiValue::new();
|
let mut results = MultiValue::new();
|
||||||
ffi::lua_xmove(thread_state, lua.state, nresults);
|
ffi::lua_xmove(thread_state, lua.state, nresults);
|
||||||
|
|
||||||
@@ -142,6 +176,62 @@ impl<'lua> Thread<'lua> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts Thread to an AsyncThread which implements Future and Stream traits.
|
||||||
|
///
|
||||||
|
/// `args` are passed as arguments to the thread function for first call.
|
||||||
|
/// The object call `resume()` while polling and also allows to run rust futures
|
||||||
|
/// to completion using an executor.
|
||||||
|
///
|
||||||
|
/// Using AsyncThread as a Stream allows to iterate through `coroutine.yield()`
|
||||||
|
/// values whereas Future version discards that values and poll until the final
|
||||||
|
/// one (returned from the thread function).
|
||||||
|
///
|
||||||
|
/// Requires `feature = "async"`
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use mlua::{Lua, Result, Thread};
|
||||||
|
/// use futures::stream::TryStreamExt;
|
||||||
|
/// # #[tokio::main]
|
||||||
|
/// # async fn main() -> Result<()> {
|
||||||
|
/// # let lua = Lua::new();
|
||||||
|
/// let thread: Thread = lua.load(r#"
|
||||||
|
/// coroutine.create(function (sum)
|
||||||
|
/// for i = 1,10 do
|
||||||
|
/// sum = sum + i
|
||||||
|
/// coroutine.yield(sum)
|
||||||
|
/// end
|
||||||
|
/// return sum
|
||||||
|
/// end)
|
||||||
|
/// "#).eval()?;
|
||||||
|
///
|
||||||
|
/// let mut stream = thread.into_async::<_, i64>(1);
|
||||||
|
/// let mut sum = 0;
|
||||||
|
/// while let Some(n) = stream.try_next().await? {
|
||||||
|
/// sum += n;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(sum, 286);
|
||||||
|
///
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||||
|
pub fn into_async<A, R>(self, args: A) -> AsyncThread<'lua, R>
|
||||||
|
where
|
||||||
|
A: ToLuaMulti<'lua>,
|
||||||
|
R: FromLuaMulti<'lua>,
|
||||||
|
{
|
||||||
|
let args = args.to_lua_multi(&self.0.lua);
|
||||||
|
AsyncThread {
|
||||||
|
thread: self,
|
||||||
|
args0: RefCell::new(Some(args)),
|
||||||
|
ret: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> PartialEq for Thread<'lua> {
|
impl<'lua> PartialEq for Thread<'lua> {
|
||||||
@@ -149,3 +239,128 @@ impl<'lua> PartialEq for Thread<'lua> {
|
|||||||
self.0 == other.0
|
self.0 == other.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
impl<'lua, R> Stream for AsyncThread<'lua, R>
|
||||||
|
where
|
||||||
|
R: FromLuaMulti<'lua>,
|
||||||
|
{
|
||||||
|
type Item = Result<R>;
|
||||||
|
|
||||||
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
let lua = self.thread.0.lua;
|
||||||
|
|
||||||
|
match self.thread.status() {
|
||||||
|
ThreadStatus::Resumable => {}
|
||||||
|
_ => return Poll::Ready(None),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _wg = WakerGuard::new(lua.state, cx.waker().clone());
|
||||||
|
let ret: MultiValue = if let Some(args) = self.args0.borrow_mut().take() {
|
||||||
|
self.thread.resume(args?)?
|
||||||
|
} else {
|
||||||
|
self.thread.resume(())?
|
||||||
|
};
|
||||||
|
|
||||||
|
if is_poll_pending(lua, &ret) {
|
||||||
|
return Poll::Pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
cx.waker().wake_by_ref();
|
||||||
|
Poll::Ready(Some(R::from_lua_multi(ret, lua)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
impl<'lua, R> Future for AsyncThread<'lua, R>
|
||||||
|
where
|
||||||
|
R: FromLuaMulti<'lua>,
|
||||||
|
{
|
||||||
|
type Output = Result<R>;
|
||||||
|
|
||||||
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let lua = self.thread.0.lua;
|
||||||
|
|
||||||
|
match self.thread.status() {
|
||||||
|
ThreadStatus::Resumable => {}
|
||||||
|
_ => return Poll::Ready(Err("Thread already finished".to_lua_err())),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _wg = WakerGuard::new(lua.state, cx.waker().clone());
|
||||||
|
let ret: MultiValue = if let Some(args) = self.args0.borrow_mut().take() {
|
||||||
|
self.thread.resume(args?)?
|
||||||
|
} else {
|
||||||
|
self.thread.resume(())?
|
||||||
|
};
|
||||||
|
|
||||||
|
if is_poll_pending(lua, &ret) {
|
||||||
|
return Poll::Pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let ThreadStatus::Resumable = self.thread.status() {
|
||||||
|
// Ignore value returned via yield()
|
||||||
|
cx.waker().wake_by_ref();
|
||||||
|
return Poll::Pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
Poll::Ready(R::from_lua_multi(ret, lua))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
fn is_poll_pending(lua: &Lua, val: &MultiValue) -> bool {
|
||||||
|
if val.len() != 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(Value::UserData(ud)) = val.iter().next() {
|
||||||
|
unsafe {
|
||||||
|
let _sg = StackGuard::new(lua.state);
|
||||||
|
assert_stack(lua.state, 3);
|
||||||
|
|
||||||
|
lua.push_ref(&ud.0);
|
||||||
|
let is_pending = get_gc_userdata::<AsyncPollPending>(lua.state, -1)
|
||||||
|
.as_ref()
|
||||||
|
.is_some();
|
||||||
|
ffi::lua_pop(lua.state, 1);
|
||||||
|
|
||||||
|
return is_pending;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
struct WakerGuard(*mut ffi::lua_State);
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
impl WakerGuard {
|
||||||
|
pub fn new(state: *mut ffi::lua_State, waker: Waker) -> Result<WakerGuard> {
|
||||||
|
unsafe {
|
||||||
|
let _sg = StackGuard::new(state);
|
||||||
|
assert_stack(state, 6);
|
||||||
|
|
||||||
|
ffi::lua_pushlightuserdata(state, &WAKER_REGISTRY_KEY as *const u8 as *mut c_void);
|
||||||
|
push_gc_userdata(state, waker)?;
|
||||||
|
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
|
Ok(WakerGuard(state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
impl Drop for WakerGuard {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
let state = self.0;
|
||||||
|
let _sg = StackGuard::new(state);
|
||||||
|
assert_stack(state, 2);
|
||||||
|
|
||||||
|
ffi::lua_pushlightuserdata(state, &WAKER_REGISTRY_KEY as *const u8 as *mut c_void);
|
||||||
|
ffi::lua_pushnil(state);
|
||||||
|
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+30
-10
@@ -1,10 +1,16 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
use std::os::raw::{c_int, c_void};
|
use std::os::raw::{c_int, c_void};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::{fmt, mem, ptr};
|
use std::{fmt, mem, ptr};
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
use futures_core::future::LocalBoxFuture;
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
|
use crate::hook::Debug;
|
||||||
use crate::lua::Lua;
|
use crate::lua::Lua;
|
||||||
|
use crate::userdata::UserDataWrapped;
|
||||||
use crate::util::{assert_stack, StackGuard};
|
use crate::util::{assert_stack, StackGuard};
|
||||||
use crate::value::MultiValue;
|
use crate::value::MultiValue;
|
||||||
|
|
||||||
@@ -20,24 +26,37 @@ pub struct LightUserData(pub *mut c_void);
|
|||||||
pub(crate) type Callback<'lua, 'a> =
|
pub(crate) type Callback<'lua, 'a> =
|
||||||
Box<dyn Fn(&'lua Lua, MultiValue<'lua>) -> Result<MultiValue<'lua>> + 'a>;
|
Box<dyn Fn(&'lua Lua, MultiValue<'lua>) -> Result<MultiValue<'lua>> + 'a>;
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub(crate) type AsyncCallback<'lua, 'a> =
|
||||||
|
Box<dyn Fn(&'lua Lua, MultiValue<'lua>) -> LocalBoxFuture<'lua, Result<MultiValue<'lua>>> + 'a>;
|
||||||
|
|
||||||
|
pub(crate) type HookCallback = Arc<RefCell<dyn FnMut(&Lua, Debug) -> Result<()>>>;
|
||||||
|
|
||||||
|
pub(crate) type UserDataCell<T> = RefCell<UserDataWrapped<T>>;
|
||||||
|
|
||||||
|
#[cfg(feature = "send")]
|
||||||
|
pub trait MaybeSend: Send {}
|
||||||
|
#[cfg(feature = "send")]
|
||||||
|
impl<T: Send> MaybeSend for T {}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "send"))]
|
||||||
|
pub trait MaybeSend {}
|
||||||
|
#[cfg(not(feature = "send"))]
|
||||||
|
impl<T> MaybeSend for T {}
|
||||||
|
|
||||||
/// An auto generated key into the Lua registry.
|
/// An auto generated key into the Lua registry.
|
||||||
///
|
///
|
||||||
/// This is a handle to a value stored inside the Lua registry. It is not directly usable like the
|
/// This is a handle to a value stored inside the Lua registry. It is not automatically
|
||||||
/// `Table` or `Function` handle types, but since it doesn't hold a reference to a parent Lua and is
|
/// garbage collected on Drop, but it can be removed with [`Lua::remove_registry_value`],
|
||||||
/// Send + Sync + 'static, it is much more flexible and can be used in many situations where it is
|
/// and instances not manually removed can be garbage collected with [`Lua::expire_registry_values`].
|
||||||
/// impossible to directly store a normal handle type. It is not automatically garbage collected on
|
|
||||||
/// Drop, but it can be removed with [`Lua::remove_registry_value`], and instances not manually
|
|
||||||
/// removed can be garbage collected with [`Lua::expire_registry_values`].
|
|
||||||
///
|
///
|
||||||
/// Be warned, If you place this into Lua via a `UserData` type or a rust callback, it is *very
|
/// Be warned, If you place this into Lua via a `UserData` type or a rust callback, it is *very
|
||||||
/// easy* to accidentally cause reference cycles that the Lua garbage collector cannot resolve.
|
/// easy* to accidentally cause reference cycles that the Lua garbage collector cannot resolve.
|
||||||
/// Instead of placing a `RegistryKey` into a `UserData` type, prefer instead to use
|
/// Instead of placing a `RegistryKey` into a `UserData` type, prefer instead to use
|
||||||
/// [`UserData::set_user_value`] / [`UserData::get_user_value`], and instead of moving a RegistryKey
|
/// [`UserData::set_user_value`] / [`UserData::get_user_value`].
|
||||||
/// into a callback, prefer [`Lua::scope`].
|
|
||||||
///
|
///
|
||||||
/// [`Lua::remove_registry_value`]: struct.Lua.html#method.remove_registry_value
|
/// [`Lua::remove_registry_value`]: struct.Lua.html#method.remove_registry_value
|
||||||
/// [`Lua::expire_registry_values`]: struct.Lua.html#method.expire_registry_values
|
/// [`Lua::expire_registry_values`]: struct.Lua.html#method.expire_registry_values
|
||||||
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
|
||||||
/// [`UserData::set_user_value`]: struct.UserData.html#method.set_user_value
|
/// [`UserData::set_user_value`]: struct.UserData.html#method.set_user_value
|
||||||
/// [`UserData::get_user_value`]: struct.UserData.html#method.get_user_value
|
/// [`UserData::get_user_value`]: struct.UserData.html#method.get_user_value
|
||||||
pub struct RegistryKey {
|
pub struct RegistryKey {
|
||||||
@@ -53,7 +72,8 @@ impl fmt::Debug for RegistryKey {
|
|||||||
|
|
||||||
impl Drop for RegistryKey {
|
impl Drop for RegistryKey {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some(list) = mlua_expect!(self.unref_list.lock(), "unref_list poisoned").as_mut() {
|
let mut unref_list = mlua_expect!(self.unref_list.lock(), "unref list poisoned");
|
||||||
|
if let Some(list) = unref_list.as_mut() {
|
||||||
list.push(self.registry_id);
|
list.push(self.registry_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+227
-39
@@ -1,13 +1,22 @@
|
|||||||
use std::cell::{Ref, RefCell, RefMut};
|
use std::cell::{Ref, RefMut};
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
use std::future::Future;
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
use {
|
||||||
|
serde::ser::{self, Serialize, Serializer},
|
||||||
|
std::result::Result as StdResult,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
use crate::function::Function;
|
use crate::function::Function;
|
||||||
use crate::lua::Lua;
|
use crate::lua::Lua;
|
||||||
use crate::table::Table;
|
use crate::table::Table;
|
||||||
use crate::types::LuaRef;
|
use crate::types::{LuaRef, MaybeSend, UserDataCell};
|
||||||
use crate::util::{assert_stack, get_userdata, StackGuard};
|
use crate::util::{assert_stack, get_destructed_userdata_metatable, get_userdata, StackGuard};
|
||||||
use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti};
|
use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti, Value};
|
||||||
|
|
||||||
/// Kinds of metamethods that can be overridden.
|
/// Kinds of metamethods that can be overridden.
|
||||||
///
|
///
|
||||||
@@ -31,26 +40,31 @@ pub enum MetaMethod {
|
|||||||
Pow,
|
Pow,
|
||||||
/// The unary minus (`-`) operator.
|
/// The unary minus (`-`) operator.
|
||||||
Unm,
|
Unm,
|
||||||
#[cfg(feature = "lua53")]
|
|
||||||
/// The floor division (//) operator.
|
/// The floor division (//) operator.
|
||||||
|
/// Requires `feature = "lua54/lua53"`
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||||
IDiv,
|
IDiv,
|
||||||
#[cfg(feature = "lua53")]
|
|
||||||
/// The bitwise AND (&) operator.
|
/// The bitwise AND (&) operator.
|
||||||
|
/// Requires `feature = "lua54/lua53"`
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||||
BAnd,
|
BAnd,
|
||||||
#[cfg(feature = "lua53")]
|
|
||||||
/// The bitwise OR (|) operator.
|
/// The bitwise OR (|) operator.
|
||||||
|
/// Requires `feature = "lua54/lua53"`
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||||
BOr,
|
BOr,
|
||||||
#[cfg(feature = "lua53")]
|
|
||||||
/// The bitwise XOR (binary ~) operator.
|
/// The bitwise XOR (binary ~) operator.
|
||||||
|
/// Requires `feature = "lua54/lua53"`
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||||
BXor,
|
BXor,
|
||||||
#[cfg(feature = "lua53")]
|
|
||||||
/// The bitwise NOT (unary ~) operator.
|
/// The bitwise NOT (unary ~) operator.
|
||||||
|
/// Requires `feature = "lua54/lua53"`
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||||
BNot,
|
BNot,
|
||||||
#[cfg(feature = "lua53")]
|
|
||||||
/// The bitwise left shift (<<) operator.
|
/// The bitwise left shift (<<) operator.
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||||
Shl,
|
Shl,
|
||||||
#[cfg(feature = "lua53")]
|
|
||||||
/// The bitwise right shift (>>) operator.
|
/// The bitwise right shift (>>) operator.
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||||
Shr,
|
Shr,
|
||||||
/// The string concatenation operator `..`.
|
/// The string concatenation operator `..`.
|
||||||
Concat,
|
Concat,
|
||||||
@@ -72,11 +86,25 @@ pub enum MetaMethod {
|
|||||||
///
|
///
|
||||||
/// This is not an operator, but will be called by methods such as `tostring` and `print`.
|
/// This is not an operator, but will be called by methods such as `tostring` and `print`.
|
||||||
ToString,
|
ToString,
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
|
||||||
/// The `__pairs` metamethod.
|
/// The `__pairs` metamethod.
|
||||||
///
|
///
|
||||||
/// This is not an operator, but it will be called by the built-in `pairs` function.
|
/// This is not an operator, but it will be called by the built-in `pairs` function.
|
||||||
|
///
|
||||||
|
/// Requires `feature = "lua54/lua53/lua52"`
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", doc))]
|
||||||
Pairs,
|
Pairs,
|
||||||
|
/// The `__close` metamethod.
|
||||||
|
///
|
||||||
|
/// Executed when a variable, that marked as to-be-closed, goes out of scope.
|
||||||
|
///
|
||||||
|
/// More information about to-be-closed variabled can be found in the Lua 5.4
|
||||||
|
/// [documentation][lua_doc].
|
||||||
|
///
|
||||||
|
/// Requires `feature = "lua54"`
|
||||||
|
///
|
||||||
|
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#3.3.8
|
||||||
|
#[cfg(any(feature = "lua54", doc))]
|
||||||
|
Close,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MetaMethod {
|
impl MetaMethod {
|
||||||
@@ -89,20 +117,22 @@ impl MetaMethod {
|
|||||||
MetaMethod::Mod => b"__mod",
|
MetaMethod::Mod => b"__mod",
|
||||||
MetaMethod::Pow => b"__pow",
|
MetaMethod::Pow => b"__pow",
|
||||||
MetaMethod::Unm => b"__unm",
|
MetaMethod::Unm => b"__unm",
|
||||||
#[cfg(feature = "lua53")]
|
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
MetaMethod::IDiv => b"__idiv",
|
MetaMethod::IDiv => b"__idiv",
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
MetaMethod::BAnd => b"__band",
|
MetaMethod::BAnd => b"__band",
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
MetaMethod::BOr => b"__bor",
|
MetaMethod::BOr => b"__bor",
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
MetaMethod::BXor => b"__bxor",
|
MetaMethod::BXor => b"__bxor",
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
MetaMethod::BNot => b"__bnot",
|
MetaMethod::BNot => b"__bnot",
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
MetaMethod::Shl => b"__shl",
|
MetaMethod::Shl => b"__shl",
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
MetaMethod::Shr => b"__shr",
|
MetaMethod::Shr => b"__shr",
|
||||||
|
|
||||||
MetaMethod::Concat => b"__concat",
|
MetaMethod::Concat => b"__concat",
|
||||||
MetaMethod::Len => b"__len",
|
MetaMethod::Len => b"__len",
|
||||||
MetaMethod::Eq => b"__eq",
|
MetaMethod::Eq => b"__eq",
|
||||||
@@ -112,8 +142,12 @@ impl MetaMethod {
|
|||||||
MetaMethod::NewIndex => b"__newindex",
|
MetaMethod::NewIndex => b"__newindex",
|
||||||
MetaMethod::Call => b"__call",
|
MetaMethod::Call => b"__call",
|
||||||
MetaMethod::ToString => b"__tostring",
|
MetaMethod::ToString => b"__tostring",
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
MetaMethod::Pairs => b"__pairs",
|
MetaMethod::Pairs => b"__pairs",
|
||||||
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
MetaMethod::Close => b"__close",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +168,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||||||
S: ?Sized + AsRef<[u8]>,
|
S: ?Sized + AsRef<[u8]>,
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
M: 'static + Send + Fn(&'lua Lua, &T, A) -> Result<R>;
|
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>;
|
||||||
|
|
||||||
/// Add a regular method which accepts a `&mut T` as the first parameter.
|
/// Add a regular method which accepts a `&mut T` as the first parameter.
|
||||||
///
|
///
|
||||||
@@ -146,7 +180,26 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||||||
S: ?Sized + AsRef<[u8]>,
|
S: ?Sized + AsRef<[u8]>,
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
M: 'static + Send + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
|
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
|
||||||
|
|
||||||
|
/// Add an async method which accepts a `T` as the first parameter and returns Future.
|
||||||
|
/// The passed `T` is cloned from the original value.
|
||||||
|
///
|
||||||
|
/// Refer to [`add_method`] for more information about the implementation.
|
||||||
|
///
|
||||||
|
/// Requires `feature = "async"`
|
||||||
|
///
|
||||||
|
/// [`add_method`]: #method.add_method
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||||
|
fn add_async_method<S, A, R, M, MR>(&mut self, name: &S, method: M)
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
S: ?Sized + AsRef<[u8]>,
|
||||||
|
A: FromLuaMulti<'lua>,
|
||||||
|
R: ToLuaMulti<'lua>,
|
||||||
|
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
|
||||||
|
MR: 'lua + Future<Output = Result<R>>;
|
||||||
|
|
||||||
/// Add a regular method as a function which accepts generic arguments, the first argument will
|
/// Add a regular method as a function which accepts generic arguments, the first argument will
|
||||||
/// be a `UserData` of type T if the method is called with Lua method syntax:
|
/// be a `UserData` of type T if the method is called with Lua method syntax:
|
||||||
@@ -162,7 +215,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||||||
S: ?Sized + AsRef<[u8]>,
|
S: ?Sized + AsRef<[u8]>,
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
F: 'static + Send + Fn(&'lua Lua, A) -> Result<R>;
|
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>;
|
||||||
|
|
||||||
/// Add a regular method as a mutable function which accepts generic arguments.
|
/// Add a regular method as a mutable function which accepts generic arguments.
|
||||||
///
|
///
|
||||||
@@ -174,7 +227,26 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||||||
S: ?Sized + AsRef<[u8]>,
|
S: ?Sized + AsRef<[u8]>,
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
F: 'static + Send + FnMut(&'lua Lua, A) -> Result<R>;
|
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>;
|
||||||
|
|
||||||
|
/// Add a regular method as an async function which accepts generic arguments
|
||||||
|
/// and returns Future.
|
||||||
|
///
|
||||||
|
/// This is an async version of [`add_function`].
|
||||||
|
///
|
||||||
|
/// Requires `feature = "async"`
|
||||||
|
///
|
||||||
|
/// [`add_function`]: #method.add_function
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||||
|
fn add_async_function<S, A, R, F, FR>(&mut self, name: &S, function: F)
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
S: ?Sized + AsRef<[u8]>,
|
||||||
|
A: FromLuaMulti<'lua>,
|
||||||
|
R: ToLuaMulti<'lua>,
|
||||||
|
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
|
||||||
|
FR: 'lua + Future<Output = Result<R>>;
|
||||||
|
|
||||||
/// Add a metamethod which accepts a `&T` as the first parameter.
|
/// Add a metamethod which accepts a `&T` as the first parameter.
|
||||||
///
|
///
|
||||||
@@ -188,7 +260,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||||||
where
|
where
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
M: 'static + Send + Fn(&'lua Lua, &T, A) -> Result<R>;
|
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>;
|
||||||
|
|
||||||
/// Add a metamethod as a function which accepts a `&mut T` as the first parameter.
|
/// Add a metamethod as a function which accepts a `&mut T` as the first parameter.
|
||||||
///
|
///
|
||||||
@@ -202,7 +274,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||||||
where
|
where
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
M: 'static + Send + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
|
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
|
||||||
|
|
||||||
/// Add a metamethod which accepts generic arguments.
|
/// Add a metamethod which accepts generic arguments.
|
||||||
///
|
///
|
||||||
@@ -213,7 +285,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||||||
where
|
where
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
F: 'static + Send + Fn(&'lua Lua, A) -> Result<R>;
|
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>;
|
||||||
|
|
||||||
/// Add a metamethod as a mutable function which accepts generic arguments.
|
/// Add a metamethod as a mutable function which accepts generic arguments.
|
||||||
///
|
///
|
||||||
@@ -224,7 +296,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||||||
where
|
where
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
F: 'static + Send + FnMut(&'lua Lua, A) -> Result<R>;
|
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for custom userdata types.
|
/// Trait for custom userdata types.
|
||||||
@@ -293,7 +365,72 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||||||
/// [`UserDataMethods`]: trait.UserDataMethods.html
|
/// [`UserDataMethods`]: trait.UserDataMethods.html
|
||||||
pub trait UserData: Sized {
|
pub trait UserData: Sized {
|
||||||
/// Adds custom methods and operators specific to this userdata.
|
/// Adds custom methods and operators specific to this userdata.
|
||||||
fn add_methods<'lua, T: UserDataMethods<'lua, Self>>(_methods: &mut T) {}
|
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct UserDataWrapped<T> {
|
||||||
|
pub(crate) data: *mut T,
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
ser: *mut dyn erased_serde::Serialize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Drop for UserDataWrapped<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
drop(Box::from_raw(self.data));
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
if self.data as *mut () != self.ser as *mut () {
|
||||||
|
drop(Box::from_raw(self.ser));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> UserDataWrapped<T> {
|
||||||
|
pub(crate) fn new(data: T) -> Self {
|
||||||
|
UserDataWrapped {
|
||||||
|
data: Box::into_raw(Box::new(data)),
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
ser: Box::into_raw(Box::new(UserDataSerializeError)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
pub(crate) fn new_ser(data: T) -> Self
|
||||||
|
where
|
||||||
|
T: 'static + Serialize,
|
||||||
|
{
|
||||||
|
let data_raw = Box::into_raw(Box::new(data));
|
||||||
|
UserDataWrapped {
|
||||||
|
data: data_raw,
|
||||||
|
ser: data_raw,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> AsRef<T> for UserDataWrapped<T> {
|
||||||
|
fn as_ref(&self) -> &T {
|
||||||
|
unsafe { &*self.data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> AsMut<T> for UserDataWrapped<T> {
|
||||||
|
fn as_mut(&mut self) -> &mut T {
|
||||||
|
unsafe { &mut *self.data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
pub(crate) struct UserDataSerializeError;
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
impl Serialize for UserDataSerializeError {
|
||||||
|
fn serialize<S>(&self, _serializer: S) -> StdResult<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
Err(ser::Error::custom("cannot serialize <userdata>"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle to an internal Lua userdata for any type that implements [`UserData`].
|
/// Handle to an internal Lua userdata for any type that implements [`UserData`].
|
||||||
@@ -318,7 +455,7 @@ pub struct AnyUserData<'lua>(pub(crate) LuaRef<'lua>);
|
|||||||
impl<'lua> AnyUserData<'lua> {
|
impl<'lua> AnyUserData<'lua> {
|
||||||
/// Checks whether the type of this userdata is `T`.
|
/// Checks whether the type of this userdata is `T`.
|
||||||
pub fn is<T: 'static + UserData>(&self) -> bool {
|
pub fn is<T: 'static + UserData>(&self) -> bool {
|
||||||
match self.inspect(|_: &RefCell<T>| Ok(())) {
|
match self.inspect(|_: &UserDataCell<T>| Ok(())) {
|
||||||
Ok(()) => true,
|
Ok(()) => true,
|
||||||
Err(Error::UserDataTypeMismatch) => false,
|
Err(Error::UserDataTypeMismatch) => false,
|
||||||
Err(_) => unreachable!(),
|
Err(_) => unreachable!(),
|
||||||
@@ -332,7 +469,10 @@ impl<'lua> AnyUserData<'lua> {
|
|||||||
/// Returns a `UserDataBorrowError` if the userdata is already mutably borrowed. Returns a
|
/// Returns a `UserDataBorrowError` if the userdata is already mutably borrowed. Returns a
|
||||||
/// `UserDataTypeMismatch` if the userdata is not of type `T`.
|
/// `UserDataTypeMismatch` if the userdata is not of type `T`.
|
||||||
pub fn borrow<T: 'static + UserData>(&self) -> Result<Ref<T>> {
|
pub fn borrow<T: 'static + UserData>(&self) -> Result<Ref<T>> {
|
||||||
self.inspect(|cell| Ok(cell.try_borrow().map_err(|_| Error::UserDataBorrowError)?))
|
self.inspect(|cell| {
|
||||||
|
let cell_ref = cell.try_borrow().map_err(|_| Error::UserDataBorrowError)?;
|
||||||
|
Ok(Ref::map(cell_ref, |x| unsafe { &*x.data }))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrow this userdata mutably if it is of type `T`.
|
/// Borrow this userdata mutably if it is of type `T`.
|
||||||
@@ -343,27 +483,29 @@ impl<'lua> AnyUserData<'lua> {
|
|||||||
/// `UserDataTypeMismatch` if the userdata is not of type `T`.
|
/// `UserDataTypeMismatch` if the userdata is not of type `T`.
|
||||||
pub fn borrow_mut<T: 'static + UserData>(&self) -> Result<RefMut<T>> {
|
pub fn borrow_mut<T: 'static + UserData>(&self) -> Result<RefMut<T>> {
|
||||||
self.inspect(|cell| {
|
self.inspect(|cell| {
|
||||||
Ok(cell
|
let cell_ref = cell
|
||||||
.try_borrow_mut()
|
.try_borrow_mut()
|
||||||
.map_err(|_| Error::UserDataBorrowMutError)?)
|
.map_err(|_| Error::UserDataBorrowMutError)?;
|
||||||
|
Ok(RefMut::map(cell_ref, |x| unsafe { &mut *x.data }))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets an associated value to this `AnyUserData`.
|
/// Sets an associated value to this `AnyUserData`.
|
||||||
///
|
///
|
||||||
/// The value may be any Lua value whatsoever, and can be retrieved with [`get_user_value`].
|
/// The value may be any Lua value whatsoever, and can be retrieved with [`get_user_value`].
|
||||||
|
/// As Lua < 5.3 allows to store only tables, the value will be stored in a table at index 1.
|
||||||
///
|
///
|
||||||
/// [`get_user_value`]: #method.get_user_value
|
/// [`get_user_value`]: #method.get_user_value
|
||||||
pub fn set_user_value<V: ToLua<'lua>>(&self, v: V) -> Result<()> {
|
pub fn set_user_value<V: ToLua<'lua>>(&self, v: V) -> Result<()> {
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
let v = {
|
let v = {
|
||||||
// Lua 5.2/5.1 allows to store only table. Then we will wrap the value.
|
// Lua 5.2/5.1 allows to store only a table. Then we will wrap the value.
|
||||||
let t = lua.create_table()?;
|
let t = lua.create_table()?;
|
||||||
t.raw_set(1, v)?;
|
t.raw_set(1, v)?;
|
||||||
crate::Value::Table(t)
|
crate::Value::Table(t)
|
||||||
};
|
};
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
let v = v.to_lua(lua)?;
|
let v = v.to_lua(lua)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
@@ -377,6 +519,8 @@ impl<'lua> AnyUserData<'lua> {
|
|||||||
|
|
||||||
/// Returns an associated value set by [`set_user_value`].
|
/// Returns an associated value set by [`set_user_value`].
|
||||||
///
|
///
|
||||||
|
/// For Lua < 5.3 the value will be automatically extracted from the table wrapper from index 1.
|
||||||
|
///
|
||||||
/// [`set_user_value`]: #method.set_user_value
|
/// [`set_user_value`]: #method.set_user_value
|
||||||
pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> {
|
pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> {
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
@@ -389,10 +533,26 @@ impl<'lua> AnyUserData<'lua> {
|
|||||||
};
|
};
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
return crate::Table::from_lua(res, lua)?.get(1);
|
return crate::Table::from_lua(res, lua)?.get(1);
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
V::from_lua(res, lua)
|
V::from_lua(res, lua)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks for a metamethod in this `AnyUserData`
|
||||||
|
pub fn has_metamethod(&self, method: MetaMethod) -> Result<bool> {
|
||||||
|
match self.get_metatable() {
|
||||||
|
Ok(mt) => {
|
||||||
|
let name = self.0.lua.create_string(method.name())?;
|
||||||
|
if let Value::Nil = mt.raw_get(name)? {
|
||||||
|
Ok(false)
|
||||||
|
} else {
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(Error::UserDataTypeMismatch) => Ok(false),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_metatable(&self) -> Result<Table<'lua>> {
|
fn get_metatable(&self) -> Result<Table<'lua>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
@@ -432,7 +592,7 @@ impl<'lua> AnyUserData<'lua> {
|
|||||||
fn inspect<'a, T, R, F>(&'a self, func: F) -> Result<R>
|
fn inspect<'a, T, R, F>(&'a self, func: F) -> Result<R>
|
||||||
where
|
where
|
||||||
T: 'static + UserData,
|
T: 'static + UserData,
|
||||||
F: FnOnce(&'a RefCell<T>) -> Result<R>,
|
F: FnOnce(&'a UserDataCell<T>) -> Result<R>,
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
@@ -451,9 +611,16 @@ impl<'lua> AnyUserData<'lua> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ffi::lua_rawequal(lua.state, -1, -2) == 0 {
|
if ffi::lua_rawequal(lua.state, -1, -2) == 0 {
|
||||||
Err(Error::UserDataTypeMismatch)
|
// Maybe UserData destructed?
|
||||||
|
ffi::lua_pop(lua.state, 1);
|
||||||
|
get_destructed_userdata_metatable(lua.state);
|
||||||
|
if ffi::lua_rawequal(lua.state, -1, -2) == 1 {
|
||||||
|
Err(Error::UserDataDestructed)
|
||||||
|
} else {
|
||||||
|
Err(Error::UserDataTypeMismatch)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
func(&*get_userdata::<RefCell<T>>(lua.state, -3))
|
func(&*get_userdata::<UserDataCell<T>>(lua.state, -3))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -472,3 +639,24 @@ impl<'lua> AsRef<AnyUserData<'lua>> for AnyUserData<'lua> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
impl<'lua> Serialize for AnyUserData<'lua> {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let f = || unsafe {
|
||||||
|
let lua = self.0.lua;
|
||||||
|
let _sg = StackGuard::new(lua.state);
|
||||||
|
assert_stack(lua.state, 2);
|
||||||
|
|
||||||
|
lua.push_userdata_ref(&self.0)?;
|
||||||
|
let ud = &*get_userdata::<UserDataCell<()>>(lua.state, -1);
|
||||||
|
(*ud.try_borrow().map_err(|_| Error::UserDataBorrowError)?.ser)
|
||||||
|
.serialize(serializer)
|
||||||
|
.map_err(|err| Error::SerializeError(err.to_string()))
|
||||||
|
};
|
||||||
|
f().map_err(ser::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+138
-130
@@ -1,14 +1,20 @@
|
|||||||
use std::any::Any;
|
use std::any::{Any, TypeId};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::os::raw::{c_char, c_int, c_void};
|
use std::os::raw::{c_char, c_int, c_void};
|
||||||
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
|
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex};
|
||||||
use std::{mem, ptr, slice};
|
use std::{mem, ptr, slice};
|
||||||
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
// The capacity must(!) be greater than number of stored keys
|
||||||
|
static ref METATABLE_CACHE: Mutex<HashMap<TypeId, u8>> = Mutex::new(HashMap::with_capacity(32));
|
||||||
|
}
|
||||||
|
|
||||||
// Checks that Lua has enough free stack space for future stack operations. On failure, this will
|
// Checks that Lua has enough free stack space for future stack operations. On failure, this will
|
||||||
// panic with an internal error message.
|
// panic with an internal error message.
|
||||||
pub unsafe fn assert_stack(state: *mut ffi::lua_State, amount: c_int) {
|
pub unsafe fn assert_stack(state: *mut ffi::lua_State, amount: c_int) {
|
||||||
@@ -51,10 +57,11 @@ impl Drop for StackGuard {
|
|||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let top = ffi::lua_gettop(self.state);
|
let top = ffi::lua_gettop(self.state);
|
||||||
|
if top < self.top {
|
||||||
|
mlua_panic!("{} too many stack values popped", self.top - top)
|
||||||
|
}
|
||||||
if top > self.top {
|
if top > self.top {
|
||||||
ffi::lua_settop(self.state, self.top);
|
ffi::lua_settop(self.state, self.top);
|
||||||
} else if top < self.top {
|
|
||||||
mlua_panic!("{} too many stack values popped", self.top - top);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,8 +182,7 @@ pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error {
|
|||||||
if let Some(err) = get_wrapped_error(state, -1).as_ref() {
|
if let Some(err) = get_wrapped_error(state, -1).as_ref() {
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
err.clone()
|
err.clone()
|
||||||
} else if is_wrapped_panic(state, -1) {
|
} else if let Some(panic) = get_gc_userdata::<WrappedPanic>(state, -1).as_mut() {
|
||||||
let panic = get_userdata::<WrappedPanic>(state, -1);
|
|
||||||
if let Some(p) = (*panic).0.take() {
|
if let Some(p) = (*panic).0.take() {
|
||||||
resume_unwind(p);
|
resume_unwind(p);
|
||||||
} else {
|
} else {
|
||||||
@@ -255,6 +261,37 @@ pub unsafe fn take_userdata<T>(state: *mut ffi::lua_State) -> T {
|
|||||||
ptr::read(ud)
|
ptr::read(ud)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pushes the userdata and attaches a metatable with __gc method
|
||||||
|
// Internally uses 5 stack spaces, does not call checkstack
|
||||||
|
pub unsafe fn push_gc_userdata<T: Any>(state: *mut ffi::lua_State, t: T) -> Result<()> {
|
||||||
|
push_meta_gc_userdata::<T, T>(state, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn push_meta_gc_userdata<MT: Any, T>(state: *mut ffi::lua_State, t: T) -> Result<()> {
|
||||||
|
let ud = protect_lua_closure(state, 0, 1, move |state| {
|
||||||
|
ffi::lua_newuserdata(state, mem::size_of::<T>()) as *mut T
|
||||||
|
})?;
|
||||||
|
ptr::write(ud, t);
|
||||||
|
get_gc_metatable_for::<MT>(state);
|
||||||
|
ffi::lua_setmetatable(state, -2);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uses 2 stack spaces, does not call checkstack
|
||||||
|
pub unsafe fn get_gc_userdata<T: Any>(state: *mut ffi::lua_State, index: c_int) -> *mut T {
|
||||||
|
let ud = ffi::lua_touserdata(state, index) as *mut T;
|
||||||
|
if ud.is_null() || ffi::lua_getmetatable(state, index) == 0 {
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
get_gc_metatable_for::<T>(state);
|
||||||
|
let res = ffi::lua_rawequal(state, -1, -2) != 0;
|
||||||
|
ffi::lua_pop(state, 2);
|
||||||
|
if !res {
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
ud
|
||||||
|
}
|
||||||
|
|
||||||
// Populates the given table with the appropriate members to be a userdata metatable for the given
|
// Populates the given table with the appropriate members to be a userdata metatable for the given
|
||||||
// type. This function takes the given table at the `metatable` index, and adds an appropriate __gc
|
// type. This function takes the given table at the `metatable` index, and adds an appropriate __gc
|
||||||
// member to it for the given type and a __metatable entry to protect the table from script access.
|
// member to it for the given type and a __metatable entry to protect the table from script access.
|
||||||
@@ -380,14 +417,14 @@ where
|
|||||||
Ok(Err(err)) => {
|
Ok(Err(err)) => {
|
||||||
ffi::lua_settop(state, 1);
|
ffi::lua_settop(state, 1);
|
||||||
ptr::write(ud as *mut WrappedError, WrappedError(err));
|
ptr::write(ud as *mut WrappedError, WrappedError(err));
|
||||||
get_error_metatable(state);
|
get_gc_metatable_for::<WrappedError>(state);
|
||||||
ffi::lua_setmetatable(state, -2);
|
ffi::lua_setmetatable(state, -2);
|
||||||
ffi::lua_error(state)
|
ffi::lua_error(state)
|
||||||
}
|
}
|
||||||
Err(p) => {
|
Err(p) => {
|
||||||
ffi::lua_settop(state, 1);
|
ffi::lua_settop(state, 1);
|
||||||
ptr::write(ud as *mut WrappedPanic, WrappedPanic(Some(p)));
|
ptr::write(ud as *mut WrappedPanic, WrappedPanic(Some(p)));
|
||||||
get_panic_metatable(state);
|
get_gc_metatable_for::<WrappedPanic>(state);
|
||||||
ffi::lua_setmetatable(state, -2);
|
ffi::lua_setmetatable(state, -2);
|
||||||
ffi::lua_error(state)
|
ffi::lua_error(state)
|
||||||
}
|
}
|
||||||
@@ -431,80 +468,104 @@ pub unsafe extern "C" fn error_traceback(state: *mut ffi::lua_State) -> c_int {
|
|||||||
cause: Arc::new(error),
|
cause: Arc::new(error),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
get_error_metatable(state);
|
get_gc_metatable_for::<WrappedError>(state);
|
||||||
ffi::lua_setmetatable(state, -2);
|
ffi::lua_setmetatable(state, -2);
|
||||||
} else if !is_wrapped_panic(state, -1) {
|
} else if get_gc_userdata::<WrappedPanic>(state, -1).is_null()
|
||||||
if ffi::lua_checkstack(state, LUA_TRACEBACK_STACK) != 0 {
|
&& ffi::lua_checkstack(state, LUA_TRACEBACK_STACK) != 0
|
||||||
let s = ffi::luaL_tolstring(state, -1, ptr::null_mut());
|
{
|
||||||
ffi::luaL_traceback(state, state, s, 0);
|
let s = ffi::luaL_tolstring(state, -1, ptr::null_mut());
|
||||||
ffi::lua_remove(state, -2);
|
ffi::luaL_traceback(state, state, s, 0);
|
||||||
}
|
ffi::lua_remove(state, -2);
|
||||||
}
|
}
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does not call lua_checkstack, uses 2 stack spaces.
|
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
|
||||||
pub unsafe fn set_main_state(state: *mut ffi::lua_State) {
|
|
||||||
ffi::lua_pushlightuserdata(state, &MAIN_THREAD_REGISTRY_KEY as *const u8 as *mut c_void);
|
|
||||||
ffi::lua_pushthread(state);
|
|
||||||
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Does not call lua_checkstack, uses 1 stack space.
|
// Does not call lua_checkstack, uses 1 stack space.
|
||||||
pub unsafe fn get_main_state(state: *mut ffi::lua_State) -> *mut ffi::lua_State {
|
pub unsafe fn get_main_state(state: *mut ffi::lua_State) -> Option<*mut ffi::lua_State> {
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_MAINTHREAD);
|
{
|
||||||
|
ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_MAINTHREAD);
|
||||||
|
let main_state = ffi::lua_tothread(state, -1);
|
||||||
|
ffi::lua_pop(state, 1);
|
||||||
|
Some(main_state)
|
||||||
|
}
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
{
|
{
|
||||||
ffi::lua_pushlightuserdata(state, &MAIN_THREAD_REGISTRY_KEY as *const u8 as *mut c_void);
|
// Check the current state first
|
||||||
ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX);
|
let is_main_state = ffi::lua_pushthread(state) == 1;
|
||||||
|
ffi::lua_pop(state, 1);
|
||||||
|
if is_main_state {
|
||||||
|
Some(state)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let main_state = ffi::lua_tothread(state, -1);
|
|
||||||
ffi::lua_pop(state, 1);
|
|
||||||
main_state
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pushes a WrappedError to the top of the stack. Uses two stack spaces and does not call
|
// Pushes a WrappedError to the top of the stack. Uses two stack spaces and does not call
|
||||||
// lua_checkstack.
|
// lua_checkstack.
|
||||||
pub unsafe fn push_wrapped_error(state: *mut ffi::lua_State, err: Error) -> Result<()> {
|
pub unsafe fn push_wrapped_error(state: *mut ffi::lua_State, err: Error) -> Result<()> {
|
||||||
let ud = protect_lua_closure(state, 0, 1, move |state| {
|
push_gc_userdata::<WrappedError>(state, WrappedError(err))
|
||||||
ffi::lua_newuserdata(state, mem::size_of::<WrappedError>()) as *mut WrappedError
|
|
||||||
})?;
|
|
||||||
ptr::write(ud, WrappedError(err));
|
|
||||||
get_error_metatable(state);
|
|
||||||
ffi::lua_setmetatable(state, -2);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if the value at the given index is a WrappedError, and if it is returns a pointer to it,
|
// Checks if the value at the given index is a WrappedError, and if it is returns a pointer to it,
|
||||||
// otherwise returns null. Uses 2 stack spaces and does not call lua_checkstack.
|
// otherwise returns null. Uses 2 stack spaces and does not call lua_checkstack.
|
||||||
pub unsafe fn get_wrapped_error(state: *mut ffi::lua_State, index: c_int) -> *const Error {
|
pub unsafe fn get_wrapped_error(state: *mut ffi::lua_State, index: c_int) -> *const Error {
|
||||||
let userdata = ffi::lua_touserdata(state, index);
|
let ud = get_gc_userdata::<WrappedError>(state, index);
|
||||||
if userdata.is_null() {
|
if ud.is_null() {
|
||||||
return ptr::null();
|
return ptr::null();
|
||||||
}
|
}
|
||||||
|
&(*ud).0
|
||||||
|
}
|
||||||
|
|
||||||
if ffi::lua_getmetatable(state, index) == 0 {
|
// Initialize the internal (with __gc) metatable for a type T
|
||||||
return ptr::null();
|
pub unsafe fn init_gc_metatable_for<T: Any>(
|
||||||
|
state: *mut ffi::lua_State,
|
||||||
|
customize_fn: Option<fn(*mut ffi::lua_State)>,
|
||||||
|
) {
|
||||||
|
let type_id = TypeId::of::<T>();
|
||||||
|
|
||||||
|
let ref_addr = {
|
||||||
|
let mut mt_cache = mlua_expect!(METATABLE_CACHE.lock(), "cannot lock metatable cache");
|
||||||
|
mlua_assert!(
|
||||||
|
mt_cache.capacity() - mt_cache.len() > 0,
|
||||||
|
"out of metatable cache capacity"
|
||||||
|
);
|
||||||
|
mt_cache.insert(type_id, 0);
|
||||||
|
&mt_cache[&type_id] as *const u8
|
||||||
|
};
|
||||||
|
|
||||||
|
ffi::lua_newtable(state);
|
||||||
|
|
||||||
|
ffi::lua_pushstring(state, cstr!("__gc"));
|
||||||
|
ffi::lua_pushcfunction(state, userdata_destructor::<T>);
|
||||||
|
ffi::lua_rawset(state, -3);
|
||||||
|
|
||||||
|
ffi::lua_pushstring(state, cstr!("__metatable"));
|
||||||
|
ffi::lua_pushboolean(state, 0);
|
||||||
|
ffi::lua_rawset(state, -3);
|
||||||
|
|
||||||
|
if let Some(f) = customize_fn {
|
||||||
|
f(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
get_error_metatable(state);
|
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, ref_addr as *mut c_void);
|
||||||
let res = ffi::lua_rawequal(state, -1, -2) != 0;
|
}
|
||||||
ffi::lua_pop(state, 2);
|
|
||||||
|
|
||||||
if res {
|
pub unsafe fn get_gc_metatable_for<T: Any>(state: *mut ffi::lua_State) {
|
||||||
&(*get_userdata::<WrappedError>(state, -1)).0
|
let type_id = TypeId::of::<T>();
|
||||||
} else {
|
let ref_addr = {
|
||||||
ptr::null()
|
let mt_cache = mlua_expect!(METATABLE_CACHE.lock(), "cannot lock metatable cache");
|
||||||
}
|
mlua_expect!(mt_cache.get(&type_id), "gc metatable does not exist") as *const u8
|
||||||
|
};
|
||||||
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, ref_addr as *mut c_void);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the error, panic, and destructed userdata metatables.
|
// Initialize the error, panic, and destructed userdata metatables.
|
||||||
pub unsafe fn init_error_registry(state: *mut ffi::lua_State) {
|
pub unsafe fn init_error_registry(state: *mut ffi::lua_State) {
|
||||||
assert_stack(state, 8);
|
assert_stack(state, 8);
|
||||||
|
|
||||||
// Create error metatable
|
// Create error and panic metatables
|
||||||
|
|
||||||
unsafe extern "C" fn error_tostring(state: *mut ffi::lua_State) -> c_int {
|
unsafe extern "C" fn error_tostring(state: *mut ffi::lua_State) -> c_int {
|
||||||
let err_buf = callback_error(state, |_| {
|
let err_buf = callback_error(state, |_| {
|
||||||
@@ -524,8 +585,7 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) {
|
|||||||
// kind of recursive error structure?)
|
// kind of recursive error structure?)
|
||||||
let _ = write!(&mut (*err_buf), "{}", error);
|
let _ = write!(&mut (*err_buf), "{}", error);
|
||||||
Ok(err_buf)
|
Ok(err_buf)
|
||||||
} else if is_wrapped_panic(state, -1) {
|
} else if let Some(panic) = get_gc_userdata::<WrappedPanic>(state, -1).as_ref() {
|
||||||
let panic = get_userdata::<WrappedPanic>(state, -1);
|
|
||||||
if let Some(ref p) = (*panic).0 {
|
if let Some(ref p) = (*panic).0 {
|
||||||
ffi::lua_pushlightuserdata(
|
ffi::lua_pushlightuserdata(
|
||||||
state,
|
state,
|
||||||
@@ -564,56 +624,31 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) {
|
|||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
ffi::lua_pushlightuserdata(
|
init_gc_metatable_for::<WrappedError>(
|
||||||
state,
|
state,
|
||||||
&ERROR_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void,
|
Some(|state| {
|
||||||
|
ffi::lua_pushstring(state, cstr!("__tostring"));
|
||||||
|
ffi::lua_pushcfunction(state, error_tostring);
|
||||||
|
ffi::lua_rawset(state, -3);
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
ffi::lua_newtable(state);
|
|
||||||
|
|
||||||
ffi::lua_pushstring(state, cstr!("__gc"));
|
init_gc_metatable_for::<WrappedPanic>(
|
||||||
ffi::lua_pushcfunction(state, userdata_destructor::<WrappedError>);
|
|
||||||
ffi::lua_rawset(state, -3);
|
|
||||||
|
|
||||||
ffi::lua_pushstring(state, cstr!("__tostring"));
|
|
||||||
ffi::lua_pushcfunction(state, error_tostring);
|
|
||||||
ffi::lua_rawset(state, -3);
|
|
||||||
|
|
||||||
ffi::lua_pushstring(state, cstr!("__metatable"));
|
|
||||||
ffi::lua_pushboolean(state, 0);
|
|
||||||
ffi::lua_rawset(state, -3);
|
|
||||||
|
|
||||||
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
|
|
||||||
|
|
||||||
// Create panic metatable
|
|
||||||
|
|
||||||
ffi::lua_pushlightuserdata(
|
|
||||||
state,
|
state,
|
||||||
&PANIC_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void,
|
Some(|state| {
|
||||||
|
ffi::lua_pushstring(state, cstr!("__tostring"));
|
||||||
|
ffi::lua_pushcfunction(state, error_tostring);
|
||||||
|
ffi::lua_rawset(state, -3);
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
ffi::lua_newtable(state);
|
|
||||||
|
|
||||||
ffi::lua_pushstring(state, cstr!("__gc"));
|
|
||||||
ffi::lua_pushcfunction(state, userdata_destructor::<WrappedPanic>);
|
|
||||||
ffi::lua_rawset(state, -3);
|
|
||||||
|
|
||||||
ffi::lua_pushstring(state, cstr!("__tostring"));
|
|
||||||
ffi::lua_pushcfunction(state, error_tostring);
|
|
||||||
ffi::lua_rawset(state, -3);
|
|
||||||
|
|
||||||
ffi::lua_pushstring(state, cstr!("__metatable"));
|
|
||||||
ffi::lua_pushboolean(state, 0);
|
|
||||||
ffi::lua_rawset(state, -3);
|
|
||||||
|
|
||||||
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
|
|
||||||
|
|
||||||
// Create destructed userdata metatable
|
// Create destructed userdata metatable
|
||||||
|
|
||||||
unsafe extern "C" fn destructed_error(state: *mut ffi::lua_State) -> c_int {
|
unsafe extern "C" fn destructed_error(state: *mut ffi::lua_State) -> c_int {
|
||||||
ffi::luaL_checkstack(state, 2, ptr::null());
|
ffi::luaL_checkstack(state, 2, ptr::null());
|
||||||
let ud = ffi::lua_newuserdata(state, mem::size_of::<WrappedError>()) as *mut WrappedError;
|
let ud = ffi::lua_newuserdata(state, mem::size_of::<WrappedError>()) as *mut WrappedError;
|
||||||
|
|
||||||
ptr::write(ud, WrappedError(Error::CallbackDestructed));
|
ptr::write(ud, WrappedError(Error::CallbackDestructed));
|
||||||
get_error_metatable(state);
|
get_gc_metatable_for::<WrappedError>(state);
|
||||||
ffi::lua_setmetatable(state, -2);
|
ffi::lua_setmetatable(state, -2);
|
||||||
ffi::lua_error(state)
|
ffi::lua_error(state)
|
||||||
}
|
}
|
||||||
@@ -632,12 +667,19 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) {
|
|||||||
cstr!("__mod"),
|
cstr!("__mod"),
|
||||||
cstr!("__pow"),
|
cstr!("__pow"),
|
||||||
cstr!("__unm"),
|
cstr!("__unm"),
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
cstr!("__idiv"),
|
cstr!("__idiv"),
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
cstr!("__band"),
|
cstr!("__band"),
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
cstr!("__bor"),
|
cstr!("__bor"),
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
cstr!("__bxor"),
|
cstr!("__bxor"),
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
cstr!("__bnot"),
|
cstr!("__bnot"),
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
cstr!("__shl"),
|
cstr!("__shl"),
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
cstr!("__shr"),
|
cstr!("__shr"),
|
||||||
cstr!("__concat"),
|
cstr!("__concat"),
|
||||||
cstr!("__len"),
|
cstr!("__len"),
|
||||||
@@ -648,8 +690,12 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) {
|
|||||||
cstr!("__newindex"),
|
cstr!("__newindex"),
|
||||||
cstr!("__call"),
|
cstr!("__call"),
|
||||||
cstr!("__tostring"),
|
cstr!("__tostring"),
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
cstr!("__pairs"),
|
cstr!("__pairs"),
|
||||||
|
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||||
cstr!("__ipairs"),
|
cstr!("__ipairs"),
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
cstr!("__close"),
|
||||||
] {
|
] {
|
||||||
ffi::lua_pushstring(state, method);
|
ffi::lua_pushstring(state, method);
|
||||||
ffi::lua_pushcfunction(state, destructed_error);
|
ffi::lua_pushcfunction(state, destructed_error);
|
||||||
@@ -709,41 +755,7 @@ unsafe fn to_string<'a>(state: *mut ffi::lua_State, index: c_int) -> Cow<'a, str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if the value at the given index is a WrappedPanic. Uses 2 stack spaces and does not call
|
pub(crate) unsafe fn get_destructed_userdata_metatable(state: *mut ffi::lua_State) {
|
||||||
// lua_checkstack.
|
|
||||||
unsafe fn is_wrapped_panic(state: *mut ffi::lua_State, index: c_int) -> bool {
|
|
||||||
let userdata = ffi::lua_touserdata(state, index);
|
|
||||||
if userdata.is_null() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ffi::lua_getmetatable(state, index) == 0 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
get_panic_metatable(state);
|
|
||||||
let res = ffi::lua_rawequal(state, -1, -2) != 0;
|
|
||||||
ffi::lua_pop(state, 2);
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn get_error_metatable(state: *mut ffi::lua_State) {
|
|
||||||
ffi::lua_pushlightuserdata(
|
|
||||||
state,
|
|
||||||
&ERROR_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void,
|
|
||||||
);
|
|
||||||
ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn get_panic_metatable(state: *mut ffi::lua_State) {
|
|
||||||
ffi::lua_pushlightuserdata(
|
|
||||||
state,
|
|
||||||
&PANIC_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void,
|
|
||||||
);
|
|
||||||
ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn get_destructed_userdata_metatable(state: *mut ffi::lua_State) {
|
|
||||||
ffi::lua_pushlightuserdata(
|
ffi::lua_pushlightuserdata(
|
||||||
state,
|
state,
|
||||||
&DESTRUCTED_USERDATA_METATABLE as *const u8 as *mut c_void,
|
&DESTRUCTED_USERDATA_METATABLE as *const u8 as *mut c_void,
|
||||||
@@ -751,9 +763,5 @@ unsafe fn get_destructed_userdata_metatable(state: *mut ffi::lua_State) {
|
|||||||
ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX);
|
ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
|
||||||
static MAIN_THREAD_REGISTRY_KEY: u8 = 0;
|
|
||||||
static ERROR_METATABLE_REGISTRY_KEY: u8 = 0;
|
|
||||||
static PANIC_METATABLE_REGISTRY_KEY: u8 = 0;
|
|
||||||
static DESTRUCTED_USERDATA_METATABLE: u8 = 0;
|
static DESTRUCTED_USERDATA_METATABLE: u8 = 0;
|
||||||
static ERROR_PRINT_BUFFER_KEY: u8 = 0;
|
static ERROR_PRINT_BUFFER_KEY: u8 = 0;
|
||||||
|
|||||||
+36
-4
@@ -1,6 +1,12 @@
|
|||||||
use std::iter::{self, FromIterator};
|
use std::iter::{self, FromIterator};
|
||||||
use std::{slice, str, vec};
|
use std::{slice, str, vec};
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
use {
|
||||||
|
serde::ser::{self, Serialize, Serializer},
|
||||||
|
std::result::Result as StdResult,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
use crate::function::Function;
|
use crate::function::Function;
|
||||||
@@ -48,18 +54,19 @@ pub enum Value<'lua> {
|
|||||||
pub use self::Value::Nil;
|
pub use self::Value::Nil;
|
||||||
|
|
||||||
impl<'lua> Value<'lua> {
|
impl<'lua> Value<'lua> {
|
||||||
pub(crate) fn type_name(&self) -> &'static str {
|
pub fn type_name(&self) -> &'static str {
|
||||||
match *self {
|
match *self {
|
||||||
Value::Nil => "nil",
|
Value::Nil => "nil",
|
||||||
Value::Boolean(_) => "boolean",
|
Value::Boolean(_) => "boolean",
|
||||||
Value::LightUserData(_) => "light userdata",
|
Value::LightUserData(_) => "lightuserdata",
|
||||||
Value::Integer(_) => "integer",
|
Value::Integer(_) => "integer",
|
||||||
Value::Number(_) => "number",
|
Value::Number(_) => "number",
|
||||||
Value::String(_) => "string",
|
Value::String(_) => "string",
|
||||||
Value::Table(_) => "table",
|
Value::Table(_) => "table",
|
||||||
Value::Function(_) => "function",
|
Value::Function(_) => "function",
|
||||||
Value::Thread(_) => "thread",
|
Value::Thread(_) => "thread",
|
||||||
Value::UserData(_) | Value::Error(_) => "userdata",
|
Value::UserData(_) => "userdata",
|
||||||
|
Value::Error(_) => "error",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +116,31 @@ impl<'lua> AsRef<Value<'lua>> for Value<'lua> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
impl<'lua> Serialize for Value<'lua> {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Value::Nil => serializer.serialize_unit(),
|
||||||
|
Value::Boolean(b) => serializer.serialize_bool(*b),
|
||||||
|
#[allow(clippy::useless_conversion)]
|
||||||
|
Value::Integer(i) => serializer.serialize_i64((*i).into()),
|
||||||
|
#[allow(clippy::useless_conversion)]
|
||||||
|
Value::Number(n) => serializer.serialize_f64((*n).into()),
|
||||||
|
Value::String(s) => s.serialize(serializer),
|
||||||
|
Value::Table(t) => t.serialize(serializer),
|
||||||
|
Value::UserData(ud) => ud.serialize(serializer),
|
||||||
|
Value::LightUserData(ud) if ud.0.is_null() => serializer.serialize_none(),
|
||||||
|
Value::Error(_) | Value::LightUserData(_) | Value::Function(_) | Value::Thread(_) => {
|
||||||
|
let msg = format!("cannot serialize <{}>", self.type_name());
|
||||||
|
Err(ser::Error::custom(msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Trait for types convertible to `Value`.
|
/// Trait for types convertible to `Value`.
|
||||||
pub trait ToLua<'lua> {
|
pub trait ToLua<'lua> {
|
||||||
/// Performs the conversion.
|
/// Performs the conversion.
|
||||||
@@ -158,7 +190,7 @@ impl<'a, 'lua> IntoIterator for &'a MultiValue<'lua> {
|
|||||||
type IntoIter = iter::Rev<slice::Iter<'a, Value<'lua>>>;
|
type IntoIter = iter::Rev<slice::Iter<'a, Value<'lua>>>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
(&self.0).into_iter().rev()
|
(&self.0).iter().rev()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+430
@@ -0,0 +1,430 @@
|
|||||||
|
#![cfg(feature = "async")]
|
||||||
|
#![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",
|
||||||
|
allow(unused_attributes)
|
||||||
|
)]
|
||||||
|
extern "system" {}
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::{
|
||||||
|
atomic::{AtomicI64, Ordering},
|
||||||
|
Arc,
|
||||||
|
};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use futures_timer::Delay;
|
||||||
|
use futures_util::stream::TryStreamExt;
|
||||||
|
|
||||||
|
use mlua::{
|
||||||
|
Error, Function, Lua, Result, Table, TableExt, Thread, UserData, UserDataMethods, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_async_function() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
let f = lua
|
||||||
|
.create_async_function(|_lua, (a, b, c): (i64, i64, i64)| async move { Ok((a + b) * c) })?;
|
||||||
|
lua.globals().set("f", f)?;
|
||||||
|
|
||||||
|
let res: i64 = lua.load("f(1, 2, 3)").eval_async().await?;
|
||||||
|
assert_eq!(res, 9);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_async_sleep() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
let sleep = lua.create_async_function(move |_lua, n: u64| async move {
|
||||||
|
Delay::new(Duration::from_millis(n)).await;
|
||||||
|
Ok(format!("elapsed:{}ms", n))
|
||||||
|
})?;
|
||||||
|
lua.globals().set("sleep", sleep)?;
|
||||||
|
|
||||||
|
let res: String = lua.load(r"return sleep(...)").call_async(100).await?;
|
||||||
|
assert_eq!(res, "elapsed:100ms");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_async_call() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
let hello = lua.create_async_function(|_lua, name: String| async move {
|
||||||
|
Delay::new(Duration::from_millis(10)).await;
|
||||||
|
Ok(format!("hello, {}!", name))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
match hello.call::<_, ()>("alex") {
|
||||||
|
Err(Error::RuntimeError(_)) => {}
|
||||||
|
_ => panic!(
|
||||||
|
"non-async executing async function must fail on the yield stage with RuntimeError"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(hello.call_async::<_, String>("alex").await?, "hello, alex!");
|
||||||
|
|
||||||
|
// Executing non-async functions using async call is allowed
|
||||||
|
let sum = lua.create_function(|_lua, (a, b): (i64, i64)| return Ok(a + b))?;
|
||||||
|
assert_eq!(sum.call_async::<_, i64>((5, 1)).await?, 6);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
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 plus_10 = sum.bind(10)?;
|
||||||
|
lua.globals().set("plus_10", plus_10)?;
|
||||||
|
|
||||||
|
assert_eq!(lua.load("plus_10(-1)").eval_async::<i64>().await?, 9);
|
||||||
|
assert_eq!(lua.load("plus_10(1)").eval_async::<i64>().await?, 11);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_async_handle_yield() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
let sum = lua.create_async_function(|_lua, (a, b): (i64, i64)| async move {
|
||||||
|
Delay::new(Duration::from_millis(10)).await;
|
||||||
|
Ok(a + b)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
lua.globals().set("sleep_sum", sum)?;
|
||||||
|
|
||||||
|
let res: String = lua
|
||||||
|
.load(
|
||||||
|
r#"
|
||||||
|
sum = sleep_sum(6, 7)
|
||||||
|
assert(sum == 13)
|
||||||
|
coroutine.yield("in progress")
|
||||||
|
return "done"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.call_async(())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
assert_eq!(res, "done");
|
||||||
|
|
||||||
|
let min = lua
|
||||||
|
.load(
|
||||||
|
r#"
|
||||||
|
function (a, b)
|
||||||
|
coroutine.yield("ignore me")
|
||||||
|
if a < b then return a else return b end
|
||||||
|
end
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.eval::<Function>()?;
|
||||||
|
assert_eq!(min.call_async::<_, i64>((-1, 1)).await?, -1);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_async_return_async_closure() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
let f = lua.create_async_function(|lua, a: i64| async move {
|
||||||
|
Delay::new(Duration::from_millis(10)).await;
|
||||||
|
|
||||||
|
let g = lua.create_async_function(move |_, b: i64| async move {
|
||||||
|
Delay::new(Duration::from_millis(10)).await;
|
||||||
|
return Ok(a + b);
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(g)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
lua.globals().set("f", f)?;
|
||||||
|
|
||||||
|
let res: i64 = lua
|
||||||
|
.load("local g = f(1); return g(2) + g(3)")
|
||||||
|
.call_async(())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
assert_eq!(res, 7);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_async_thread_stream() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
let thread = lua.create_thread(
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
function (sum)
|
||||||
|
for i = 1,10 do
|
||||||
|
sum = sum + i
|
||||||
|
coroutine.yield(sum)
|
||||||
|
end
|
||||||
|
return sum
|
||||||
|
end
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.eval()?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let mut stream = thread.into_async::<_, i64>(1);
|
||||||
|
let mut sum = 0;
|
||||||
|
while let Some(n) = stream.try_next().await? {
|
||||||
|
sum += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(sum, 286);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_async_thread() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
let cnt = Arc::new(10); // sleep 10ms
|
||||||
|
let cnt2 = cnt.clone();
|
||||||
|
let f = lua.create_async_function(move |_lua, ()| {
|
||||||
|
let cnt3 = cnt2.clone();
|
||||||
|
async move {
|
||||||
|
Delay::new(Duration::from_millis(*cnt3.as_ref())).await;
|
||||||
|
Ok("done")
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let res: String = lua.create_thread(f)?.into_async(()).await?;
|
||||||
|
|
||||||
|
assert_eq!(res, "done");
|
||||||
|
|
||||||
|
assert_eq!(Arc::strong_count(&cnt), 2);
|
||||||
|
lua.gc_collect()?; // thread_s is non-resumable and subject to garbage collection
|
||||||
|
assert_eq!(Arc::strong_count(&cnt), 1);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_async_table() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
let table = lua.create_table()?;
|
||||||
|
table.set("val", 10)?;
|
||||||
|
|
||||||
|
let get_value = lua.create_async_function(|_, table: Table| async move {
|
||||||
|
Delay::new(Duration::from_millis(10)).await;
|
||||||
|
table.get::<_, i64>("val")
|
||||||
|
})?;
|
||||||
|
table.set("get_value", get_value)?;
|
||||||
|
|
||||||
|
let set_value = lua.create_async_function(|_, (table, n): (Table, i64)| async move {
|
||||||
|
Delay::new(Duration::from_millis(10)).await;
|
||||||
|
table.set("val", n)
|
||||||
|
})?;
|
||||||
|
table.set("set_value", set_value)?;
|
||||||
|
|
||||||
|
let sleep = lua.create_async_function(|_, n| async move {
|
||||||
|
Delay::new(Duration::from_millis(n)).await;
|
||||||
|
Ok(format!("elapsed:{}ms", n))
|
||||||
|
})?;
|
||||||
|
table.set("sleep", sleep)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
table
|
||||||
|
.call_async_method::<_, _, i64>("get_value", ())
|
||||||
|
.await?,
|
||||||
|
10
|
||||||
|
);
|
||||||
|
table.call_async_method("set_value", 15).await?;
|
||||||
|
assert_eq!(
|
||||||
|
table
|
||||||
|
.call_async_method::<_, _, i64>("get_value", ())
|
||||||
|
.await?,
|
||||||
|
15
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
table
|
||||||
|
.call_async_function::<_, _, String>("sleep", 7)
|
||||||
|
.await?,
|
||||||
|
"elapsed:7ms"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_async_userdata() -> Result<()> {
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct MyUserData(Arc<AtomicI64>);
|
||||||
|
|
||||||
|
impl UserData for MyUserData {
|
||||||
|
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
methods.add_async_method("get_value", |_, data, ()| async move {
|
||||||
|
Delay::new(Duration::from_millis(10)).await;
|
||||||
|
Ok(data.0.load(Ordering::Relaxed))
|
||||||
|
});
|
||||||
|
|
||||||
|
methods.add_async_method("set_value", |_, data, n| async move {
|
||||||
|
Delay::new(Duration::from_millis(10)).await;
|
||||||
|
data.0.store(n, Ordering::Relaxed);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
|
methods.add_async_function("sleep", |_, n| async move {
|
||||||
|
Delay::new(Duration::from_millis(n)).await;
|
||||||
|
Ok(format!("elapsed:{}ms", n))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let lua = Lua::new();
|
||||||
|
let globals = lua.globals();
|
||||||
|
|
||||||
|
let userdata = lua.create_userdata(MyUserData(Arc::new(AtomicI64::new(11))))?;
|
||||||
|
globals.set("userdata", userdata.clone())?;
|
||||||
|
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
assert(userdata:get_value() == 11)
|
||||||
|
userdata:set_value(12)
|
||||||
|
assert(userdata.sleep(5) == "elapsed:5ms")
|
||||||
|
assert(userdata:get_value() == 12)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.exec_async()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_async_scope() -> Result<()> {
|
||||||
|
let ref lua = Lua::new();
|
||||||
|
|
||||||
|
let ref rc = Rc::new(Cell::new(0));
|
||||||
|
|
||||||
|
let fut = lua.async_scope(|scope| async move {
|
||||||
|
let f = scope.create_async_function(move |_, n: u64| {
|
||||||
|
let rc2 = rc.clone();
|
||||||
|
async move {
|
||||||
|
rc2.set(42);
|
||||||
|
Delay::new(Duration::from_millis(n)).await;
|
||||||
|
assert_eq!(Rc::strong_count(&rc2), 2);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
lua.globals().set("f", f.clone())?;
|
||||||
|
|
||||||
|
assert_eq!(Rc::strong_count(rc), 1);
|
||||||
|
let _ = f.call_async::<u64, ()>(10).await?;
|
||||||
|
assert_eq!(Rc::strong_count(rc), 1);
|
||||||
|
|
||||||
|
// Create future in partialy polled state (Poll::Pending)
|
||||||
|
let g = lua.create_thread(f)?;
|
||||||
|
g.resume::<u64, ()>(10)?;
|
||||||
|
lua.globals().set("g", g)?;
|
||||||
|
assert_eq!(Rc::strong_count(rc), 2);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(Rc::strong_count(rc), 1);
|
||||||
|
let _ = fut.await?;
|
||||||
|
assert_eq!(Rc::strong_count(rc), 1);
|
||||||
|
|
||||||
|
match lua
|
||||||
|
.globals()
|
||||||
|
.get::<_, Function>("f")?
|
||||||
|
.call_async::<_, ()>(10)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Err(Error::CallbackError { ref cause, .. }) => match cause.as_ref() {
|
||||||
|
Error::CallbackDestructed => {}
|
||||||
|
e => panic!("expected `CallbackDestructed` error cause, got {:?}", e),
|
||||||
|
},
|
||||||
|
r => panic!("improper return for destructed function: {:?}", r),
|
||||||
|
};
|
||||||
|
|
||||||
|
match lua.globals().get::<_, Thread>("g")?.resume::<_, Value>(()) {
|
||||||
|
Err(Error::CallbackError { ref cause, .. }) => match cause.as_ref() {
|
||||||
|
Error::CallbackDestructed => {}
|
||||||
|
e => panic!("expected `CallbackDestructed` error cause, got {:?}", e),
|
||||||
|
},
|
||||||
|
r => panic!("improper return for destructed function: {:?}", r),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_async_scope_userdata() -> Result<()> {
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct MyUserData(Arc<AtomicI64>);
|
||||||
|
|
||||||
|
impl UserData for MyUserData {
|
||||||
|
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
methods.add_async_method("get_value", |_, data, ()| async move {
|
||||||
|
Delay::new(Duration::from_millis(10)).await;
|
||||||
|
Ok(data.0.load(Ordering::Relaxed))
|
||||||
|
});
|
||||||
|
|
||||||
|
methods.add_async_method("set_value", |_, data, n| async move {
|
||||||
|
Delay::new(Duration::from_millis(10)).await;
|
||||||
|
data.0.store(n, Ordering::Relaxed);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
|
methods.add_async_function("sleep", |_, n| async move {
|
||||||
|
Delay::new(Duration::from_millis(n)).await;
|
||||||
|
Ok(format!("elapsed:{}ms", n))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ref lua = Lua::new();
|
||||||
|
|
||||||
|
let ref arc = Arc::new(AtomicI64::new(11));
|
||||||
|
|
||||||
|
lua.async_scope(|scope| async move {
|
||||||
|
let ud = scope.create_userdata(MyUserData(arc.clone()))?;
|
||||||
|
lua.globals().set("userdata", ud)?;
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
assert(userdata:get_value() == 11)
|
||||||
|
userdata:set_value(12)
|
||||||
|
assert(userdata.sleep(5) == "elapsed:5ms")
|
||||||
|
assert(userdata:get_value() == 12)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.exec_async()
|
||||||
|
.await
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
assert_eq!(Arc::strong_count(arc), 1);
|
||||||
|
|
||||||
|
match lua.load("userdata:get_value()").exec_async().await {
|
||||||
|
Err(Error::CallbackError { ref cause, .. }) => match cause.as_ref() {
|
||||||
|
Error::CallbackDestructed => {}
|
||||||
|
e => panic!("expected `CallbackDestructed` error cause, got {:?}", e),
|
||||||
|
},
|
||||||
|
r => panic!("improper return for destructed userdata: {:?}", r),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,3 +1,15 @@
|
|||||||
|
#![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",
|
||||||
|
allow(unused_attributes)
|
||||||
|
)]
|
||||||
|
extern "system" {}
|
||||||
|
|
||||||
use bstr::{BStr, BString};
|
use bstr::{BStr, BString};
|
||||||
use mlua::{Lua, Result};
|
use mlua::{Lua, Result};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn test_compilation() {
|
||||||
|
let t = trybuild::TestCases::new();
|
||||||
|
|
||||||
|
t.compile_fail("tests/compile/function_borrow.rs");
|
||||||
|
t.compile_fail("tests/compile/lua_norefunwindsafe.rs");
|
||||||
|
t.compile_fail("tests/compile/ref_nounwindsafe.rs");
|
||||||
|
t.compile_fail("tests/compile/scope_callback_capture.rs");
|
||||||
|
t.compile_fail("tests/compile/scope_callback_inner.rs");
|
||||||
|
t.compile_fail("tests/compile/scope_callback_outer.rs");
|
||||||
|
t.compile_fail("tests/compile/scope_invariance.rs");
|
||||||
|
t.compile_fail("tests/compile/scope_mutable_aliasing.rs");
|
||||||
|
t.compile_fail("tests/compile/scope_userdata_borrow.rs");
|
||||||
|
t.compile_fail("tests/compile/static_callback_args.rs");
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
t.compile_fail("tests/compile/async_nonstatic_userdata.rs");
|
||||||
|
|
||||||
|
#[cfg(feature = "send")]
|
||||||
|
t.compile_fail("tests/compile/non_send.rs");
|
||||||
|
#[cfg(not(feature = "send"))]
|
||||||
|
t.pass("tests/compile/non_send.rs");
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
use mlua::{Lua, UserData, UserDataMethods};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let ref lua = Lua::new();
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct MyUserData<'a>(&'a i64);
|
||||||
|
|
||||||
|
impl<'a> UserData for MyUserData<'a> {
|
||||||
|
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
methods.add_async_method("print", |_, data, ()| async move {
|
||||||
|
println!("{}", data.0);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
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> {
|
||||||
|
| ^^
|
||||||
|
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 {
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
error[E0277]: the type `UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||||
|
--> $DIR/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
|
||||||
|
|
|
||||||
|
::: $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`
|
||||||
|
|
|
||||||
|
= 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]`
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
use std::cell::Cell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use mlua::{Lua, Result};
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
let data = Rc::new(Cell::new(0));
|
||||||
|
|
||||||
|
lua.create_function(move |_, ()| {
|
||||||
|
Ok(data.get())
|
||||||
|
})?
|
||||||
|
.call::<_, i32>(())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
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]`
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
error[E0277]: the type `UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||||
|
--> $DIR/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
|
||||||
|
|
|
||||||
|
::: $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`
|
||||||
|
|
|
||||||
|
= 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]`
|
||||||
+3
-7
@@ -1,15 +1,11 @@
|
|||||||
use mlua::{Lua, Table, Result};
|
use mlua::{Lua, Table};
|
||||||
|
|
||||||
struct Test {
|
|
||||||
field: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
lua.scope(|scope| -> Result<()> {
|
lua.scope(|scope| {
|
||||||
let mut inner: Option<Table> = None;
|
let mut inner: Option<Table> = None;
|
||||||
let f = scope
|
let f = scope
|
||||||
.create_function_mut(move |lua, t: Table| {
|
.create_function_mut(move |_, t: Table| {
|
||||||
if let Some(old) = inner.take() {
|
if let Some(old) = inner.take() {
|
||||||
// Access old callback `Lua`.
|
// Access old callback `Lua`.
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
warning: unused variable: `old`
|
||||||
|
--> $DIR/scope_callback_capture.rs:9:29
|
||||||
|
|
|
||||||
|
9 | if let Some(old) = inner.take() {
|
||||||
|
| ^^^ help: if this is intentional, prefix it with an underscore: `_old`
|
||||||
|
|
|
||||||
|
= note: `#[warn(unused_variables)]` on by default
|
||||||
|
|
||||||
|
error[E0521]: borrowed data escapes outside of closure
|
||||||
|
--> $DIR/scope_callback_capture.rs:7:17
|
||||||
|
|
|
||||||
|
5 | lua.scope(|scope| {
|
||||||
|
| -----
|
||||||
|
| |
|
||||||
|
| `scope` declared here, outside of the closure body
|
||||||
|
| `scope` is a reference that is only valid in the closure body
|
||||||
|
6 | let mut inner: Option<Table> = None;
|
||||||
|
7 | let f = scope
|
||||||
|
| _________________^
|
||||||
|
8 | | .create_function_mut(move |_, t: Table| {
|
||||||
|
9 | | if let Some(old) = inner.take() {
|
||||||
|
10 | | // Access old callback `Lua`.
|
||||||
|
... |
|
||||||
|
13 | | Ok(())
|
||||||
|
14 | | })?;
|
||||||
|
| |______________^ `scope` escapes the closure body here
|
||||||
@@ -1,12 +1,8 @@
|
|||||||
use mlua::{Lua, Table, Result};
|
use mlua::{Lua, Table};
|
||||||
|
|
||||||
struct Test {
|
|
||||||
field: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
lua.scope(|scope| -> Result<()> {
|
lua.scope(|scope| {
|
||||||
let mut inner: Option<Table> = None;
|
let mut inner: Option<Table> = None;
|
||||||
let f = scope
|
let f = scope
|
||||||
.create_function_mut(|_, t: Table| {
|
.create_function_mut(|_, t: Table| {
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
error[E0521]: borrowed data escapes outside of closure
|
||||||
|
--> $DIR/scope_callback_inner.rs:7:17
|
||||||
|
|
|
||||||
|
5 | lua.scope(|scope| {
|
||||||
|
| -----
|
||||||
|
| |
|
||||||
|
| `scope` declared here, outside of the closure body
|
||||||
|
| `scope` is a reference that is only valid in the closure body
|
||||||
|
6 | let mut inner: Option<Table> = None;
|
||||||
|
7 | let f = scope
|
||||||
|
| _________________^
|
||||||
|
8 | | .create_function_mut(|_, t: Table| {
|
||||||
|
9 | | inner = Some(t);
|
||||||
|
10 | | Ok(())
|
||||||
|
11 | | })?;
|
||||||
|
| |______________^ `scope` escapes the closure body here
|
||||||
|
|
||||||
|
error[E0373]: closure may outlive the current function, but it borrows `inner`, which is owned by the current function
|
||||||
|
--> $DIR/scope_callback_inner.rs:8:34
|
||||||
|
|
|
||||||
|
5 | lua.scope(|scope| {
|
||||||
|
| ----- has type `&Scope<'_, '2>`
|
||||||
|
...
|
||||||
|
8 | .create_function_mut(|_, t: Table| {
|
||||||
|
| ^^^^^^^^^^^^^ may outlive borrowed value `inner`
|
||||||
|
9 | inner = Some(t);
|
||||||
|
| ----- `inner` is borrowed here
|
||||||
|
|
|
||||||
|
note: function requires argument type to outlive `'2`
|
||||||
|
--> $DIR/scope_callback_inner.rs:7:17
|
||||||
|
|
|
||||||
|
7 | let f = scope
|
||||||
|
| _________________^
|
||||||
|
8 | | .create_function_mut(|_, t: Table| {
|
||||||
|
9 | | inner = Some(t);
|
||||||
|
10 | | Ok(())
|
||||||
|
11 | | })?;
|
||||||
|
| |______________^
|
||||||
|
help: to force the closure to take ownership of `inner` (and any other referenced variables), use the `move` keyword
|
||||||
|
|
|
||||||
|
8 | .create_function_mut(move |_, t: Table| {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
@@ -1,13 +1,9 @@
|
|||||||
use mlua::{Lua, Table, Result};
|
use mlua::{Lua, Table};
|
||||||
|
|
||||||
struct Test {
|
|
||||||
field: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
let mut outer: Option<Table> = None;
|
let mut outer: Option<Table> = None;
|
||||||
lua.scope(|scope| -> Result<()> {
|
lua.scope(|scope| {
|
||||||
let f = scope
|
let f = scope
|
||||||
.create_function_mut(|_, t: Table| {
|
.create_function_mut(|_, t: Table| {
|
||||||
outer = Some(t);
|
outer = Some(t);
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
error[E0521]: borrowed data escapes outside of closure
|
||||||
|
--> $DIR/scope_callback_outer.rs:7:17
|
||||||
|
|
|
||||||
|
6 | lua.scope(|scope| {
|
||||||
|
| -----
|
||||||
|
| |
|
||||||
|
| `scope` declared here, outside of the closure body
|
||||||
|
| `scope` is a reference that is only valid in the closure body
|
||||||
|
7 | let f = scope
|
||||||
|
| _________________^
|
||||||
|
8 | | .create_function_mut(|_, t: Table| {
|
||||||
|
9 | | outer = Some(t);
|
||||||
|
10 | | Ok(())
|
||||||
|
11 | | })?;
|
||||||
|
| |______________^ `scope` escapes the closure body here
|
||||||
|
|
||||||
|
error[E0597]: `outer` does not live long enough
|
||||||
|
--> $DIR/scope_callback_outer.rs:9:17
|
||||||
|
|
|
||||||
|
6 | lua.scope(|scope| {
|
||||||
|
| ------- value captured here
|
||||||
|
...
|
||||||
|
9 | outer = Some(t);
|
||||||
|
| ^^^^^ borrowed value does not live long enough
|
||||||
|
...
|
||||||
|
15 | }
|
||||||
|
| -
|
||||||
|
| |
|
||||||
|
| `outer` dropped here while still borrowed
|
||||||
|
| borrow might be used here, when `outer` is dropped and runs the destructor for type `Option<LuaTable<'_>>`
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use mlua::{Lua, Result};
|
use mlua::Lua;
|
||||||
|
|
||||||
struct Test {
|
struct Test {
|
||||||
field: i32,
|
field: i32,
|
||||||
@@ -6,7 +6,7 @@ struct Test {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
lua.scope(|scope| -> Result<()> {
|
lua.scope(|scope| {
|
||||||
let f = {
|
let f = {
|
||||||
let mut test = Test { field: 0 };
|
let mut test = Test { field: 0 };
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
error[E0373]: closure may outlive the current function, but it borrows `test`, which is owned by the current function
|
error[E0373]: closure may outlive the current function, but it borrows `test`, which is owned by the current function
|
||||||
--> $DIR/scope_invariance.rs:14:38
|
--> $DIR/scope_invariance.rs:14:38
|
||||||
|
|
|
|
||||||
9 | lua.scope(|scope| -> Result<()> {
|
9 | lua.scope(|scope| {
|
||||||
| ----- has type `&mlua::scope::Scope<'_, '1>`
|
| ----- has type `&Scope<'_, '1>`
|
||||||
...
|
...
|
||||||
14 | .create_function_mut(|_, ()| {
|
14 | .create_function_mut(|_, ()| {
|
||||||
| ^^^^^^^ may outlive borrowed value `test`
|
| ^^^^^^^ may outlive borrowed value `test`
|
||||||
+7
-7
@@ -1,15 +1,15 @@
|
|||||||
use mlua::{Lua, UserData, Result};
|
use mlua::{Lua, UserData};
|
||||||
|
|
||||||
struct MyUserData<'a>(&'a mut i32);
|
|
||||||
impl<'a> UserData for MyUserData<'a> {}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
struct MyUserData<'a>(&'a mut i32);
|
||||||
|
impl<'a> UserData for MyUserData<'a> {};
|
||||||
|
|
||||||
let mut i = 1;
|
let mut i = 1;
|
||||||
|
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
lua.scope(|scope| -> Result<()> {
|
lua.scope(|scope| {
|
||||||
let _a = scope.create_nonstatic_userdata(MyUserData(&mut i))?;
|
let _a = scope.create_nonstatic_userdata(MyUserData(&mut i)).unwrap();
|
||||||
let _b = scope.create_nonstatic_userdata(MyUserData(&mut i))?;
|
let _b = scope.create_nonstatic_userdata(MyUserData(&mut i)).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
error[E0499]: cannot borrow `i` as mutable more than once at a time
|
error[E0499]: cannot borrow `i` as mutable more than once at a time
|
||||||
--> $DIR/scope_mutable_aliasing.rs:12:61
|
--> $DIR/scope_mutable_aliasing.rs:12:61
|
||||||
|
|
|
|
||||||
11 | let _a = scope.create_nonstatic_userdata(MyUserData(&mut i))?;
|
11 | let _a = scope.create_nonstatic_userdata(MyUserData(&mut i)).unwrap();
|
||||||
| ------ first mutable borrow occurs here
|
| ------ first mutable borrow occurs here
|
||||||
12 | let _b = scope.create_nonstatic_userdata(MyUserData(&mut i))?;
|
12 | let _b = scope.create_nonstatic_userdata(MyUserData(&mut i)).unwrap();
|
||||||
| ------------------------- ^^^^^^ second mutable borrow occurs here
|
| ------------------------- ^^^^^^ second mutable borrow occurs here
|
||||||
| |
|
| |
|
||||||
| first borrow later used by call
|
| first borrow later used by call
|
||||||
+6
-7
@@ -1,19 +1,18 @@
|
|||||||
use mlua::{Lua, UserData, Result};
|
use mlua::{Lua, UserData};
|
||||||
|
|
||||||
struct MyUserData<'a>(&'a i32);
|
|
||||||
impl<'a> UserData for MyUserData<'a> {}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Should not allow userdata borrow to outlive lifetime of AnyUserData handle
|
// Should not allow userdata borrow to outlive lifetime of AnyUserData handle
|
||||||
|
struct MyUserData<'a>(&'a i32);
|
||||||
|
impl<'a> UserData for MyUserData<'a> {};
|
||||||
|
|
||||||
let igood = 1;
|
let igood = 1;
|
||||||
|
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
lua.scope(|scope| -> Result<()> {
|
lua.scope(|scope| {
|
||||||
let _ugood = scope.create_nonstatic_userdata(MyUserData(&igood))?;
|
let _ugood = scope.create_nonstatic_userdata(MyUserData(&igood)).unwrap();
|
||||||
let _ubad = {
|
let _ubad = {
|
||||||
let ibad = 42;
|
let ibad = 42;
|
||||||
scope.create_nonstatic_userdata(MyUserData(&ibad))?;
|
scope.create_nonstatic_userdata(MyUserData(&ibad)).unwrap();
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
+5
-5
@@ -1,13 +1,13 @@
|
|||||||
error[E0597]: `ibad` does not live long enough
|
error[E0597]: `ibad` does not live long enough
|
||||||
--> $DIR/scope_userdata_borrow.rs:16:56
|
--> $DIR/scope_userdata_borrow.rs:15:56
|
||||||
|
|
|
|
||||||
12 | lua.scope(|scope| -> Result<()> {
|
11 | lua.scope(|scope| {
|
||||||
| ----- has type `&mlua::scope::Scope<'_, '1>`
|
| ----- has type `&Scope<'_, '1>`
|
||||||
...
|
...
|
||||||
16 | scope.create_nonstatic_userdata(MyUserData(&ibad))?;
|
15 | scope.create_nonstatic_userdata(MyUserData(&ibad)).unwrap();
|
||||||
| -------------------------------------------^^^^^--
|
| -------------------------------------------^^^^^--
|
||||||
| | |
|
| | |
|
||||||
| | borrowed value does not live long enough
|
| | borrowed value does not live long enough
|
||||||
| argument requires that `ibad` is borrowed for `'1`
|
| argument requires that `ibad` is borrowed for `'1`
|
||||||
17 | };
|
16 | };
|
||||||
| - `ibad` dropped here while still borrowed
|
| - `ibad` dropped here while still borrowed
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use mlua::{Lua, Result, Table};
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
thread_local! {
|
||||||
|
static BAD_TIME: RefCell<Option<Table<'static>>> = RefCell::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
lua.create_function(|_, table: Table| {
|
||||||
|
BAD_TIME.with(|bt| {
|
||||||
|
*bt.borrow_mut() = Some(table);
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
})?
|
||||||
|
.call::<_, ()>(lua.create_table()?)?;
|
||||||
|
|
||||||
|
// In debug, this will panic with a reference leak before getting to the next part but
|
||||||
|
// it segfaults anyway.
|
||||||
|
drop(lua);
|
||||||
|
|
||||||
|
BAD_TIME.with(|bt| {
|
||||||
|
println!(
|
||||||
|
"you're gonna have a bad time: {}",
|
||||||
|
bt.borrow().as_ref().unwrap().len().unwrap()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
error[E0597]: `lua` does not live long enough
|
||||||
|
--> $DIR/static_callback_args.rs:12:5
|
||||||
|
|
|
||||||
|
12 | lua.create_function(|_, table: Table| {
|
||||||
|
| -^^
|
||||||
|
| |
|
||||||
|
| _____borrowed value does not live long enough
|
||||||
|
| |
|
||||||
|
13 | | BAD_TIME.with(|bt| {
|
||||||
|
14 | | *bt.borrow_mut() = Some(table);
|
||||||
|
15 | | });
|
||||||
|
16 | | Ok(())
|
||||||
|
17 | | })?
|
||||||
|
| |______- 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
|
||||||
|
|
|
||||||
|
12 | lua.create_function(|_, table: Table| {
|
||||||
|
| ---
|
||||||
|
| |
|
||||||
|
| _____borrow of `lua` occurs here
|
||||||
|
| |
|
||||||
|
13 | | BAD_TIME.with(|bt| {
|
||||||
|
14 | | *bt.borrow_mut() = Some(table);
|
||||||
|
15 | | });
|
||||||
|
16 | | Ok(())
|
||||||
|
17 | | })?
|
||||||
|
| |______- argument requires that `lua` is borrowed for `'static`
|
||||||
|
...
|
||||||
|
22 | drop(lua);
|
||||||
|
| ^^^ move out of `lua` occurs here
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn test_compile_fail() {
|
|
||||||
let t = trybuild::TestCases::new();
|
|
||||||
t.compile_fail("tests/compile_fail/*.rs");
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
error[E0277]: the type `std::cell::UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
|
||||||
--> $DIR/lua_norefunwindsafe.rs:7:5
|
|
||||||
|
|
|
||||||
7 | catch_unwind(|| lua.create_table().unwrap());
|
|
||||||
| ^^^^^^^^^^^^ `std::cell::UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
|
||||||
|
|
|
||||||
= help: within `mlua::lua::Lua`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<()>`
|
|
||||||
= note: required because it appears within the type `std::marker::PhantomData<std::cell::UnsafeCell<()>>`
|
|
||||||
= 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`
|
|
||||||
= note: required because it appears within the type `[closure@$DIR/tests/compile_fail/lua_norefunwindsafe.rs:7:18: 7:48 lua:&mlua::lua::Lua]`
|
|
||||||
|
|
||||||
error[E0277]: the type `std::cell::UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
|
||||||
--> $DIR/lua_norefunwindsafe.rs:7:5
|
|
||||||
|
|
|
||||||
7 | catch_unwind(|| lua.create_table().unwrap());
|
|
||||||
| ^^^^^^^^^^^^ `std::cell::UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
|
||||||
|
|
|
||||||
= 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 `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`
|
|
||||||
= note: required because it appears within the type `[closure@$DIR/tests/compile_fail/lua_norefunwindsafe.rs:7:18: 7:48 lua:&mlua::lua::Lua]`
|
|
||||||
|
|
||||||
error[E0277]: the type `std::cell::UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
|
||||||
--> $DIR/lua_norefunwindsafe.rs:7:5
|
|
||||||
|
|
|
||||||
7 | catch_unwind(|| lua.create_table().unwrap());
|
|
||||||
| ^^^^^^^^^^^^ `std::cell::UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
|
||||||
|
|
|
||||||
= 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 `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`
|
|
||||||
= note: required because it appears within the type `[closure@$DIR/tests/compile_fail/lua_norefunwindsafe.rs:7:18: 7:48 lua:&mlua::lua::Lua]`
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
error[E0277]: the type `std::cell::UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
|
||||||
--> $DIR/ref_nounwindsafe.rs:8:5
|
|
||||||
|
|
|
||||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
|
||||||
| ^^^^^^^^^^^^ `std::cell::UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
|
||||||
|
|
|
||||||
= help: within `mlua::lua::Lua`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<()>`
|
|
||||||
= note: required because it appears within the type `std::marker::PhantomData<std::cell::UnsafeCell<()>>`
|
|
||||||
= 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`
|
|
||||||
= note: required because it appears within the type `mlua::types::LuaRef<'_>`
|
|
||||||
= note: required because it appears within the type `mlua::table::Table<'_>`
|
|
||||||
= note: required because it appears within the type `[closure@$DIR/tests/compile_fail/ref_nounwindsafe.rs:8:18: 8:54 table:mlua::table::Table<'_>]`
|
|
||||||
|
|
||||||
error[E0277]: the type `std::cell::UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
|
||||||
--> $DIR/ref_nounwindsafe.rs:8:5
|
|
||||||
|
|
|
||||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
|
||||||
| ^^^^^^^^^^^^ `std::cell::UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
|
||||||
|
|
|
||||||
= 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 `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`
|
|
||||||
= note: required because it appears within the type `mlua::types::LuaRef<'_>`
|
|
||||||
= note: required because it appears within the type `mlua::table::Table<'_>`
|
|
||||||
= note: required because it appears within the type `[closure@$DIR/tests/compile_fail/ref_nounwindsafe.rs:8:18: 8:54 table:mlua::table::Table<'_>]`
|
|
||||||
|
|
||||||
error[E0277]: the type `std::cell::UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
|
||||||
--> $DIR/ref_nounwindsafe.rs:8:5
|
|
||||||
|
|
|
||||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
|
||||||
| ^^^^^^^^^^^^ `std::cell::UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
|
||||||
|
|
|
||||||
= 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 `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`
|
|
||||||
= note: required because it appears within the type `mlua::types::LuaRef<'_>`
|
|
||||||
= note: required because it appears within the type `mlua::table::Table<'_>`
|
|
||||||
= note: required because it appears within the type `[closure@$DIR/tests/compile_fail/ref_nounwindsafe.rs:8:18: 8:54 table:mlua::table::Table<'_>]`
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
|
|
||||||
--> $DIR/scope_callback_capture.rs:12:14
|
|
||||||
|
|
|
||||||
12 | .create_function_mut(move |lua, t: Table| {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 9:15...
|
|
||||||
--> $DIR/scope_callback_capture.rs:9:15
|
|
||||||
|
|
|
||||||
9 | lua.scope(|scope| -> Result<()> {
|
|
||||||
| _______________^
|
|
||||||
10 | | let mut inner: Option<Table> = None;
|
|
||||||
11 | | let f = scope
|
|
||||||
12 | | .create_function_mut(move |lua, t: Table| {
|
|
||||||
... |
|
|
||||||
20 | | Ok(())
|
|
||||||
21 | | });
|
|
||||||
| |_____^
|
|
||||||
note: ...so that reference does not outlive borrowed content
|
|
||||||
--> $DIR/scope_callback_capture.rs:11:17
|
|
||||||
|
|
|
||||||
11 | let f = scope
|
|
||||||
| ^^^^^
|
|
||||||
note: but, the lifetime must be valid for the method call at 9:5...
|
|
||||||
--> $DIR/scope_callback_capture.rs:9:5
|
|
||||||
|
|
|
||||||
9 | / lua.scope(|scope| -> Result<()> {
|
|
||||||
10 | | let mut inner: Option<Table> = None;
|
|
||||||
11 | | let f = scope
|
|
||||||
12 | | .create_function_mut(move |lua, t: Table| {
|
|
||||||
... |
|
|
||||||
20 | | Ok(())
|
|
||||||
21 | | });
|
|
||||||
| |______^
|
|
||||||
note: ...so that a type/lifetime parameter is in scope here
|
|
||||||
--> $DIR/scope_callback_capture.rs:9:5
|
|
||||||
|
|
|
||||||
9 | / lua.scope(|scope| -> Result<()> {
|
|
||||||
10 | | let mut inner: Option<Table> = None;
|
|
||||||
11 | | let f = scope
|
|
||||||
12 | | .create_function_mut(move |lua, t: Table| {
|
|
||||||
... |
|
|
||||||
20 | | Ok(())
|
|
||||||
21 | | });
|
|
||||||
| |______^
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
|
|
||||||
--> $DIR/scope_callback_inner.rs:12:14
|
|
||||||
|
|
|
||||||
12 | .create_function_mut(|_, t: Table| {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 9:15...
|
|
||||||
--> $DIR/scope_callback_inner.rs:9:15
|
|
||||||
|
|
|
||||||
9 | lua.scope(|scope| -> Result<()> {
|
|
||||||
| _______________^
|
|
||||||
10 | | let mut inner: Option<Table> = None;
|
|
||||||
11 | | let f = scope
|
|
||||||
12 | | .create_function_mut(|_, t: Table| {
|
|
||||||
... |
|
|
||||||
17 | | Ok(())
|
|
||||||
18 | | });
|
|
||||||
| |_____^
|
|
||||||
note: ...so that reference does not outlive borrowed content
|
|
||||||
--> $DIR/scope_callback_inner.rs:11:17
|
|
||||||
|
|
|
||||||
11 | let f = scope
|
|
||||||
| ^^^^^
|
|
||||||
note: but, the lifetime must be valid for the method call at 9:5...
|
|
||||||
--> $DIR/scope_callback_inner.rs:9:5
|
|
||||||
|
|
|
||||||
9 | / lua.scope(|scope| -> Result<()> {
|
|
||||||
10 | | let mut inner: Option<Table> = None;
|
|
||||||
11 | | let f = scope
|
|
||||||
12 | | .create_function_mut(|_, t: Table| {
|
|
||||||
... |
|
|
||||||
17 | | Ok(())
|
|
||||||
18 | | });
|
|
||||||
| |______^
|
|
||||||
note: ...so that a type/lifetime parameter is in scope here
|
|
||||||
--> $DIR/scope_callback_inner.rs:9:5
|
|
||||||
|
|
|
||||||
9 | / lua.scope(|scope| -> Result<()> {
|
|
||||||
10 | | let mut inner: Option<Table> = None;
|
|
||||||
11 | | let f = scope
|
|
||||||
12 | | .create_function_mut(|_, t: Table| {
|
|
||||||
... |
|
|
||||||
17 | | Ok(())
|
|
||||||
18 | | });
|
|
||||||
| |______^
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
error: borrowed data cannot be stored outside of its closure
|
|
||||||
--> $DIR/scope_callback_outer.rs:11:17
|
|
||||||
|
|
|
||||||
9 | let mut outer: Option<Table> = None;
|
|
||||||
| --------- ...so that variable is valid at time of its declaration
|
|
||||||
10 | lua.scope(|scope| -> Result<()> {
|
|
||||||
| --------------------- borrowed data cannot outlive this closure
|
|
||||||
11 | let f = scope
|
|
||||||
| ^^^^^ cannot be stored outside of its closure
|
|
||||||
12 | .create_function_mut(|_, t: Table| {
|
|
||||||
| ------------------- cannot infer an appropriate lifetime...
|
|
||||||
@@ -1,3 +1,15 @@
|
|||||||
|
#![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",
|
||||||
|
allow(unused_attributes)
|
||||||
|
)]
|
||||||
|
extern "system" {}
|
||||||
|
|
||||||
use mlua::{Function, Lua, Result, String};
|
use mlua::{Function, Lua, Result, String};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -75,3 +87,17 @@ fn test_rust_function() -> Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dump() -> Result<()> {
|
||||||
|
let lua = unsafe { Lua::unsafe_new() };
|
||||||
|
|
||||||
|
let concat_lua = lua
|
||||||
|
.load(r#"function(arg1, arg2) return arg1 .. arg2 end"#)
|
||||||
|
.eval::<Function>()?;
|
||||||
|
let concat = lua.load(&concat_lua.dump(false)?).into_function()?;
|
||||||
|
|
||||||
|
assert_eq!(concat.call::<_, String>(("foo", "bar"))?, "foobar");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
+261
@@ -0,0 +1,261 @@
|
|||||||
|
#![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",
|
||||||
|
allow(unused_attributes)
|
||||||
|
)]
|
||||||
|
extern "system" {}
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::str;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use mlua::{Error, HookTriggers, Lua, Result, Value};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn line_counts() -> Result<()> {
|
||||||
|
let output = Arc::new(Mutex::new(Vec::new()));
|
||||||
|
let hook_output = output.clone();
|
||||||
|
|
||||||
|
let lua = Lua::new();
|
||||||
|
lua.set_hook(
|
||||||
|
HookTriggers {
|
||||||
|
every_line: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
move |_lua, debug| {
|
||||||
|
hook_output.lock().unwrap().push(debug.curr_line());
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
local x = 2 + 3
|
||||||
|
local y = x * 63
|
||||||
|
local z = string.len(x..", "..y)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.exec()?;
|
||||||
|
|
||||||
|
lua.remove_hook();
|
||||||
|
|
||||||
|
let output = output.lock().unwrap();
|
||||||
|
if cfg!(feature = "luajit") && lua.load("jit.version_num").eval::<i64>()? >= 20100 {
|
||||||
|
assert_eq!(*output, vec![2, 3, 4, 0, 4]);
|
||||||
|
} else {
|
||||||
|
assert_eq!(*output, vec![2, 3, 4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_calls() -> Result<()> {
|
||||||
|
let output = Arc::new(Mutex::new(Vec::new()));
|
||||||
|
let hook_output = output.clone();
|
||||||
|
|
||||||
|
let lua = Lua::new();
|
||||||
|
lua.set_hook(
|
||||||
|
HookTriggers {
|
||||||
|
on_calls: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
move |_lua, debug| {
|
||||||
|
let names = debug.names();
|
||||||
|
let source = debug.source();
|
||||||
|
let name = names.name.map(|s| str::from_utf8(s).unwrap().to_owned());
|
||||||
|
let what = source.what.map(|s| str::from_utf8(s).unwrap().to_owned());
|
||||||
|
hook_output.lock().unwrap().push((name, what));
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
local v = string.len("Hello World")
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.exec()?;
|
||||||
|
|
||||||
|
lua.remove_hook();
|
||||||
|
|
||||||
|
let output = output.lock().unwrap();
|
||||||
|
if cfg!(feature = "luajit") && lua.load("jit.version_num").eval::<i64>()? >= 20100 {
|
||||||
|
assert_eq!(
|
||||||
|
*output,
|
||||||
|
vec![
|
||||||
|
(None, Some("main".to_string())),
|
||||||
|
(Some("len".to_string()), Some("Lua".to_string()))
|
||||||
|
]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
assert_eq!(
|
||||||
|
*output,
|
||||||
|
vec![
|
||||||
|
(None, Some("main".to_string())),
|
||||||
|
(Some("len".to_string()), Some("C".to_string()))
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn error_within_hook() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
lua.set_hook(
|
||||||
|
HookTriggers {
|
||||||
|
every_line: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
|_lua, _debug| {
|
||||||
|
Err(Error::RuntimeError(
|
||||||
|
"Something happened in there!".to_string(),
|
||||||
|
))
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let err = lua
|
||||||
|
.load("x = 1")
|
||||||
|
.exec()
|
||||||
|
.expect_err("panic didn't propagate");
|
||||||
|
|
||||||
|
match err {
|
||||||
|
Error::CallbackError { cause, .. } => match cause.deref() {
|
||||||
|
Error::RuntimeError(s) => assert_eq!(s, "Something happened in there!"),
|
||||||
|
_ => panic!("wrong callback error kind caught"),
|
||||||
|
},
|
||||||
|
_ => panic!("wrong error kind caught"),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn limit_execution_instructions() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
let mut max_instructions = 10000;
|
||||||
|
|
||||||
|
#[cfg(feature = "luajit")]
|
||||||
|
// For LuaJIT disable JIT, as compiled code does not trigger hooks
|
||||||
|
lua.load("jit.off()").exec()?;
|
||||||
|
|
||||||
|
lua.set_hook(
|
||||||
|
HookTriggers {
|
||||||
|
every_nth_instruction: Some(30),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
move |_lua, _debug| {
|
||||||
|
max_instructions -= 30;
|
||||||
|
if max_instructions < 0 {
|
||||||
|
Err(Error::RuntimeError("time's up".to_string()))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
lua.globals().set("x", Value::Integer(0))?;
|
||||||
|
let _ = lua
|
||||||
|
.load(
|
||||||
|
r#"
|
||||||
|
for i = 1, 10000 do
|
||||||
|
x = x + 1
|
||||||
|
end
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.exec()
|
||||||
|
.expect_err("instruction limit didn't occur");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hook_removal() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
lua.set_hook(
|
||||||
|
HookTriggers {
|
||||||
|
every_nth_instruction: Some(1),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
|_lua, _debug| {
|
||||||
|
Err(Error::RuntimeError(
|
||||||
|
"this hook should've been removed by this time".to_string(),
|
||||||
|
))
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assert!(lua.load("local x = 1").exec().is_err());
|
||||||
|
lua.remove_hook();
|
||||||
|
assert!(lua.load("local x = 1").exec().is_ok());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hook_swap_within_hook() -> Result<()> {
|
||||||
|
thread_local! {
|
||||||
|
static TL_LUA: RefCell<Option<Lua>> = RefCell::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
TL_LUA.with(|tl| {
|
||||||
|
*tl.borrow_mut() = Some(Lua::new());
|
||||||
|
});
|
||||||
|
|
||||||
|
TL_LUA.with(|tl| {
|
||||||
|
tl.borrow().as_ref().unwrap().set_hook(
|
||||||
|
HookTriggers {
|
||||||
|
every_line: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
move |lua, _debug| {
|
||||||
|
lua.globals().set("ok", 1i64)?;
|
||||||
|
TL_LUA.with(|tl| {
|
||||||
|
tl.borrow().as_ref().unwrap().set_hook(
|
||||||
|
HookTriggers {
|
||||||
|
every_line: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
move |lua, _debug| {
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
if ok ~= nil then
|
||||||
|
ok = ok + 1
|
||||||
|
end
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.exec()
|
||||||
|
.expect("exec failure within hook");
|
||||||
|
TL_LUA.with(|tl| {
|
||||||
|
tl.borrow().as_ref().unwrap().remove_hook();
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
TL_LUA.with(|tl| {
|
||||||
|
let tl = tl.borrow();
|
||||||
|
let lua = tl.as_ref().unwrap();
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
local x = 1
|
||||||
|
x = 2
|
||||||
|
local y = 3
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.exec()?;
|
||||||
|
assert_eq!(lua.globals().get::<_, i64>("ok")?, 2);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
+44
-1
@@ -1,13 +1,56 @@
|
|||||||
|
#![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",
|
||||||
|
allow(unused_attributes)
|
||||||
|
)]
|
||||||
|
extern "system" {}
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use mlua::{Lua, Result, UserData};
|
use mlua::{Lua, Result, UserData};
|
||||||
|
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
|
use mlua::Error;
|
||||||
|
|
||||||
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
|
#[test]
|
||||||
|
fn test_memory_limit() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
let initial_memory = lua.used_memory();
|
||||||
|
assert!(
|
||||||
|
initial_memory > 0,
|
||||||
|
"used_memory reporting is wrong, lua uses memory for stdlib"
|
||||||
|
);
|
||||||
|
|
||||||
|
let f = lua
|
||||||
|
.load("local t = {}; for i = 1,10000 do t[i] = i end")
|
||||||
|
.into_function()?;
|
||||||
|
f.call::<_, ()>(()).expect("should trigger no memory limit");
|
||||||
|
|
||||||
|
lua.set_memory_limit(initial_memory + 10000)?;
|
||||||
|
match f.call::<_, ()>(()) {
|
||||||
|
Err(Error::MemoryError(_)) => {}
|
||||||
|
something_else => panic!("did not trigger memory error: {:?}", something_else),
|
||||||
|
};
|
||||||
|
|
||||||
|
lua.set_memory_limit(0)?;
|
||||||
|
f.call::<_, ()>(()).expect("should trigger no memory limit");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_gc_control() -> Result<()> {
|
fn test_gc_control() -> Result<()> {
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
let globals = lua.globals();
|
let globals = lua.globals();
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
{
|
{
|
||||||
assert!(lua.gc_is_running());
|
assert!(lua.gc_is_running());
|
||||||
lua.gc_stop();
|
lua.gc_stop();
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[target.x86_64-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_runner"
|
||||||
|
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,82 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use mlua::{Lua, Result};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_module() -> Result<()> {
|
||||||
|
let lua = make_lua()?;
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
local mod = require("rust_module")
|
||||||
|
assert(mod.sum(2,2) == 4)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.exec()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "lua54",
|
||||||
|
feature = "lua53",
|
||||||
|
feature = "lua52",
|
||||||
|
feature = "lua51"
|
||||||
|
))]
|
||||||
|
#[test]
|
||||||
|
fn test_module_from_thread() -> Result<()> {
|
||||||
|
let lua = make_lua()?;
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
local mod
|
||||||
|
|
||||||
|
local co = coroutine.create(function(a, b)
|
||||||
|
mod = require("rust_module")
|
||||||
|
assert(mod.sum(a, b) == a + b)
|
||||||
|
end)
|
||||||
|
|
||||||
|
coroutine.resume(co, 3, 5)
|
||||||
|
collectgarbage()
|
||||||
|
|
||||||
|
assert(mod.used_memory() > 0)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.exec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_lua() -> Result<Lua> {
|
||||||
|
let (dylib_path, dylib_ext, separator);
|
||||||
|
if cfg!(target_os = "macos") {
|
||||||
|
dylib_path = env::var("DYLD_FALLBACK_LIBRARY_PATH").unwrap();
|
||||||
|
dylib_ext = "dylib";
|
||||||
|
separator = ":";
|
||||||
|
} else if cfg!(target_os = "linux") {
|
||||||
|
dylib_path = env::var("LD_LIBRARY_PATH").unwrap();
|
||||||
|
dylib_ext = "so";
|
||||||
|
separator = ":";
|
||||||
|
} else if cfg!(target_os = "windows") {
|
||||||
|
dylib_path = env::var("PATH").unwrap();
|
||||||
|
dylib_ext = "dll";
|
||||||
|
separator = ";";
|
||||||
|
} else {
|
||||||
|
panic!("unknown target os");
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut cpath = dylib_path
|
||||||
|
.split(separator)
|
||||||
|
.take(3)
|
||||||
|
.map(|p| {
|
||||||
|
let mut path = PathBuf::from(p);
|
||||||
|
path.push(format!("lib?.{}", dylib_ext));
|
||||||
|
path.to_str().unwrap().to_owned()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(";");
|
||||||
|
|
||||||
|
if cfg!(target_os = "windows") {
|
||||||
|
cpath = cpath.replace("\\", "\\\\");
|
||||||
|
cpath = cpath.replace("lib?.", "?.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let lua = unsafe { Lua::unsafe_new() }; // To be able to load C modules
|
||||||
|
lua.load(&format!("package.cpath = \"{}\"", cpath)).exec()?;
|
||||||
|
Ok(lua)
|
||||||
|
}
|
||||||
+14
-5
@@ -1,3 +1,15 @@
|
|||||||
|
#![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",
|
||||||
|
allow(unused_attributes)
|
||||||
|
)]
|
||||||
|
extern "system" {}
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@@ -44,10 +56,8 @@ fn scope_drop() -> Result<()> {
|
|||||||
let rc = Rc::new(());
|
let rc = Rc::new(());
|
||||||
|
|
||||||
lua.scope(|scope| {
|
lua.scope(|scope| {
|
||||||
lua.globals().set(
|
lua.globals()
|
||||||
"test",
|
.set("test", scope.create_userdata(MyUserdata(rc.clone()))?)?;
|
||||||
scope.create_static_userdata(MyUserdata(rc.clone()))?,
|
|
||||||
)?;
|
|
||||||
assert_eq!(Rc::strong_count(&rc), 2);
|
assert_eq!(Rc::strong_count(&rc), 2);
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
@@ -198,7 +208,6 @@ fn scope_userdata_mismatch() -> Result<()> {
|
|||||||
a.inc(a)
|
a.inc(a)
|
||||||
b.inc(b)
|
b.inc(b)
|
||||||
end
|
end
|
||||||
|
|
||||||
function bad(a, b)
|
function bad(a, b)
|
||||||
a.inc(b)
|
a.inc(b)
|
||||||
end
|
end
|
||||||
|
|||||||
+341
@@ -0,0 +1,341 @@
|
|||||||
|
#![cfg(feature = "serialize")]
|
||||||
|
#![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",
|
||||||
|
allow(unused_attributes)
|
||||||
|
)]
|
||||||
|
extern "system" {}
|
||||||
|
|
||||||
|
use mlua::{Error, Lua, LuaSerdeExt, Result as LuaResult, UserData, Value};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialize() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct MyUserData(i64, String);
|
||||||
|
|
||||||
|
impl UserData for MyUserData {};
|
||||||
|
|
||||||
|
let lua = Lua::new();
|
||||||
|
let globals = lua.globals();
|
||||||
|
|
||||||
|
let ud = lua.create_ser_userdata(MyUserData(123, "test userdata".into()))?;
|
||||||
|
globals.set("ud", ud)?;
|
||||||
|
globals.set("null", lua.null()?)?;
|
||||||
|
|
||||||
|
let empty_array = lua.create_table()?;
|
||||||
|
empty_array.set_metatable(Some(lua.array_metatable()?));
|
||||||
|
globals.set("empty_array", empty_array)?;
|
||||||
|
|
||||||
|
let val = lua
|
||||||
|
.load(
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
_bool = true,
|
||||||
|
_integer = 123,
|
||||||
|
_number = 321.99,
|
||||||
|
_string = "test string serialization",
|
||||||
|
_table_arr = {nil, "value 1", nil, "value 2", {}},
|
||||||
|
_table_map = {["table"] = "map", ["null"] = null},
|
||||||
|
_bytes = "\240\040\140\040",
|
||||||
|
_userdata = ud,
|
||||||
|
_null = null,
|
||||||
|
_empty_map = {},
|
||||||
|
_empty_array = empty_array,
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.eval::<Value>()?;
|
||||||
|
|
||||||
|
let json = serde_json::json!({
|
||||||
|
"_bool": true,
|
||||||
|
"_integer": 123,
|
||||||
|
"_number": 321.99,
|
||||||
|
"_string": "test string serialization",
|
||||||
|
"_table_arr": [null, "value 1", null, "value 2", {}],
|
||||||
|
"_table_map": {"table": "map", "null": null},
|
||||||
|
"_bytes": [240, 40, 140, 40],
|
||||||
|
"_userdata": [123, "test userdata"],
|
||||||
|
"_null": null,
|
||||||
|
"_empty_map": {},
|
||||||
|
"_empty_array": [],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(serde_json::to_value(&val)?, json);
|
||||||
|
|
||||||
|
// Test to-from loop
|
||||||
|
let val = lua.to_value(&json)?;
|
||||||
|
let expected_json = lua.from_value::<serde_json::Value>(val)?;
|
||||||
|
assert_eq!(expected_json, json);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialize_in_scope() -> LuaResult<()> {
|
||||||
|
#[derive(Serialize, Clone)]
|
||||||
|
struct MyUserData(i64, String);
|
||||||
|
|
||||||
|
impl UserData for MyUserData {};
|
||||||
|
|
||||||
|
let lua = Lua::new();
|
||||||
|
lua.scope(|scope| {
|
||||||
|
let ud = scope.create_ser_userdata(MyUserData(-5, "test userdata".into()))?;
|
||||||
|
assert_eq!(
|
||||||
|
serde_json::to_value(&ud).unwrap(),
|
||||||
|
serde_json::json!((-5, "test userdata"))
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
lua.scope(|scope| {
|
||||||
|
let ud = scope.create_ser_userdata(MyUserData(-5, "test userdata".into()))?;
|
||||||
|
lua.globals().set("ud", ud)
|
||||||
|
})?;
|
||||||
|
let val = lua.load("ud").eval::<Value>()?;
|
||||||
|
match serde_json::to_value(&val) {
|
||||||
|
Ok(v) => panic!("expected destructed error, got {}", v),
|
||||||
|
Err(e) if e.to_string().contains("destructed") => {}
|
||||||
|
Err(e) => panic!("expected destructed error, got {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialize_failure() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct MyUserData(i64);
|
||||||
|
|
||||||
|
impl UserData for MyUserData {};
|
||||||
|
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
let ud = Value::UserData(lua.create_userdata(MyUserData(123))?);
|
||||||
|
match serde_json::to_value(&ud) {
|
||||||
|
Ok(v) => panic!("expected serialization error, got {}", v),
|
||||||
|
Err(serde_json::Error { .. }) => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let func = lua.create_function(|_, _: ()| Ok(()))?;
|
||||||
|
match serde_json::to_value(&Value::Function(func.clone())) {
|
||||||
|
Ok(v) => panic!("expected serialization error, got {}", v),
|
||||||
|
Err(serde_json::Error { .. }) => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let thr = lua.create_thread(func)?;
|
||||||
|
match serde_json::to_value(&Value::Thread(thr)) {
|
||||||
|
Ok(v) => panic!("expected serialization error, got {}", v),
|
||||||
|
Err(serde_json::Error { .. }) => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_to_value_struct() -> LuaResult<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
let globals = lua.globals();
|
||||||
|
globals.set("null", lua.null()?)?;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Test {
|
||||||
|
name: String,
|
||||||
|
key: i64,
|
||||||
|
data: Option<bool>,
|
||||||
|
};
|
||||||
|
|
||||||
|
let test = Test {
|
||||||
|
name: "alex".to_string(),
|
||||||
|
key: -16,
|
||||||
|
data: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
globals.set("value", lua.to_value(&test)?)?;
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
assert(value["name"] == "alex")
|
||||||
|
assert(value["key"] == -16)
|
||||||
|
assert(value["data"] == null)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.exec()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_to_value_enum() -> LuaResult<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
let globals = lua.globals();
|
||||||
|
globals.set("null", lua.null()?)?;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Test {
|
||||||
|
name: String,
|
||||||
|
key: i64,
|
||||||
|
data: Option<bool>,
|
||||||
|
};
|
||||||
|
|
||||||
|
let test = Test {
|
||||||
|
name: "alex".to_string(),
|
||||||
|
key: -16,
|
||||||
|
data: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
globals.set("value", lua.to_value(&test)?)?;
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
assert(value["name"] == "alex")
|
||||||
|
assert(value["key"] == -16)
|
||||||
|
assert(value["data"] == null)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.exec()?;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
enum E {
|
||||||
|
Unit,
|
||||||
|
Integer(u32),
|
||||||
|
Tuple(u32, u32),
|
||||||
|
Struct { a: u32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
let u = E::Unit;
|
||||||
|
globals.set("value", lua.to_value(&u)?)?;
|
||||||
|
lua.load(r#"assert(value == "Unit")"#).exec()?;
|
||||||
|
|
||||||
|
let n = E::Integer(1);
|
||||||
|
globals.set("value", lua.to_value(&n)?)?;
|
||||||
|
lua.load(r#"assert(value["Integer"] == 1)"#).exec()?;
|
||||||
|
|
||||||
|
let t = E::Tuple(1, 2);
|
||||||
|
globals.set("value", lua.to_value(&t)?)?;
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
assert(value["Tuple"][1] == 1)
|
||||||
|
assert(value["Tuple"][2] == 2)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.exec()?;
|
||||||
|
|
||||||
|
let s = E::Struct { a: 1 };
|
||||||
|
globals.set("value", lua.to_value(&s)?)?;
|
||||||
|
lua.load(r#"assert(value["Struct"]["a"] == 1)"#).exec()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_value_struct() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
#[derive(Deserialize, PartialEq, Debug)]
|
||||||
|
struct Test {
|
||||||
|
int: u32,
|
||||||
|
seq: Vec<String>,
|
||||||
|
map: std::collections::HashMap<i32, i32>,
|
||||||
|
empty: Vec<()>,
|
||||||
|
tuple: (u8, u8, u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = lua
|
||||||
|
.load(
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
int = 1,
|
||||||
|
seq = {"a", "b"},
|
||||||
|
map = {2, [4] = 1},
|
||||||
|
empty = {},
|
||||||
|
tuple = {10, 20, 30},
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.eval::<Value>()?;
|
||||||
|
let got = lua.from_value(value)?;
|
||||||
|
assert_eq!(
|
||||||
|
Test {
|
||||||
|
int: 1,
|
||||||
|
seq: vec!["a".into(), "b".into()],
|
||||||
|
map: vec![(1, 2), (4, 1)].into_iter().collect(),
|
||||||
|
empty: vec![],
|
||||||
|
tuple: (10, 20, 30),
|
||||||
|
},
|
||||||
|
got
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_value_enum() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
#[derive(Deserialize, PartialEq, Debug)]
|
||||||
|
enum E {
|
||||||
|
Unit,
|
||||||
|
Integer(u32),
|
||||||
|
Tuple(u32, u32),
|
||||||
|
Struct { a: u32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = lua.load(r#""Unit""#).eval()?;
|
||||||
|
let got = lua.from_value(value)?;
|
||||||
|
assert_eq!(E::Unit, got);
|
||||||
|
|
||||||
|
let value = lua.load(r#"{Integer = 1}"#).eval()?;
|
||||||
|
let got = lua.from_value(value)?;
|
||||||
|
assert_eq!(E::Integer(1), got);
|
||||||
|
|
||||||
|
let value = lua.load(r#"{Tuple = {1, 2}}"#).eval()?;
|
||||||
|
let got = lua.from_value(value)?;
|
||||||
|
assert_eq!(E::Tuple(1, 2), got);
|
||||||
|
|
||||||
|
let value = lua.load(r#"{Struct = {a = 3}}"#).eval()?;
|
||||||
|
let got = lua.from_value(value)?;
|
||||||
|
assert_eq!(E::Struct { a: 3 }, got);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_value_enum_untagged() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
lua.globals().set("null", lua.null()?)?;
|
||||||
|
|
||||||
|
#[derive(Deserialize, PartialEq, Debug)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum Eut {
|
||||||
|
Unit,
|
||||||
|
Integer(u64),
|
||||||
|
Tuple(u32, u32),
|
||||||
|
Struct { a: u32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = lua.load(r#"null"#).eval()?;
|
||||||
|
let got = lua.from_value(value)?;
|
||||||
|
assert_eq!(Eut::Unit, got);
|
||||||
|
|
||||||
|
let value = lua.load(r#"1"#).eval()?;
|
||||||
|
let got = lua.from_value(value)?;
|
||||||
|
assert_eq!(Eut::Integer(1), got);
|
||||||
|
|
||||||
|
let value = lua.load(r#"{3, 1}"#).eval()?;
|
||||||
|
let got = lua.from_value(value)?;
|
||||||
|
assert_eq!(Eut::Tuple(3, 1), got);
|
||||||
|
|
||||||
|
let value = lua.load(r#"{a = 10}"#).eval()?;
|
||||||
|
let got = lua.from_value(value)?;
|
||||||
|
assert_eq!(Eut::Struct { a: 10 }, got);
|
||||||
|
|
||||||
|
let value = lua.load(r#"{b = 12}"#).eval()?;
|
||||||
|
match lua.from_value::<Eut>(value) {
|
||||||
|
Ok(v) => panic!("expected Error::DeserializeError, got {:?}", v),
|
||||||
|
Err(Error::DeserializeError(_)) => {}
|
||||||
|
Err(e) => panic!("expected Error::DeserializeError, got {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,3 +1,15 @@
|
|||||||
|
#![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",
|
||||||
|
allow(unused_attributes)
|
||||||
|
)]
|
||||||
|
extern "system" {}
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use mlua::{Lua, Result, String};
|
use mlua::{Lua, Result, String};
|
||||||
|
|||||||
+84
-1
@@ -1,4 +1,16 @@
|
|||||||
use mlua::{Lua, Nil, Result, Table, Value};
|
#![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",
|
||||||
|
allow(unused_attributes)
|
||||||
|
)]
|
||||||
|
extern "system" {}
|
||||||
|
|
||||||
|
use mlua::{Lua, Nil, Result, Table, TableExt, Value};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_set_get() -> Result<()> {
|
fn test_set_get() -> Result<()> {
|
||||||
@@ -109,6 +121,47 @@ fn test_table() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_table_sequence_from() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
let get_table = lua.create_function(|_, t: Table| Ok(t))?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_table
|
||||||
|
.call::<_, Table>(vec![1, 2, 3])?
|
||||||
|
.sequence_values()
|
||||||
|
.collect::<Result<Vec<i64>>>()?,
|
||||||
|
vec![1, 2, 3]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_table
|
||||||
|
.call::<_, Table>([1, 2, 3].as_ref())?
|
||||||
|
.sequence_values()
|
||||||
|
.collect::<Result<Vec<i64>>>()?,
|
||||||
|
vec![1, 2, 3]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_table
|
||||||
|
.call::<_, Table>([1, 2, 3])?
|
||||||
|
.sequence_values()
|
||||||
|
.collect::<Result<Vec<i64>>>()?,
|
||||||
|
vec![1, 2, 3]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_table
|
||||||
|
.call::<_, Table>(&[1, 2, 3])?
|
||||||
|
.sequence_values()
|
||||||
|
.collect::<Result<Vec<i64>>>()?,
|
||||||
|
vec![1, 2, 3]
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_table_scope() -> Result<()> {
|
fn test_table_scope() -> Result<()> {
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
@@ -226,3 +279,33 @@ fn test_table_error() -> Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_table_call() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
table = {a = 1}
|
||||||
|
|
||||||
|
function table.func(key)
|
||||||
|
return "func_"..key
|
||||||
|
end
|
||||||
|
|
||||||
|
function table:method(key)
|
||||||
|
return "method_"..self[key]
|
||||||
|
end
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.exec()?;
|
||||||
|
|
||||||
|
let table: Table = lua.globals().get("table")?;
|
||||||
|
|
||||||
|
assert_eq!(table.call_function::<_, _, String>("func", "a")?, "func_a");
|
||||||
|
assert_eq!(
|
||||||
|
table.call_method::<_, _, String>("method", "a")?,
|
||||||
|
"method_1"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
+142
-5
@@ -1,12 +1,95 @@
|
|||||||
|
#![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",
|
||||||
|
allow(unused_attributes)
|
||||||
|
)]
|
||||||
|
extern "system" {}
|
||||||
|
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::panic::catch_unwind;
|
use std::panic::catch_unwind;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{error, f32, f64, fmt};
|
use std::{error, f32, f64, fmt};
|
||||||
|
|
||||||
use mlua::{
|
use mlua::{
|
||||||
Error, ExternalError, Function, Lua, Nil, Result, String, Table, UserData, Value, Variadic,
|
ChunkMode, Error, ExternalError, Function, Lua, Nil, Result, StdLib, String, Table, UserData,
|
||||||
|
Value, Variadic,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_safety() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
assert!(lua.load(r#"require "debug""#).exec().is_err());
|
||||||
|
match lua.load_from_std_lib(StdLib::DEBUG) {
|
||||||
|
Err(Error::SafetyError(_)) => {}
|
||||||
|
Err(e) => panic!("expected SafetyError, got {:?}", e),
|
||||||
|
Ok(_) => panic!("expected SafetyError, got no error"),
|
||||||
|
}
|
||||||
|
drop(lua);
|
||||||
|
|
||||||
|
let lua = unsafe { Lua::unsafe_new() };
|
||||||
|
assert!(lua.load(r#"require "debug""#).exec().is_ok());
|
||||||
|
drop(lua);
|
||||||
|
|
||||||
|
match Lua::new_with(StdLib::DEBUG) {
|
||||||
|
Err(Error::SafetyError(_)) => {}
|
||||||
|
Err(e) => panic!("expected SafetyError, got {:?}", e),
|
||||||
|
Ok(_) => panic!("expected SafetyError, got new Lua state"),
|
||||||
|
}
|
||||||
|
|
||||||
|
let lua = Lua::new();
|
||||||
|
match lua.load(r#"package.loadlib()"#).exec() {
|
||||||
|
Err(Error::CallbackError { ref cause, .. }) => match cause.as_ref() {
|
||||||
|
Error::SafetyError(_) => {}
|
||||||
|
e => panic!("expected SafetyError cause, got {:?}", e),
|
||||||
|
},
|
||||||
|
Err(e) => panic!("expected CallbackError, got {:?}", e),
|
||||||
|
Ok(_) => panic!("expected CallbackError, got no error"),
|
||||||
|
};
|
||||||
|
match lua.load(r#"require "fake_ffi""#).exec() {
|
||||||
|
Err(Error::RuntimeError(msg)) => assert!(msg.contains("can't load C modules in safe mode")),
|
||||||
|
Err(e) => panic!("expected RuntimeError, got {:?}", e),
|
||||||
|
Ok(_) => panic!("expected RuntimeError, got no error"),
|
||||||
|
}
|
||||||
|
|
||||||
|
match lua.load("1 + 1").set_mode(ChunkMode::Binary).exec() {
|
||||||
|
Err(Error::SafetyError(msg)) => {
|
||||||
|
assert!(msg.contains("binary chunks are disabled in safe mode"))
|
||||||
|
}
|
||||||
|
Err(e) => panic!("expected SafetyError, got {:?}", e),
|
||||||
|
Ok(_) => panic!("expected SafetyError, got no error"),
|
||||||
|
}
|
||||||
|
|
||||||
|
let bytecode = lua.load("return 1 + 1").into_function()?.dump(true)?;
|
||||||
|
match lua.load(&bytecode).exec() {
|
||||||
|
Err(Error::SafetyError(msg)) => {
|
||||||
|
assert!(msg.contains("binary chunks are disabled in safe mode"))
|
||||||
|
}
|
||||||
|
Err(e) => panic!("expected SafetyError, got {:?}", e),
|
||||||
|
Ok(_) => panic!("expected SafetyError, got no error"),
|
||||||
|
}
|
||||||
|
drop(lua);
|
||||||
|
|
||||||
|
// Test safety rules after dynamically loading `package` library
|
||||||
|
let lua = Lua::new_with(StdLib::NONE)?;
|
||||||
|
assert!(lua.globals().get::<_, Option<Value>>("require")?.is_none());
|
||||||
|
lua.load_from_std_lib(StdLib::PACKAGE)?;
|
||||||
|
match lua.load(r#"package.loadlib()"#).exec() {
|
||||||
|
Err(Error::CallbackError { ref cause, .. }) => match cause.as_ref() {
|
||||||
|
Error::SafetyError(_) => {}
|
||||||
|
e => panic!("expected SafetyError cause, got {:?}", e),
|
||||||
|
},
|
||||||
|
Err(e) => panic!("expected CallbackError, got {:?}", e),
|
||||||
|
Ok(_) => panic!("expected CallbackError, got no error"),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_load() -> Result<()> {
|
fn test_load() -> Result<()> {
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
@@ -75,6 +158,41 @@ fn test_eval() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_mode() -> Result<()> {
|
||||||
|
let lua = unsafe { Lua::unsafe_new() };
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
lua.load("1 + 1").set_mode(ChunkMode::Text).eval::<i32>()?,
|
||||||
|
2
|
||||||
|
);
|
||||||
|
match lua.load("1 + 1").set_mode(ChunkMode::Binary).exec() {
|
||||||
|
Ok(_) => panic!("expected SyntaxError, got no error"),
|
||||||
|
Err(Error::SyntaxError { message: msg, .. }) => {
|
||||||
|
assert!(msg.contains("attempt to load a text chunk"))
|
||||||
|
}
|
||||||
|
Err(e) => panic!("expected SyntaxError, got {:?}", e),
|
||||||
|
};
|
||||||
|
|
||||||
|
let bytecode = lua.load("return 1 + 1").into_function()?.dump(true)?;
|
||||||
|
assert_eq!(lua.load(&bytecode).eval::<i32>()?, 2);
|
||||||
|
assert_eq!(
|
||||||
|
lua.load(&bytecode)
|
||||||
|
.set_mode(ChunkMode::Binary)
|
||||||
|
.eval::<i32>()?,
|
||||||
|
2
|
||||||
|
);
|
||||||
|
match lua.load(&bytecode).set_mode(ChunkMode::Text).exec() {
|
||||||
|
Ok(_) => panic!("expected SyntaxError, got no error"),
|
||||||
|
Err(Error::SyntaxError { message: msg, .. }) => {
|
||||||
|
assert!(msg.contains("attempt to load a binary chunk"))
|
||||||
|
}
|
||||||
|
Err(e) => panic!("expected SyntaxError, got {:?}", e),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lua_multi() -> Result<()> {
|
fn test_lua_multi() -> Result<()> {
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
@@ -389,7 +507,7 @@ fn test_num_conversion() -> Result<()> {
|
|||||||
|
|
||||||
assert_eq!(lua.load("1.0").eval::<i64>()?, 1);
|
assert_eq!(lua.load("1.0").eval::<i64>()?, 1);
|
||||||
assert_eq!(lua.load("1.0").eval::<f64>()?, 1.0);
|
assert_eq!(lua.load("1.0").eval::<f64>()?, 1.0);
|
||||||
#[cfg(feature = "lua53")]
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||||
assert_eq!(lua.load("1.0").eval::<String>()?, "1.0");
|
assert_eq!(lua.load("1.0").eval::<String>()?, "1.0");
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
assert_eq!(lua.load("1.0").eval::<String>()?, "1");
|
assert_eq!(lua.load("1.0").eval::<String>()?, "1");
|
||||||
@@ -405,7 +523,9 @@ fn test_num_conversion() -> Result<()> {
|
|||||||
assert!(lua.load("math.huge").eval::<i64>().is_err());
|
assert!(lua.load("math.huge").eval::<i64>().is_err());
|
||||||
|
|
||||||
assert_eq!(lua.unpack::<f64>(lua.pack(f32::MAX)?)?, f32::MAX as f64);
|
assert_eq!(lua.unpack::<f64>(lua.pack(f32::MAX)?)?, f32::MAX as f64);
|
||||||
assert!(lua.unpack::<f32>(lua.pack(f64::MAX)?).is_err());
|
assert_eq!(lua.unpack::<f64>(lua.pack(f32::MIN)?)?, f32::MIN as f64);
|
||||||
|
assert_eq!(lua.unpack::<f32>(lua.pack(f64::MAX)?)?, f32::INFINITY);
|
||||||
|
assert_eq!(lua.unpack::<f32>(lua.pack(f64::MIN)?)?, f32::NEG_INFINITY);
|
||||||
|
|
||||||
assert_eq!(lua.unpack::<i128>(lua.pack(1i128 << 64)?)?, 1i128 << 64);
|
assert_eq!(lua.unpack::<i128>(lua.pack(1i128 << 64)?)?, 1i128 << 64);
|
||||||
|
|
||||||
@@ -466,7 +586,12 @@ fn test_pcall_xpcall() -> Result<()> {
|
|||||||
assert_eq!(globals.get::<_, String>("pcall_error")?, "testerror");
|
assert_eq!(globals.get::<_, String>("pcall_error")?, "testerror");
|
||||||
|
|
||||||
assert_eq!(globals.get::<_, bool>("xpcall_statusr")?, false);
|
assert_eq!(globals.get::<_, bool>("xpcall_statusr")?, false);
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52", feature = "luajit"))]
|
#[cfg(any(
|
||||||
|
feature = "lua54",
|
||||||
|
feature = "lua53",
|
||||||
|
feature = "lua52",
|
||||||
|
feature = "luajit"
|
||||||
|
))]
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
globals.get::<_, std::string::String>("xpcall_error")?,
|
globals.get::<_, std::string::String>("xpcall_error")?,
|
||||||
"testerror"
|
"testerror"
|
||||||
@@ -799,7 +924,7 @@ fn context_thread() -> Result<()> {
|
|||||||
)
|
)
|
||||||
.into_function()?;
|
.into_function()?;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
f.call::<_, ()>(lua.current_thread())?;
|
f.call::<_, ()>(lua.current_thread())?;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
@@ -828,3 +953,15 @@ fn context_thread_51() -> Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "luajit")]
|
||||||
|
fn test_jit_version() -> Result<()> {
|
||||||
|
let lua = Lua::new();
|
||||||
|
let jit: Table = lua.globals().get("jit")?;
|
||||||
|
assert!(jit
|
||||||
|
.get::<_, String>("version")?
|
||||||
|
.to_str()?
|
||||||
|
.contains("LuaJIT"));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
+18
-1
@@ -1,3 +1,15 @@
|
|||||||
|
#![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",
|
||||||
|
allow(unused_attributes)
|
||||||
|
)]
|
||||||
|
extern "system" {}
|
||||||
|
|
||||||
use std::panic::catch_unwind;
|
use std::panic::catch_unwind;
|
||||||
|
|
||||||
use mlua::{Error, Function, Lua, Result, Thread, ThreadStatus};
|
use mlua::{Error, Function, Lua, Result, Thread, ThreadStatus};
|
||||||
@@ -100,7 +112,12 @@ fn coroutine_from_closure() -> Result<()> {
|
|||||||
let thrd_main = lua.create_function(|_, ()| Ok(()))?;
|
let thrd_main = lua.create_function(|_, ()| Ok(()))?;
|
||||||
lua.globals().set("main", thrd_main)?;
|
lua.globals().set("main", thrd_main)?;
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52", feature = "luajit"))]
|
#[cfg(any(
|
||||||
|
feature = "lua54",
|
||||||
|
feature = "lua53",
|
||||||
|
feature = "lua52",
|
||||||
|
feature = "luajit"
|
||||||
|
))]
|
||||||
let thrd: Thread = lua.load("coroutine.create(main)").eval()?;
|
let thrd: Thread = lua.load("coroutine.create(main)").eval()?;
|
||||||
#[cfg(feature = "lua51")]
|
#[cfg(feature = "lua51")]
|
||||||
let thrd: Thread = lua
|
let thrd: Thread = lua
|
||||||
|
|||||||
@@ -1,3 +1,15 @@
|
|||||||
|
#![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",
|
||||||
|
allow(unused_attributes)
|
||||||
|
)]
|
||||||
|
extern "system" {}
|
||||||
|
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
|
||||||
use mlua::{Function, LightUserData, Lua, Result};
|
use mlua::{Function, LightUserData, Lua, Result};
|
||||||
|
|||||||
+71
-3
@@ -1,5 +1,20 @@
|
|||||||
|
#![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",
|
||||||
|
allow(unused_attributes)
|
||||||
|
)]
|
||||||
|
extern "system" {}
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
use std::sync::atomic::{AtomicI64, Ordering};
|
||||||
|
|
||||||
use mlua::{
|
use mlua::{
|
||||||
AnyUserData, ExternalError, Function, Lua, MetaMethod, Result, String, UserData,
|
AnyUserData, ExternalError, Function, Lua, MetaMethod, Result, String, UserData,
|
||||||
UserDataMethods, Value,
|
UserDataMethods, Value,
|
||||||
@@ -95,7 +110,7 @@ fn test_metamethods() -> Result<()> {
|
|||||||
Err("no such custom index".to_lua_err())
|
Err("no such custom index".to_lua_err())
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
methods.add_meta_method(MetaMethod::Pairs, |lua, data, ()| {
|
methods.add_meta_method(MetaMethod::Pairs, |lua, data, ()| {
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
let stateless_iter = lua.create_function(|_, (data, i): (MyUserData, i64)| {
|
let stateless_iter = lua.create_function(|_, (data, i): (MyUserData, i64)| {
|
||||||
@@ -120,7 +135,7 @@ fn test_metamethods() -> Result<()> {
|
|||||||
10
|
10
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
let pairs_it = {
|
let pairs_it = {
|
||||||
lua.load(
|
lua.load(
|
||||||
r#"
|
r#"
|
||||||
@@ -140,7 +155,7 @@ fn test_metamethods() -> Result<()> {
|
|||||||
assert_eq!(lua.load("userdata1 - userdata2").eval::<MyUserData>()?.0, 4);
|
assert_eq!(lua.load("userdata1 - userdata2").eval::<MyUserData>()?.0, 4);
|
||||||
assert_eq!(lua.load("userdata1:get()").eval::<i64>()?, 7);
|
assert_eq!(lua.load("userdata1:get()").eval::<i64>()?, 7);
|
||||||
assert_eq!(lua.load("userdata2.inner").eval::<i64>()?, 3);
|
assert_eq!(lua.load("userdata2.inner").eval::<i64>()?, 3);
|
||||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
assert_eq!(pairs_it.call::<_, i64>(())?, 28);
|
assert_eq!(pairs_it.call::<_, i64>(())?, 28);
|
||||||
assert!(lua.load("userdata2.nonexist_field").eval::<()>().is_err());
|
assert!(lua.load("userdata2.nonexist_field").eval::<()>().is_err());
|
||||||
|
|
||||||
@@ -151,6 +166,58 @@ fn test_metamethods() -> Result<()> {
|
|||||||
assert!(userdata2 != userdata3); // because references are differ
|
assert!(userdata2 != userdata3); // because references are differ
|
||||||
assert!(userdata2.equals(userdata3)?);
|
assert!(userdata2.equals(userdata3)?);
|
||||||
|
|
||||||
|
let userdata1: AnyUserData = globals.get("userdata1")?;
|
||||||
|
assert!(userdata1.has_metamethod(MetaMethod::Add)?);
|
||||||
|
assert!(userdata1.has_metamethod(MetaMethod::Sub)?);
|
||||||
|
assert!(userdata1.has_metamethod(MetaMethod::Index)?);
|
||||||
|
assert!(!userdata1.has_metamethod(MetaMethod::Pow)?);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
fn test_metamethod_close() -> Result<()> {
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct MyUserData(Arc<AtomicI64>);
|
||||||
|
|
||||||
|
impl UserData for MyUserData {
|
||||||
|
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
methods.add_method("get", |_, data, ()| Ok(data.0.load(Ordering::Relaxed)));
|
||||||
|
methods.add_meta_method(MetaMethod::Close, |_, data, _err: Value| {
|
||||||
|
data.0.store(0, Ordering::Relaxed);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let lua = Lua::new();
|
||||||
|
let globals = lua.globals();
|
||||||
|
|
||||||
|
let ud = MyUserData(Arc::new(AtomicI64::new(-1)));
|
||||||
|
let ud2 = ud.clone();
|
||||||
|
|
||||||
|
globals.set(
|
||||||
|
"new_userdata",
|
||||||
|
lua.create_function(move |_lua, val: i64| {
|
||||||
|
let ud = ud2.clone();
|
||||||
|
ud.0.store(val, Ordering::Relaxed);
|
||||||
|
Ok(ud)
|
||||||
|
})?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
lua.load(
|
||||||
|
r#"
|
||||||
|
do
|
||||||
|
local ud <close> = new_userdata(7)
|
||||||
|
assert(ud:get() == 7)
|
||||||
|
end
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.exec()?;
|
||||||
|
|
||||||
|
assert_eq!(ud.0.load(Ordering::Relaxed), 0);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,6 +286,7 @@ fn detroys_userdata() -> Result<()> {
|
|||||||
#[test]
|
#[test]
|
||||||
fn user_value() -> Result<()> {
|
fn user_value() -> Result<()> {
|
||||||
struct MyUserData;
|
struct MyUserData;
|
||||||
|
|
||||||
impl UserData for MyUserData {}
|
impl UserData for MyUserData {}
|
||||||
|
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
|
|||||||
@@ -1,3 +1,15 @@
|
|||||||
|
#![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",
|
||||||
|
allow(unused_attributes)
|
||||||
|
)]
|
||||||
|
extern "system" {}
|
||||||
|
|
||||||
use mlua::{Lua, Result, Value};
|
use mlua::{Lua, Result, Value};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user