Compare commits
152 commits
Author | SHA1 | Date | |
---|---|---|---|
|
aede7c726c | ||
|
6807dfa22e | ||
|
f27c49f931 | ||
|
693a808b6e | ||
|
a6ca65aa74 | ||
|
a7278cab78 | ||
|
e1bbd00a33 | ||
|
e98998d6ac | ||
|
cca177df5b | ||
|
65396a910f | ||
|
de69d10d73 | ||
|
959e61b97c | ||
|
1040c0a347 | ||
|
9045419586 | ||
|
fcd162f3eb | ||
|
0354703dbf | ||
|
9831d0e397 | ||
|
7f14d93c2b | ||
|
29c6c9cb58 | ||
|
e01af22bac | ||
|
cfa959e599 | ||
|
e523fb2c86 | ||
|
81a9998559 | ||
|
050ac4f5ad | ||
|
967cbb53b0 | ||
|
44a8d86d8a | ||
|
33278d4a64 | ||
|
20a16839aa | ||
|
83ed442bf9 | ||
|
bf6708ba58 | ||
|
0cd724f63b | ||
|
5330b900fd | ||
|
ee32dc33f3 | ||
|
ab029b087d | ||
|
185fee956d | ||
|
4fc69be5f6 | ||
|
3ec076693a | ||
|
95adf8df8e | ||
|
4a25eab257 | ||
|
40fe937878 | ||
|
a6b178328d | ||
|
f3f173fcb6 | ||
|
d3b48cf2f3 | ||
|
f9ff6116db | ||
|
f75af6d75f | ||
|
059e41bafb | ||
|
f7ee6dc635 | ||
|
0919ff21c9 | ||
|
553251761f | ||
|
b46b476f80 | ||
|
70e16b51ae | ||
|
9596b97faa | ||
|
8cbb3d8fae | ||
|
e7f494530f | ||
|
3746c3614f | ||
|
9af1aaf889 | ||
|
c20eb20a59 | ||
|
04ba93137c | ||
|
113f91ace3 | ||
|
ff0d923aae | ||
|
d9ac7abff2 | ||
|
48aa97351d | ||
|
4516ca0bb5 | ||
|
9005f32a98 | ||
|
93d36b9068 | ||
|
f9f32bffce | ||
|
da5010e6de | ||
|
4afca8f5bb | ||
|
b065db37c2 | ||
|
a100ebb3d7 | ||
|
a05a58b258 | ||
|
3766cee4dd | ||
|
99becdb590 | ||
|
799b4e9f0d | ||
|
93f0b2a5de | ||
|
62db3adde1 | ||
|
afa343ff08 | ||
|
4f06f614a9 | ||
|
30ba616a8a | ||
|
0076aa735a | ||
|
bcf2cbea37 | ||
|
8cd594c609 | ||
|
8d71ea79aa | ||
|
2a8c5c7f82 | ||
|
6b2ceb60c4 | ||
|
3aac7131ee | ||
|
1807fa789c | ||
|
7db7526a08 | ||
|
bea9b0f8b5 | ||
|
32a3f478bd | ||
|
294b3b7aae | ||
|
b0dabe9d3c | ||
|
5133a9837a | ||
|
790df77965 | ||
|
a62636fde0 | ||
|
d77c0e3b8d | ||
|
3904213ed0 | ||
|
a5ce0c1409 | ||
|
dba76f3994 | ||
|
86f506a170 | ||
|
d3975bdf30 | ||
|
21affdadfd | ||
|
17473269f8 | ||
|
88e3e92009 | ||
|
1ba7a409d5 | ||
|
ef81f40afa | ||
|
a018d3b6dc | ||
|
0215c31a3a | ||
|
5cd82d0f6b | ||
|
75697e3a3b | ||
|
d1c80be033 | ||
|
a8fef51e86 | ||
|
28a063c1e5 | ||
|
55fac90a74 | ||
|
70d287cf9f | ||
|
d607039a31 | ||
|
0ea65a2985 | ||
|
8c333354d3 | ||
|
f63f147265 | ||
|
595dc3e95f | ||
|
ac28c8d8d2 | ||
|
d5315da8d1 | ||
|
a7cc7f328a | ||
|
516f01ed44 | ||
|
4492a20bbc | ||
|
595bc3a2b3 | ||
|
87c10ca93d | ||
|
f75b7b7879 | ||
|
de1cfa070f | ||
|
ec1fa04085 | ||
|
714dd6249f | ||
|
5089dd73c0 | ||
|
9533f08d3a | ||
|
0a3b65af88 | ||
|
3a9c8c2da2 | ||
|
952dae1de5 | ||
|
c88e5f0c4b | ||
|
55b778c68b | ||
|
c6d3727171 | ||
|
4e0ba6559e | ||
|
405cff5d49 | ||
|
37cddc6b1c | ||
|
2c069f7033 | ||
|
1e61d1dadc | ||
|
32124b31a0 | ||
|
3e5f8e7bb8 | ||
|
cab92f4ea2 | ||
|
fa99f62a99 | ||
|
eed7b1f3af | ||
|
c322e028e2 | ||
|
6dc127f4eb | ||
|
d4f8dce597 |
8
.github/workflows/coverage.yml
vendored
8
.github/workflows/coverage.yml
vendored
|
@ -10,14 +10,14 @@ jobs:
|
|||
options: --security-opt seccomp=unconfined
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Generate code coverage
|
||||
- name: Generate coverage report
|
||||
run: |
|
||||
cargo tarpaulin --verbose --features lua54,vendored,async,send,serialize,macros --out xml --exclude-files benches --exclude-files build --exclude-files mlua_derive --exclude-files src/ffi --exclude-files tests
|
||||
|
||||
- name: Upload to codecov.io
|
||||
uses: codecov/codecov-action@v1
|
||||
- name: Upload report to codecov.io
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{secrets.CODECOV_TOKEN}}
|
||||
fail_ci_if_error: false
|
||||
|
|
289
.github/workflows/main.yml
vendored
289
.github/workflows/main.yml
vendored
|
@ -7,98 +7,94 @@ jobs:
|
|||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, macos-latest, windows-latest]
|
||||
os: [ubuntu-22.04, macos-latest, windows-latest]
|
||||
rust: [stable]
|
||||
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||
lua: [lua54, lua53, lua52, lua51, luajit, luau]
|
||||
include:
|
||||
- os: ubuntu-20.04
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
- os: ubuntu-22.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
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Build ${{ matrix.lua }} vendored
|
||||
run: |
|
||||
cargo build --features "${{ matrix.lua }},vendored"
|
||||
cargo build --features "${{ matrix.lua }},vendored,async,send,serialize,macros"
|
||||
shell: bash
|
||||
- name: Build ${{ matrix.lua }} pkg-config
|
||||
if: ${{ matrix.os == 'ubuntu-20.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
|
||||
cargo build --features "${{ matrix.lua }}"
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: Build ${{ matrix.lua }} vendored
|
||||
run: |
|
||||
cargo build --features "${{ matrix.lua }},vendored"
|
||||
cargo build --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot"
|
||||
shell: bash
|
||||
- name: Build ${{ matrix.lua }} pkg-config
|
||||
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends liblua5.4-dev liblua5.3-dev liblua5.2-dev liblua5.1-0-dev libluajit-5.1-dev
|
||||
cargo build --features "${{ matrix.lua }}"
|
||||
|
||||
build_aarch64_cross_macos:
|
||||
name: Cross-compile to aarch64-apple-darwin
|
||||
runs-on: macos-11.0
|
||||
runs-on: macos-latest
|
||||
needs: build
|
||||
strategy:
|
||||
matrix:
|
||||
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
target: aarch64-apple-darwin
|
||||
override: true
|
||||
- name: Cross-compile
|
||||
run: cargo build --target aarch64-apple-darwin --features "${{ matrix.lua }},vendored,async,send,serialize,macros"
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
target: aarch64-apple-darwin
|
||||
- name: Cross-compile
|
||||
run: cargo build --target aarch64-apple-darwin --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot"
|
||||
|
||||
build_aarch64_cross_ubuntu:
|
||||
name: Cross-compile to aarch64-unknown-linux-gnu
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs: build
|
||||
strategy:
|
||||
matrix:
|
||||
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
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 }},vendored,async,send,serialize,macros"
|
||||
shell: bash
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
target: aarch64-unknown-linux-gnu
|
||||
- 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 }},vendored,async,send,serialize,macros,parking_lot"
|
||||
shell: bash
|
||||
|
||||
build_armv7_cross_ubuntu:
|
||||
name: Cross-compile to armv7-unknown-linux-gnueabihf
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs: build
|
||||
strategy:
|
||||
matrix:
|
||||
lua: [lua54, lua53, lua52, lua51]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
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 }},vendored,async,send,serialize,macros"
|
||||
shell: bash
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
target: armv7-unknown-linux-gnueabihf
|
||||
- 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 }},vendored,async,send,serialize,macros,parking_lot"
|
||||
shell: bash
|
||||
|
||||
test:
|
||||
name: Test
|
||||
|
@ -106,35 +102,34 @@ jobs:
|
|||
needs: build
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, macos-latest, windows-latest]
|
||||
os: [ubuntu-22.04, macos-latest, windows-latest]
|
||||
rust: [stable, nightly]
|
||||
lua: [lua54, lua53, lua52, lua51, luajit, luajit52]
|
||||
lua: [lua54, lua53, lua52, lua51, luajit, luajit52, luau]
|
||||
include:
|
||||
- os: ubuntu-20.04
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
- os: ubuntu-22.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
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Run ${{ matrix.lua }} tests
|
||||
run: |
|
||||
cargo test --features "${{ matrix.lua }},vendored"
|
||||
cargo test --features "${{ matrix.lua }},vendored,async,send,serialize,macros"
|
||||
shell: bash
|
||||
- name: Run compile tests (macos lua54)
|
||||
if: ${{ matrix.os == 'macos-latest' && matrix.lua == 'lua54' }}
|
||||
run: |
|
||||
TRYBUILD=overwrite cargo test --features "${{ matrix.lua }},vendored" -- --ignored
|
||||
TRYBUILD=overwrite cargo test --features "${{ matrix.lua }},vendored,async,send,serialize,macros" -- --ignored
|
||||
shell: bash
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Run ${{ matrix.lua }} tests
|
||||
run: |
|
||||
cargo test --features "${{ matrix.lua }},vendored"
|
||||
cargo test --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot"
|
||||
shell: bash
|
||||
- name: Run compile tests (macos lua54)
|
||||
if: ${{ matrix.os == 'macos-latest' && matrix.lua == 'lua54' }}
|
||||
run: |
|
||||
TRYBUILD=overwrite cargo test --features "${{ matrix.lua }},vendored" -- --ignored
|
||||
TRYBUILD=overwrite cargo test --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot" -- --ignored
|
||||
shell: bash
|
||||
|
||||
test_with_sanitizer:
|
||||
name: Test with address sanitizer
|
||||
|
@ -142,25 +137,24 @@ jobs:
|
|||
needs: build
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04]
|
||||
os: [ubuntu-22.04]
|
||||
rust: [nightly]
|
||||
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||
lua: [lua54, lua53, lua52, lua51, luajit, luau]
|
||||
include:
|
||||
- os: ubuntu-20.04
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: ubuntu-22.04
|
||||
target: x86_64-unknown-linux-gnu
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Run ${{ matrix.lua }} tests with address sanitizer
|
||||
run: |
|
||||
RUSTFLAGS="-Z sanitizer=address" \
|
||||
cargo test --tests --features "${{ matrix.lua }},vendored,async,send,serialize,macros" --target x86_64-unknown-linux-gnu -- --skip test_too_many_recursions
|
||||
shell: bash
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Run ${{ matrix.lua }} tests with address sanitizer
|
||||
run: |
|
||||
RUSTFLAGS="-Z sanitizer=address" \
|
||||
cargo test --tests --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot" --target x86_64-unknown-linux-gnu -- --skip test_too_many_recursions
|
||||
shell: bash
|
||||
|
||||
test_modules:
|
||||
name: Test modules
|
||||
|
@ -168,27 +162,26 @@ jobs:
|
|||
needs: build
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, macos-latest]
|
||||
os: [ubuntu-22.04, macos-latest]
|
||||
rust: [stable]
|
||||
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||
include:
|
||||
- os: ubuntu-20.04
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
- os: ubuntu-22.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
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Run ${{ matrix.lua }} module tests
|
||||
run: |
|
||||
(cd examples/module && cargo build --release --features "${{ matrix.lua }},vendored")
|
||||
(cd tests/module && cargo test --release --features "${{ matrix.lua }},vendored")
|
||||
shell: bash
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Run ${{ matrix.lua }} module tests
|
||||
run: |
|
||||
(cd tests/module && cargo build --release --features "${{ matrix.lua }}")
|
||||
(cd tests/module/loader && cargo test --release --features "${{ matrix.lua }},vendored")
|
||||
shell: bash
|
||||
|
||||
test_modules_windows:
|
||||
name: Test modules on Windows
|
||||
|
@ -201,42 +194,40 @@ jobs:
|
|||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: msys2/setup-msys2@v2
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Rust & Lua
|
||||
run: |
|
||||
pacman -S --noconfirm mingw-w64-x86_64-rust mingw-w64-x86_64-lua mingw-w64-x86_64-luajit mingw-w64-x86_64-pkg-config
|
||||
- name: Run ${{ matrix.lua }} module tests
|
||||
run: |
|
||||
(cd examples/module && cargo build --release --features "${{ matrix.lua }}")
|
||||
(cd tests/module && cargo test --release --features "${{ matrix.lua }}")
|
||||
- uses: msys2/setup-msys2@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Rust & Lua
|
||||
run: |
|
||||
pacman -S --noconfirm mingw-w64-x86_64-rust mingw-w64-x86_64-lua mingw-w64-x86_64-luajit mingw-w64-x86_64-pkg-config
|
||||
- name: Run ${{ matrix.lua }} module tests
|
||||
run: |
|
||||
(cd tests/module && cargo build --release --features "${{ matrix.lua }}")
|
||||
(cd tests/module/loader && cargo test --release --features "${{ matrix.lua }}")
|
||||
|
||||
rustfmt:
|
||||
name: Rustfmt
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
components: rustfmt
|
||||
override: true
|
||||
- run: cargo fmt -- --check
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
components: rustfmt
|
||||
- run: cargo fmt -- --check
|
||||
|
||||
clippy:
|
||||
name: Clippy check
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||
lua: [lua54, lua53, lua52, lua51, luajit, luau]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: nightly
|
||||
components: clippy
|
||||
override: true
|
||||
toolchain: nightly
|
||||
components: clippy
|
||||
- uses: actions-rs/clippy-check@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --features "${{ matrix.lua }},vendored,async,send,serialize,macros"
|
||||
args: --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot"
|
||||
|
|
91
CHANGELOG.md
91
CHANGELOG.md
|
@ -1,3 +1,94 @@
|
|||
## v0.8.6
|
||||
|
||||
- Fixed bug when recycled Registry slot can be set to Nil
|
||||
|
||||
## v0.8.5
|
||||
|
||||
- Fixed potential unsoundness when using `Layout::from_size_align_unchecked` and Rust 1.65+
|
||||
- Performance optimizations around string and table creation in standalone mode
|
||||
- Added fast track path to Table `get`/`set`/`len` methods without metatable
|
||||
- Added new methods `push`/`pop`/`raw_push`/`raw_pop` to Table
|
||||
- Fix getting caller information from `Lua::load`
|
||||
- Better checks and tests when trying to modify a Luau readonly table
|
||||
|
||||
## v0.8.4
|
||||
|
||||
- Minimal Luau updated to 0.548
|
||||
|
||||
## v0.8.3
|
||||
|
||||
- Close to-be-closed variables for Lua 5.4 when using call_async functions (#192)
|
||||
- Fixed Lua assertion when inspecting another thread stack. (#195)
|
||||
- Use more reliable way to create LuaJIT VM (which can fail if use Rust allocator on non-x86 platforms)
|
||||
|
||||
## v0.8.2
|
||||
|
||||
- Performance optimizations in handling UserData
|
||||
- Minimal Luau updated to 0.536
|
||||
- Fixed bug in `Function::bind` when passing empty binds and no arguments (#189)
|
||||
|
||||
## v0.8.1
|
||||
|
||||
- Added `Lua::create_proxy` for accessing to UserData static fields and functions without instance
|
||||
- Added `Table::to_pointer()` and `String::to_pointer()` functions
|
||||
- Bugfixes and improvements (#176 #179)
|
||||
|
||||
## v0.8.0
|
||||
Changes since 0.7.4
|
||||
- Roblox Luau support
|
||||
- Removed C glue
|
||||
- Added async support to `__index` and `__newindex` metamethods
|
||||
- Added `Function::info()` to get information about functions (#149).
|
||||
- Added `parking_lot` dependency under feature flag (for `UserData`)
|
||||
- `Hash` implementation for Lua String
|
||||
- Added `Value::to_pointer()` function
|
||||
- Performance improvements
|
||||
|
||||
Breaking changes:
|
||||
- Refactored `AsChunk` trait (added implementation for `Path` and `PathBuf`).
|
||||
|
||||
## v0.8.0-beta.5
|
||||
|
||||
- Lua sources no longer needed to build modules
|
||||
- Added `__iter` metamethod for Luau
|
||||
- Added `Value::to_pointer()` function
|
||||
- Added `Function::coverage` for Luau to obtain coverage report
|
||||
- Bugfixes and improvements (#153 #161 #168)
|
||||
|
||||
## v0.8.0-beta.4
|
||||
|
||||
- Removed `&Lua` from `Lua::set_interrupt` as it's not safe (introduced in v0.8.0-beta.3)
|
||||
- Enabled `Lua::gc_inc` for Luau
|
||||
- Luau `debug` module marked as safe (enabled by default)
|
||||
- Implemented `Hash` for Lua String
|
||||
- Support mode options in `collectgarbage` for Luau
|
||||
- Added ability to set global Luau compiler (used for loading all chunks).
|
||||
- Refactored `AsChunk` trait (breaking changes).
|
||||
`AsChunk` now implemented for `Path` and `PathBuf` to load lua files from fs.
|
||||
- Added `parking_lot` dependency and feature flag (for `UserData`)
|
||||
- Added `Function::info()` to get information about functions (#149).
|
||||
- Bugfixes and improvements (#104 #142)
|
||||
|
||||
## v0.8.0-beta.3
|
||||
|
||||
- Luau vector constructor
|
||||
- Luau sandboxing support
|
||||
- Luau interrupts (yieldable)
|
||||
- More Luau compiler options (mutable globals)
|
||||
- Other performance improvements
|
||||
|
||||
## v0.8.0-beta.2
|
||||
|
||||
- Luau vector datatype support
|
||||
- Luau readonly table attribute
|
||||
- Other Luau improvements
|
||||
|
||||
## v0.8.0-beta.1
|
||||
|
||||
- Roblox Luau support
|
||||
- Refactored ffi module. C glue is no longer required
|
||||
- Added async support to `__index` and `__newindex` metamethods
|
||||
|
||||
## v0.7.4
|
||||
|
||||
- Improved `Lua::create_registry_value` to reuse previously expired registry keys.
|
||||
|
|
25
Cargo.toml
25
Cargo.toml
|
@ -1,30 +1,28 @@
|
|||
[package]
|
||||
name = "mlua"
|
||||
version = "0.7.4" # remember to update html_root_url and mlua_derive
|
||||
version = "0.8.6" # remember to update html_root_url and mlua_derive
|
||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@chucklefish.org>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/khvzak/mlua"
|
||||
documentation = "https://docs.rs/mlua"
|
||||
readme = "README.md"
|
||||
keywords = ["lua", "luajit", "async", "futures", "scripting"]
|
||||
keywords = ["lua", "luajit", "luau", "async", "scripting"]
|
||||
categories = ["api-bindings", "asynchronous"]
|
||||
license = "MIT"
|
||||
links = "lua"
|
||||
build = "build/main.rs"
|
||||
description = """
|
||||
High level bindings to Lua 5.4/5.3/5.2/5.1 (including LuaJIT)
|
||||
High level bindings to Lua 5.4/5.3/5.2/5.1 (including LuaJIT) and Roblox Luau
|
||||
with async/await features and support of writing native Lua modules in Rust.
|
||||
"""
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["lua54", "vendored", "async", "send", "serialize", "macros"]
|
||||
features = ["lua54", "vendored", "async", "send", "serialize", "macros", "parking_lot"]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"mlua_derive",
|
||||
"examples/module",
|
||||
"tests/module",
|
||||
]
|
||||
|
||||
[features]
|
||||
|
@ -34,6 +32,7 @@ lua52 = []
|
|||
lua51 = []
|
||||
luajit = []
|
||||
luajit52 = ["luajit"]
|
||||
luau = ["luau0-src"]
|
||||
vendored = ["lua-src", "luajit-src"]
|
||||
module = ["mlua_derive"]
|
||||
async = ["futures-core", "futures-task", "futures-util"]
|
||||
|
@ -42,7 +41,7 @@ serialize = ["serde", "erased-serde"]
|
|||
macros = ["mlua_derive/macros"]
|
||||
|
||||
[dependencies]
|
||||
mlua_derive = { version = "=0.6.0", optional = true, path = "mlua_derive" }
|
||||
mlua_derive = { version = "=0.8.0", optional = true, path = "mlua_derive" }
|
||||
bstr = { version = "0.2", features = ["std"], default_features = false }
|
||||
once_cell = { version = "1.0" }
|
||||
num-traits = { version = "0.2.14" }
|
||||
|
@ -52,15 +51,17 @@ futures-task = { version = "0.3.5", optional = true }
|
|||
futures-util = { version = "0.3.5", optional = true }
|
||||
serde = { version = "1.0", optional = true }
|
||||
erased-serde = { version = "0.3", optional = true }
|
||||
parking_lot = { version = "0.12", optional = true }
|
||||
|
||||
[build-dependencies]
|
||||
cc = { version = "1.0" }
|
||||
pkg-config = { version = "0.3.17" }
|
||||
lua-src = { version = ">= 540.0.0, < 550.0.0", optional = true }
|
||||
luajit-src = { version = ">= 210.3.1, < 220.0.0", optional = true }
|
||||
lua-src = { version = ">= 544.0.0, < 550.0.0", optional = true }
|
||||
luajit-src = { version = ">= 210.4.0, < 220.0.0", optional = true }
|
||||
luau0-src = { version = "0.4.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rustyline = "9.0"
|
||||
rustyline = "10.0"
|
||||
criterion = { version = "0.3.4", features = ["html_reports", "async_tokio"] }
|
||||
trybuild = "1.0"
|
||||
futures = "0.3.5"
|
||||
|
@ -68,8 +69,10 @@ hyper = { version = "0.14", features = ["client", "server"] }
|
|||
reqwest = { version = "0.11", features = ["json"] }
|
||||
tokio = { version = "1.0", features = ["full"] }
|
||||
futures-timer = "3.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
maplit = "1.0"
|
||||
tempfile = "3"
|
||||
|
||||
[[bench]]
|
||||
name = "benchmark"
|
||||
|
|
21
FAQ.md
Normal file
21
FAQ.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
# mlua FAQ
|
||||
|
||||
This file is for general questions that don't fit into the README or crate docs.
|
||||
|
||||
## Loading a C module fails with error `undefined symbol: lua_xxx`. How to fix?
|
||||
|
||||
Add the following rustflags to your [.cargo/config](http://doc.crates.io/config.html) in order to properly export Lua symbols:
|
||||
|
||||
```toml
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
rustflags = ["-C", "link-args=-rdynamic"]
|
||||
|
||||
[target.x86_64-apple-darwin]
|
||||
rustflags = ["-C", "link-args=-rdynamic"]
|
||||
```
|
||||
|
||||
## I want to add support for a Lua VM fork to mlua. Do you accept pull requests?
|
||||
|
||||
Adding new feature flag to support a Lua VM fork is a major step that requires huge effort to maintain it.
|
||||
Regular updates, testing, checking compatibility, etc.
|
||||
That's why I don't plan to support new Lua VM forks or other languages in mlua.
|
33
README.md
33
README.md
|
@ -9,18 +9,23 @@
|
|||
[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
|
||||
[MSRV]: https://img.shields.io/badge/rust-1.53+-brightgreen.svg?&logo=rust
|
||||
[MSRV]: https://img.shields.io/badge/rust-1.56+-brightgreen.svg?&logo=rust
|
||||
|
||||
[Guided Tour](examples/guided_tour.rs)
|
||||
[Guided Tour] | [Benchmarks] | [FAQ]
|
||||
|
||||
[Guided Tour]: examples/guided_tour.rs
|
||||
[Benchmarks]: https://github.com/khvzak/script-bench-rs
|
||||
[FAQ]: FAQ.md
|
||||
|
||||
`mlua` is bindings to [Lua](https://www.lua.org) programming language for Rust with a goal to provide
|
||||
_safe_ (as far as it's possible), high level, easy to use, practical and flexible API.
|
||||
|
||||
Started as `rlua` 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.
|
||||
Started as `rlua` fork, `mlua` supports Lua 5.4, 5.3, 5.2, 5.1 (including LuaJIT) and [Roblox Luau] and allows to write native Lua modules in Rust as well as use Lua in a standalone mode.
|
||||
|
||||
`mlua` tested on Windows/macOS/Linux including module mode in [GitHub Actions] on `x86_64` platform and cross-compilation to `aarch64` (other targets are also supported).
|
||||
|
||||
[GitHub Actions]: https://github.com/khvzak/mlua/actions
|
||||
[Roblox Luau]: https://luau-lang.org
|
||||
|
||||
## Usage
|
||||
|
||||
|
@ -35,28 +40,34 @@ Below is a list of the available feature flags. By default `mlua` does not enabl
|
|||
* `lua51`: activate Lua [5.1] support
|
||||
* `luajit`: activate [LuaJIT] support
|
||||
* `luajit52`: activate [LuaJIT] support with partial compatibility with Lua 5.2
|
||||
* `luau`: activate [Luau] support (auto vendored mode)
|
||||
* `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 using [serde] framework
|
||||
* `macros`: enable procedural macros (such as `chunk!`)
|
||||
* `parking_lot`: support UserData types wrapped in [parking_lot]'s primitives (`Arc<Mutex>` and `Arc<RwLock>`)
|
||||
|
||||
[5.4]: https://www.lua.org/manual/5.4/manual.html
|
||||
[5.3]: https://www.lua.org/manual/5.3/manual.html
|
||||
[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/
|
||||
[Luau]: https://github.com/Roblox/luau
|
||||
[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
|
||||
[parking_lot]: https://github.com/Amanieu/parking_lot
|
||||
|
||||
### 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`.
|
||||
`mlua` supports async/await for all Lua versions including Luau.
|
||||
|
||||
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)
|
||||
|
@ -76,7 +87,7 @@ With `serialize` feature flag enabled, `mlua` allows you to serialize/deserializ
|
|||
|
||||
### Compiling
|
||||
|
||||
You have to enable one of the features `lua54`, `lua53`, `lua52`, `lua51` or `luajit(52)`, according to the chosen Lua version.
|
||||
You have to enable one of the features: `lua54`, `lua53`, `lua52`, `lua51`, `luajit(52)` or `luau`, according to the chosen 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.
|
||||
|
@ -99,7 +110,7 @@ Add to `Cargo.toml` :
|
|||
|
||||
``` toml
|
||||
[dependencies]
|
||||
mlua = { version = "0.7", features = ["lua54", "vendored"] }
|
||||
mlua = { version = "0.8", features = ["lua54", "vendored"] }
|
||||
```
|
||||
|
||||
`main.rs`
|
||||
|
@ -134,7 +145,7 @@ Add to `Cargo.toml` :
|
|||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
mlua = { version = "0.7", features = ["lua54", "vendored", "module"] }
|
||||
mlua = { version = "0.8", features = ["lua54", "vendored", "module"] }
|
||||
```
|
||||
|
||||
`lib.rs` :
|
||||
|
@ -249,6 +260,14 @@ If you encounter them, a bug report would be very welcome:
|
|||
|
||||
+ If you detect that, after catching a panic or during a Drop triggered from a panic, a `Lua` or handle method is triggering other bugs or there is a Lua stack space leak, this is a bug. `mlua` instances are supposed to remain fully usable in the face of user generated panics. This guarantee does not extend to panics marked with "mlua internal error" simply because that is already indicative of a separate bug.
|
||||
|
||||
## Sandboxing
|
||||
|
||||
Please check the [Luau Sandboxing] page if you are interested in running untrusted Lua scripts in controlled environment.
|
||||
|
||||
`mlua` provides `Lua::sandbox` method for enabling sandbox mode (Luau only).
|
||||
|
||||
[Luau Sandboxing]: https://luau-lang.org/sandbox
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the [MIT license](LICENSE)
|
||||
|
|
|
@ -209,6 +209,33 @@ fn create_userdata(c: &mut Criterion) {
|
|||
});
|
||||
}
|
||||
|
||||
fn call_userdata_index(c: &mut Criterion) {
|
||||
struct UserData(i64);
|
||||
impl LuaUserData for UserData {
|
||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_meta_method(LuaMetaMethod::Index, move |_, _, index: String| Ok(index));
|
||||
}
|
||||
}
|
||||
|
||||
let lua = Lua::new();
|
||||
lua.globals().set("userdata", UserData(10)).unwrap();
|
||||
|
||||
c.bench_function("call [userdata index] 10", |b| {
|
||||
b.iter_batched_ref(
|
||||
|| {
|
||||
collect_gc_twice(&lua);
|
||||
lua.load("function() for i = 1,10 do local v = userdata.test end end")
|
||||
.eval::<LuaFunction>()
|
||||
.unwrap()
|
||||
},
|
||||
|function| {
|
||||
function.call::<_, ()>(()).unwrap();
|
||||
},
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
fn call_userdata_method(c: &mut Criterion) {
|
||||
struct UserData(i64);
|
||||
impl LuaUserData for UserData {
|
||||
|
@ -283,6 +310,7 @@ criterion_group! {
|
|||
call_concat_callback,
|
||||
create_registry_values,
|
||||
create_userdata,
|
||||
call_userdata_index,
|
||||
call_userdata_method,
|
||||
call_async_userdata_method,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
pub fn probe_lua() -> Option<PathBuf> {
|
||||
unreachable!()
|
||||
None
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use std::env;
|
||||
use std::ops::Bound;
|
||||
use std::path::PathBuf;
|
||||
|
@ -70,7 +72,7 @@ pub fn probe_lua() -> Option<PathBuf> {
|
|||
.probe(alt_probe);
|
||||
}
|
||||
|
||||
lua.expect(&format!("cannot find Lua {} using `pkg-config`", ver))
|
||||
lua.unwrap_or_else(|_| panic!("cannot find Lua {} using `pkg-config`", ver))
|
||||
.include_paths
|
||||
.get(0)
|
||||
.cloned()
|
||||
|
@ -79,7 +81,7 @@ pub fn probe_lua() -> Option<PathBuf> {
|
|||
#[cfg(feature = "luajit")]
|
||||
{
|
||||
let lua = pkg_config::Config::new()
|
||||
.range_version((Bound::Included("2.0.5"), Bound::Unbounded))
|
||||
.range_version((Bound::Included("2.0.4"), Bound::Unbounded))
|
||||
.cargo_metadata(need_lua_lib)
|
||||
.probe("luajit");
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn probe_lua() -> Option<PathBuf> {
|
||||
|
@ -17,8 +19,9 @@ pub fn probe_lua() -> Option<PathBuf> {
|
|||
}
|
||||
builder.build()
|
||||
};
|
||||
#[cfg(feature = "luau")]
|
||||
let artifacts = luau0_src::Build::new().build();
|
||||
|
||||
#[cfg(not(feature = "module"))]
|
||||
artifacts.print_cargo_metadata();
|
||||
|
||||
Some(artifacts.include_dir().to_owned())
|
||||
|
|
230
build/main.rs
230
build/main.rs
|
@ -1,20 +1,15 @@
|
|||
#![allow(unreachable_code)]
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::{Error, ErrorKind, Result, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
#[cfg_attr(
|
||||
all(
|
||||
feature = "vendored",
|
||||
any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "lua51",
|
||||
feature = "luajit"
|
||||
any(
|
||||
feature = "luau",
|
||||
all(
|
||||
feature = "vendored",
|
||||
any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "lua51",
|
||||
feature = "luajit"
|
||||
)
|
||||
)
|
||||
),
|
||||
path = "find_vendored.rs"
|
||||
|
@ -38,174 +33,24 @@ use std::process::Command;
|
|||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "lua51",
|
||||
feature = "luajit"
|
||||
feature = "luajit",
|
||||
feature = "luau"
|
||||
)),
|
||||
path = "find_dummy.rs"
|
||||
)]
|
||||
mod find;
|
||||
|
||||
trait CommandExt {
|
||||
fn execute(&mut self) -> Result<()>;
|
||||
}
|
||||
|
||||
impl CommandExt for Command {
|
||||
/// Execute the command and return an error if it exited with a failure status.
|
||||
fn execute(&mut self) -> Result<()> {
|
||||
self.status()
|
||||
.and_then(|status| {
|
||||
if status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(ErrorKind::Other, "non-zero exit code"))
|
||||
}
|
||||
})
|
||||
.map_err(|_| {
|
||||
Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("The command {:?} did not run successfully.", self),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// `include_path` is optional as Lua headers can be also found in compiler standard paths
|
||||
fn build_glue(include_path: Option<impl AsRef<Path>>) {
|
||||
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
|
||||
let mut config = cc::Build::new();
|
||||
if let Some(include_path) = include_path {
|
||||
config.include(include_path.as_ref());
|
||||
}
|
||||
|
||||
// Compile and run glue.c
|
||||
let glue = build_dir.join("glue");
|
||||
|
||||
config
|
||||
.get_compiler()
|
||||
.to_command()
|
||||
.arg("src/ffi/glue/glue.c")
|
||||
.arg("-o")
|
||||
.arg(&glue)
|
||||
.execute()
|
||||
.unwrap();
|
||||
|
||||
Command::new(glue)
|
||||
.arg(build_dir.join("glue.rs"))
|
||||
.execute()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// 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
|
||||
)?;
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
writeln!(
|
||||
glue,
|
||||
"pub const LUA_REGISTRYINDEX: c_int = -{} - 1000;",
|
||||
if pointer_bit_width >= 32 {
|
||||
1_000_000
|
||||
} else {
|
||||
15_000
|
||||
}
|
||||
)?;
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
writeln!(glue, "pub const LUA_REGISTRYINDEX: c_int = -10000;")?;
|
||||
|
||||
// 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() {
|
||||
#[cfg(not(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "lua51",
|
||||
feature = "luajit"
|
||||
feature = "luajit",
|
||||
feature = "luau"
|
||||
)))]
|
||||
compile_error!(
|
||||
"You must enable one of the features: lua54, lua53, lua52, lua51, luajit, luajit52"
|
||||
"You must enable one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau"
|
||||
);
|
||||
|
||||
#[cfg(all(
|
||||
|
@ -214,29 +59,43 @@ fn main() {
|
|||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "lua51",
|
||||
feature = "luajit"
|
||||
feature = "luajit",
|
||||
feature = "luau"
|
||||
)
|
||||
))]
|
||||
compile_error!(
|
||||
"You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52"
|
||||
"You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau"
|
||||
);
|
||||
|
||||
#[cfg(all(
|
||||
feature = "lua53",
|
||||
any(feature = "lua52", feature = "lua51", feature = "luajit")
|
||||
any(
|
||||
feature = "lua52",
|
||||
feature = "lua51",
|
||||
feature = "luajit",
|
||||
feature = "luau"
|
||||
)
|
||||
))]
|
||||
compile_error!(
|
||||
"You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52"
|
||||
"You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau"
|
||||
);
|
||||
|
||||
#[cfg(all(feature = "lua52", any(feature = "lua51", feature = "luajit")))]
|
||||
#[cfg(all(
|
||||
feature = "lua52",
|
||||
any(feature = "lua51", feature = "luajit", feature = "luau")
|
||||
))]
|
||||
compile_error!(
|
||||
"You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52"
|
||||
"You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau"
|
||||
);
|
||||
|
||||
#[cfg(all(feature = "lua51", feature = "luajit"))]
|
||||
#[cfg(all(feature = "lua51", any(feature = "luajit", feature = "luau")))]
|
||||
compile_error!(
|
||||
"You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52"
|
||||
"You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau"
|
||||
);
|
||||
|
||||
#[cfg(all(feature = "luajit", feature = "luau"))]
|
||||
compile_error!(
|
||||
"You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau"
|
||||
);
|
||||
|
||||
// We don't support "vendored module" mode on windows
|
||||
|
@ -246,14 +105,11 @@ fn main() {
|
|||
+ "Please, use `pkg-config` or custom mode to link to a Lua dll."
|
||||
);
|
||||
|
||||
let include_dir = find::probe_lua();
|
||||
if env::var("TARGET").unwrap() != env::var("HOST").unwrap() {
|
||||
// The `probe_lua` call above is still needed here
|
||||
generate_glue().unwrap();
|
||||
} else {
|
||||
build_glue(include_dir);
|
||||
println!("cargo:rerun-if-changed=src/ffi/glue/glue.c");
|
||||
}
|
||||
#[cfg(all(feature = "luau", feature = "module"))]
|
||||
compile_error!("Luau does not support module mode");
|
||||
|
||||
#[cfg(any(not(feature = "module"), target_os = "windows"))]
|
||||
find::probe_lua();
|
||||
|
||||
println!("cargo:rerun-if-changed=build");
|
||||
}
|
||||
|
|
|
@ -7,13 +7,14 @@ edition = "2018"
|
|||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[workspace]
|
||||
|
||||
[features]
|
||||
lua54 = ["mlua/lua54"]
|
||||
lua53 = ["mlua/lua53"]
|
||||
lua52 = ["mlua/lua52"]
|
||||
lua51 = ["mlua/lua51"]
|
||||
luajit = ["mlua/luajit"]
|
||||
vendored = ["mlua/vendored"]
|
||||
|
||||
[dependencies]
|
||||
mlua = { path = "../..", features = ["module"] }
|
||||
|
|
|
@ -8,32 +8,10 @@ fn used_memory(lua: &Lua, _: ()) -> LuaResult<usize> {
|
|||
Ok(lua.used_memory())
|
||||
}
|
||||
|
||||
fn check_userdata(_: &Lua, ud: MyUserData) -> LuaResult<i32> {
|
||||
Ok(ud.0)
|
||||
}
|
||||
|
||||
#[mlua::lua_module]
|
||||
fn rust_module(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let exports = lua.create_table()?;
|
||||
exports.set("sum", lua.create_function(sum)?)?;
|
||||
exports.set("used_memory", lua.create_function(used_memory)?)?;
|
||||
exports.set("check_userdata", lua.create_function(check_userdata)?)?;
|
||||
Ok(exports)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct MyUserData(i32);
|
||||
|
||||
impl LuaUserData for MyUserData {}
|
||||
|
||||
#[mlua::lua_module]
|
||||
fn rust_module_second(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let exports = lua.create_table()?;
|
||||
exports.set("userdata", lua.create_userdata(MyUserData(123))?)?;
|
||||
Ok(exports)
|
||||
}
|
||||
|
||||
#[mlua::lua_module]
|
||||
fn rust_module_error(_: &Lua) -> LuaResult<LuaTable> {
|
||||
Err("custom module error".to_lua_err())
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use rustyline::Editor;
|
|||
|
||||
fn main() {
|
||||
let lua = Lua::new();
|
||||
let mut editor = Editor::<()>::new();
|
||||
let mut editor = Editor::<()>::new().expect("Failed to make rustyline editor");
|
||||
|
||||
loop {
|
||||
let mut prompt = "> ";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "mlua_derive"
|
||||
version = "0.6.0"
|
||||
version = "0.8.0"
|
||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
|
||||
edition = "2018"
|
||||
description = "Procedural macros for the mlua crate."
|
||||
|
@ -21,4 +21,4 @@ proc-macro-error = { version = "1.0", optional = true }
|
|||
syn = { version = "1.0", features = ["full"] }
|
||||
itertools = { version = "0.10", optional = true }
|
||||
regex = { version = "1.4", optional = true }
|
||||
once_cell = { version = "1.5", optional = true }
|
||||
once_cell = { version = "1.0", optional = true }
|
||||
|
|
|
@ -62,6 +62,8 @@ pub fn chunk(input: TokenStream) -> TokenStream {
|
|||
|
||||
let wrapped_code = quote! {{
|
||||
use ::mlua::{AsChunk, ChunkMode, Lua, Result, Value};
|
||||
use ::std::borrow::Cow;
|
||||
use ::std::io::Result as IoResult;
|
||||
use ::std::marker::PhantomData;
|
||||
use ::std::sync::Mutex;
|
||||
|
||||
|
@ -73,8 +75,8 @@ pub fn chunk(input: TokenStream) -> TokenStream {
|
|||
where
|
||||
F: FnOnce(&'lua Lua) -> Result<Value<'lua>>,
|
||||
{
|
||||
fn source(&self) -> &[u8] {
|
||||
(#source).as_bytes()
|
||||
fn source(&self) -> IoResult<Cow<[u8]>> {
|
||||
Ok(Cow::Borrowed((#source).as_bytes()))
|
||||
}
|
||||
|
||||
fn env(&self, lua: &'lua Lua) -> Result<Option<Value<'lua>>> {
|
||||
|
|
510
src/chunk.rs
Normal file
510
src/chunk.rs
Normal file
|
@ -0,0 +1,510 @@
|
|||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CString;
|
||||
use std::io::Result as IoResult;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::string::String as StdString;
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::function::Function;
|
||||
use crate::lua::Lua;
|
||||
use crate::value::{FromLuaMulti, ToLua, ToLuaMulti, Value};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
use {futures_core::future::LocalBoxFuture, futures_util::future};
|
||||
|
||||
/// Trait for types [loadable by Lua] and convertible to a [`Chunk`]
|
||||
///
|
||||
/// [loadable by Lua]: https://www.lua.org/manual/5.4/manual.html#3.3.2
|
||||
/// [`Chunk`]: crate::Chunk
|
||||
pub trait AsChunk<'lua> {
|
||||
/// Returns chunk data (can be text or binary)
|
||||
fn source(&self) -> IoResult<Cow<[u8]>>;
|
||||
|
||||
/// Returns optional chunk name
|
||||
fn name(&self) -> Option<StdString> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns optional chunk [environment]
|
||||
///
|
||||
/// [environment]: https://www.lua.org/manual/5.4/manual.html#2.2
|
||||
fn env(&self, _lua: &'lua Lua) -> Result<Option<Value<'lua>>> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Returns optional chunk mode (text or binary)
|
||||
fn mode(&self) -> Option<ChunkMode> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsChunk<'lua> for str {
|
||||
fn source(&self) -> IoResult<Cow<[u8]>> {
|
||||
Ok(Cow::Borrowed(self.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsChunk<'lua> for StdString {
|
||||
fn source(&self) -> IoResult<Cow<[u8]>> {
|
||||
Ok(Cow::Borrowed(self.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsChunk<'lua> for [u8] {
|
||||
fn source(&self) -> IoResult<Cow<[u8]>> {
|
||||
Ok(Cow::Borrowed(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsChunk<'lua> for Vec<u8> {
|
||||
fn source(&self) -> IoResult<Cow<[u8]>> {
|
||||
Ok(Cow::Borrowed(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsChunk<'lua> for Path {
|
||||
fn source(&self) -> IoResult<Cow<[u8]>> {
|
||||
std::fs::read(self).map(Cow::Owned)
|
||||
}
|
||||
|
||||
fn name(&self) -> Option<StdString> {
|
||||
Some(format!("@{}", self.display()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsChunk<'lua> for PathBuf {
|
||||
fn source(&self) -> IoResult<Cow<[u8]>> {
|
||||
std::fs::read(self).map(Cow::Owned)
|
||||
}
|
||||
|
||||
fn name(&self) -> Option<StdString> {
|
||||
Some(format!("@{}", self.display()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returned from [`Lua::load`] and is used to finalize loading and executing Lua main chunks.
|
||||
///
|
||||
/// [`Lua::load`]: crate::Lua::load
|
||||
#[must_use = "`Chunk`s do nothing unless one of `exec`, `eval`, `call`, or `into_function` are called on them"]
|
||||
pub struct Chunk<'lua, 'a> {
|
||||
pub(crate) lua: &'lua Lua,
|
||||
pub(crate) source: IoResult<Cow<'a, [u8]>>,
|
||||
pub(crate) name: Option<StdString>,
|
||||
pub(crate) env: Result<Option<Value<'lua>>>,
|
||||
pub(crate) mode: Option<ChunkMode>,
|
||||
#[cfg(feature = "luau")]
|
||||
pub(crate) compiler: Option<Compiler>,
|
||||
}
|
||||
|
||||
/// Represents chunk mode (text or binary).
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum ChunkMode {
|
||||
Text,
|
||||
Binary,
|
||||
}
|
||||
|
||||
/// Luau compiler
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Compiler {
|
||||
optimization_level: u8,
|
||||
debug_level: u8,
|
||||
coverage_level: u8,
|
||||
vector_lib: Option<String>,
|
||||
vector_ctor: Option<String>,
|
||||
mutable_globals: Vec<String>,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
impl Default for Compiler {
|
||||
fn default() -> Self {
|
||||
// Defaults are taken from luacode.h
|
||||
Compiler {
|
||||
optimization_level: 1,
|
||||
debug_level: 1,
|
||||
coverage_level: 0,
|
||||
vector_lib: None,
|
||||
vector_ctor: None,
|
||||
mutable_globals: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
impl Compiler {
|
||||
/// Creates Luau compiler instance with default options
|
||||
pub fn new() -> Self {
|
||||
Compiler::default()
|
||||
}
|
||||
|
||||
/// Sets Luau compiler optimization level.
|
||||
///
|
||||
/// Possible values:
|
||||
/// * 0 - no optimization
|
||||
/// * 1 - baseline optimization level that doesn't prevent debuggability (default)
|
||||
/// * 2 - includes optimizations that harm debuggability such as inlining
|
||||
pub fn set_optimization_level(mut self, level: u8) -> Self {
|
||||
self.optimization_level = level;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets Luau compiler debug level.
|
||||
///
|
||||
/// Possible values:
|
||||
/// * 0 - no debugging support
|
||||
/// * 1 - line info & function names only; sufficient for backtraces (default)
|
||||
/// * 2 - full debug info with local & upvalue names; necessary for debugger
|
||||
pub fn set_debug_level(mut self, level: u8) -> Self {
|
||||
self.debug_level = level;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets Luau compiler code coverage level.
|
||||
///
|
||||
/// Possible values:
|
||||
/// * 0 - no code coverage support (default)
|
||||
/// * 1 - statement coverage
|
||||
/// * 2 - statement and expression coverage (verbose)
|
||||
pub fn set_coverage_level(mut self, level: u8) -> Self {
|
||||
self.coverage_level = level;
|
||||
self
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn set_vector_lib(mut self, lib: Option<String>) -> Self {
|
||||
self.vector_lib = lib;
|
||||
self
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn set_vector_ctor(mut self, ctor: Option<String>) -> Self {
|
||||
self.vector_ctor = ctor;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets a list of globals that are mutable.
|
||||
///
|
||||
/// It disables the import optimization for fields accessed through these.
|
||||
pub fn set_mutable_globals(mut self, globals: Vec<String>) -> Self {
|
||||
self.mutable_globals = globals;
|
||||
self
|
||||
}
|
||||
|
||||
/// Compiles the `source` into bytecode.
|
||||
pub fn compile(&self, source: impl AsRef<[u8]>) -> Vec<u8> {
|
||||
use std::os::raw::c_int;
|
||||
use std::ptr;
|
||||
|
||||
let vector_lib = self.vector_lib.clone();
|
||||
let vector_lib = vector_lib.and_then(|lib| CString::new(lib).ok());
|
||||
let vector_lib = vector_lib.as_ref();
|
||||
let vector_ctor = self.vector_ctor.clone();
|
||||
let vector_ctor = vector_ctor.and_then(|ctor| CString::new(ctor).ok());
|
||||
let vector_ctor = vector_ctor.as_ref();
|
||||
|
||||
let mutable_globals = self
|
||||
.mutable_globals
|
||||
.iter()
|
||||
.map(|name| CString::new(name.clone()).ok())
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap_or_default();
|
||||
let mut mutable_globals = mutable_globals
|
||||
.iter()
|
||||
.map(|s| s.as_ptr())
|
||||
.collect::<Vec<_>>();
|
||||
let mut mutable_globals_ptr = ptr::null_mut();
|
||||
if !mutable_globals.is_empty() {
|
||||
mutable_globals.push(ptr::null());
|
||||
mutable_globals_ptr = mutable_globals.as_mut_ptr();
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let options = ffi::lua_CompileOptions {
|
||||
optimizationLevel: self.optimization_level as c_int,
|
||||
debugLevel: self.debug_level as c_int,
|
||||
coverageLevel: self.coverage_level as c_int,
|
||||
vectorLib: vector_lib.map_or(ptr::null(), |s| s.as_ptr()),
|
||||
vectorCtor: vector_ctor.map_or(ptr::null(), |s| s.as_ptr()),
|
||||
mutableGlobals: mutable_globals_ptr,
|
||||
};
|
||||
ffi::luau_compile(source.as_ref(), options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, 'a> Chunk<'lua, 'a> {
|
||||
/// Sets the name of this chunk, which results in more informative error traces.
|
||||
pub fn set_name(mut self, name: impl AsRef<str>) -> Result<Self> {
|
||||
self.name = Some(name.as_ref().to_string());
|
||||
// Do extra validation
|
||||
let _ = self.convert_name()?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Sets the first upvalue (`_ENV`) of the loaded chunk to the given value.
|
||||
///
|
||||
/// Lua main chunks always have exactly one upvalue, and this upvalue is used as the `_ENV`
|
||||
/// variable inside the chunk. By default this value is set to the global environment.
|
||||
///
|
||||
/// Calling this method changes the `_ENV` upvalue to the value provided, and variables inside
|
||||
/// the chunk will refer to the given environment rather than the global one.
|
||||
///
|
||||
/// All global variables (including the standard library!) are looked up in `_ENV`, so it may be
|
||||
/// necessary to populate the environment in order for scripts using custom environments to be
|
||||
/// useful.
|
||||
pub fn set_environment<V: ToLua<'lua>>(mut self, env: V) -> Result<Self> {
|
||||
// Prefer to propagate errors here and wrap to `Ok`
|
||||
self.env = Ok(Some(env.to_lua(self.lua)?));
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Sets whether the chunk is text or binary (autodetected by default).
|
||||
///
|
||||
/// Be aware, Lua does not check the consistency of the code inside binary chunks.
|
||||
/// Running maliciously crafted bytecode can crash the interpreter.
|
||||
pub fn set_mode(mut self, mode: ChunkMode) -> Self {
|
||||
self.mode = Some(mode);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets or overwrites a Luau compiler used for this chunk.
|
||||
///
|
||||
/// See [`Compiler`] for details and possible options.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn set_compiler(mut self, compiler: Compiler) -> Self {
|
||||
self.compiler = Some(compiler);
|
||||
self
|
||||
}
|
||||
|
||||
/// Execute this chunk of code.
|
||||
///
|
||||
/// This is equivalent to calling the chunk function with no arguments and no return values.
|
||||
pub fn exec(self) -> Result<()> {
|
||||
self.call(())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Asynchronously execute this chunk of code.
|
||||
///
|
||||
/// See [`exec`] for more details.
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`exec`]: #method.exec
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
pub fn exec_async<'fut>(self) -> LocalBoxFuture<'fut, Result<()>>
|
||||
where
|
||||
'lua: 'fut,
|
||||
{
|
||||
self.call_async(())
|
||||
}
|
||||
|
||||
/// Evaluate the chunk as either an expression or block.
|
||||
///
|
||||
/// If the chunk can be parsed as an expression, this loads and executes the chunk and returns
|
||||
/// the value that it evaluates to. Otherwise, the chunk is interpreted as a block as normal,
|
||||
/// and this is equivalent to calling `exec`.
|
||||
pub fn eval<R: FromLuaMulti<'lua>>(self) -> Result<R> {
|
||||
// Bytecode is always interpreted as a statement.
|
||||
// For source code, first try interpreting the lua as an expression by adding
|
||||
// "return", then as a statement. This is the same thing the
|
||||
// actual lua repl does.
|
||||
if self.detect_mode() == ChunkMode::Binary {
|
||||
self.call(())
|
||||
} else if let Ok(function) = self.to_expression() {
|
||||
function.call(())
|
||||
} else {
|
||||
self.call(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Asynchronously evaluate the chunk as either an expression or block.
|
||||
///
|
||||
/// See [`eval`] for more details.
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`eval`]: #method.eval
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
pub fn eval_async<'fut, R>(self) -> LocalBoxFuture<'fut, Result<R>>
|
||||
where
|
||||
'lua: 'fut,
|
||||
R: FromLuaMulti<'lua> + 'fut,
|
||||
{
|
||||
if self.detect_mode() == ChunkMode::Binary {
|
||||
self.call_async(())
|
||||
} else if let Ok(function) = self.to_expression() {
|
||||
function.call_async(())
|
||||
} else {
|
||||
self.call_async(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Load the chunk function and call it with the given arguments.
|
||||
///
|
||||
/// This is equivalent to `into_function` and calling the resulting function.
|
||||
pub fn call<A: ToLuaMulti<'lua>, R: FromLuaMulti<'lua>>(self, args: A) -> Result<R> {
|
||||
self.into_function()?.call(args)
|
||||
}
|
||||
|
||||
/// Load the chunk function and asynchronously call it with the given arguments.
|
||||
///
|
||||
/// See [`call`] for more details.
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`call`]: #method.call
|
||||
#[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,
|
||||
{
|
||||
match self.into_function() {
|
||||
Ok(func) => func.call_async(args),
|
||||
Err(e) => Box::pin(future::err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Load this chunk into a regular `Function`.
|
||||
///
|
||||
/// This simply compiles the chunk without actually executing it.
|
||||
#[cfg_attr(not(feature = "luau"), allow(unused_mut))]
|
||||
pub fn into_function(mut self) -> Result<Function<'lua>> {
|
||||
#[cfg(feature = "luau")]
|
||||
if self.compiler.is_some() {
|
||||
// We don't need to compile source if no compiler set
|
||||
self.compile();
|
||||
}
|
||||
|
||||
let name = self.convert_name()?;
|
||||
self.lua
|
||||
.load_chunk(self.source?.as_ref(), name.as_deref(), self.env?, self.mode)
|
||||
}
|
||||
|
||||
/// Compiles the chunk and changes mode to binary.
|
||||
///
|
||||
/// It does nothing if the chunk is already binary.
|
||||
fn compile(&mut self) {
|
||||
if let Ok(ref source) = self.source {
|
||||
if self.detect_mode() == ChunkMode::Text {
|
||||
#[cfg(feature = "luau")]
|
||||
{
|
||||
let data = self
|
||||
.compiler
|
||||
.get_or_insert_with(Default::default)
|
||||
.compile(source);
|
||||
self.source = Ok(Cow::Owned(data));
|
||||
self.mode = Some(ChunkMode::Binary);
|
||||
}
|
||||
#[cfg(not(feature = "luau"))]
|
||||
if let Ok(func) = self.lua.load_chunk(source.as_ref(), None, None, None) {
|
||||
let data = func.dump(false);
|
||||
self.source = Ok(Cow::Owned(data));
|
||||
self.mode = Some(ChunkMode::Binary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetches compiled bytecode of this chunk from the cache.
|
||||
///
|
||||
/// If not found, compiles the source code and stores it on the cache.
|
||||
pub(crate) fn try_cache(mut self) -> Self {
|
||||
struct ChunksCache(HashMap<Vec<u8>, Vec<u8>>);
|
||||
|
||||
// Try to fetch compiled chunk from cache
|
||||
let mut text_source = None;
|
||||
if let Ok(ref source) = self.source {
|
||||
if self.detect_mode() == ChunkMode::Text {
|
||||
if let Some(cache) = self.lua.app_data_ref::<ChunksCache>() {
|
||||
if let Some(data) = cache.0.get(source.as_ref()) {
|
||||
self.source = Ok(Cow::Owned(data.clone()));
|
||||
self.mode = Some(ChunkMode::Binary);
|
||||
return self;
|
||||
}
|
||||
}
|
||||
text_source = Some(source.as_ref().to_vec());
|
||||
}
|
||||
}
|
||||
|
||||
// Compile and cache the chunk
|
||||
if let Some(text_source) = text_source {
|
||||
self.compile();
|
||||
if let Ok(ref binary_source) = self.source {
|
||||
if self.detect_mode() == ChunkMode::Binary {
|
||||
if let Some(mut cache) = self.lua.app_data_mut::<ChunksCache>() {
|
||||
cache.0.insert(text_source, binary_source.as_ref().to_vec());
|
||||
} else {
|
||||
let mut cache = ChunksCache(HashMap::new());
|
||||
cache.0.insert(text_source, binary_source.as_ref().to_vec());
|
||||
self.lua.set_app_data(cache);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
fn to_expression(&self) -> Result<Function<'lua>> {
|
||||
// We assume that mode is Text
|
||||
let source = self.source.as_ref();
|
||||
let source = source.map_err(|err| Error::RuntimeError(err.to_string()))?;
|
||||
let source = Self::expression_source(source);
|
||||
// We don't need to compile source if no compiler options set
|
||||
#[cfg(feature = "luau")]
|
||||
let source = self
|
||||
.compiler
|
||||
.as_ref()
|
||||
.map(|c| c.compile(&source))
|
||||
.unwrap_or(source);
|
||||
|
||||
let name = self.convert_name()?;
|
||||
self.lua
|
||||
.load_chunk(&source, name.as_deref(), self.env.clone()?, None)
|
||||
}
|
||||
|
||||
fn detect_mode(&self) -> ChunkMode {
|
||||
match (self.mode, &self.source) {
|
||||
(Some(mode), _) => mode,
|
||||
(None, Ok(source)) => {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
if source.starts_with(ffi::LUA_SIGNATURE) {
|
||||
return ChunkMode::Binary;
|
||||
}
|
||||
#[cfg(feature = "luau")]
|
||||
if *source.first().unwrap_or(&u8::MAX) < b'\n' {
|
||||
return ChunkMode::Binary;
|
||||
}
|
||||
ChunkMode::Text
|
||||
}
|
||||
(None, Err(_)) => ChunkMode::Text, // any value is fine
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_name(&self) -> Result<Option<CString>> {
|
||||
self.name
|
||||
.clone()
|
||||
.map(CString::new)
|
||||
.transpose()
|
||||
.map_err(|err| Error::RuntimeError(format!("invalid name: {err}")))
|
||||
}
|
||||
|
||||
fn expression_source(source: &[u8]) -> Vec<u8> {
|
||||
let mut buf = Vec::with_capacity(b"return ".len() + source.len());
|
||||
buf.extend(b"return ");
|
||||
buf.extend(source);
|
||||
buf
|
||||
}
|
||||
}
|
|
@ -250,18 +250,21 @@ impl<'lua> ToLua<'lua> for &str {
|
|||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for Cow<'_, str> {
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::String(lua.create_string(self.as_bytes())?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for Box<str> {
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::String(lua.create_string(&*self)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for Box<str> {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
let ty = value.type_name();
|
||||
Ok(lua
|
||||
|
@ -278,12 +281,14 @@ impl<'lua> FromLua<'lua> for Box<str> {
|
|||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for CString {
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::String(lua.create_string(self.as_bytes())?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for CString {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
let ty = value.type_name();
|
||||
let string = lua
|
||||
|
@ -306,24 +311,28 @@ impl<'lua> FromLua<'lua> for CString {
|
|||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for &CStr {
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::String(lua.create_string(self.to_bytes())?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for Cow<'_, CStr> {
|
||||
#[inline]
|
||||
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 {
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::String(lua.create_string(&self)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for BString {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
let ty = value.type_name();
|
||||
Ok(BString::from(
|
||||
|
@ -340,14 +349,16 @@ impl<'lua> FromLua<'lua> for BString {
|
|||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for &BStr {
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::String(lua.create_string(&self)?))
|
||||
Ok(Value::String(lua.create_string(self)?))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! lua_convert_int {
|
||||
($x:ty) => {
|
||||
impl<'lua> ToLua<'lua> for $x {
|
||||
#[inline]
|
||||
fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
|
||||
cast(self)
|
||||
.map(Value::Integer)
|
||||
|
@ -362,22 +373,27 @@ macro_rules! lua_convert_int {
|
|||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for $x {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
let ty = value.type_name();
|
||||
(if let Value::Integer(i) = value {
|
||||
cast(i)
|
||||
} else if let Some(i) = lua.coerce_integer(value.clone())? {
|
||||
cast(i)
|
||||
} else {
|
||||
cast(lua.coerce_number(value)?.ok_or_else(|| {
|
||||
Error::FromLuaConversionError {
|
||||
from: ty,
|
||||
to: stringify!($x),
|
||||
message: Some(
|
||||
"expected number or string coercible to number".to_string(),
|
||||
),
|
||||
(match value {
|
||||
Value::Integer(i) => cast(i),
|
||||
Value::Number(n) => cast(n),
|
||||
_ => {
|
||||
if let Some(i) = lua.coerce_integer(value.clone())? {
|
||||
cast(i)
|
||||
} else {
|
||||
cast(lua.coerce_number(value)?.ok_or_else(|| {
|
||||
Error::FromLuaConversionError {
|
||||
from: ty,
|
||||
to: stringify!($x),
|
||||
message: Some(
|
||||
"expected number or string coercible to number".to_string(),
|
||||
),
|
||||
}
|
||||
})?)
|
||||
}
|
||||
})?)
|
||||
}
|
||||
})
|
||||
.ok_or_else(|| Error::FromLuaConversionError {
|
||||
from: ty,
|
||||
|
@ -405,6 +421,7 @@ lua_convert_int!(usize);
|
|||
macro_rules! lua_convert_float {
|
||||
($x:ty) => {
|
||||
impl<'lua> ToLua<'lua> for $x {
|
||||
#[inline]
|
||||
fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
|
||||
cast(self)
|
||||
.ok_or_else(|| Error::ToLuaConversionError {
|
||||
|
@ -417,6 +434,7 @@ macro_rules! lua_convert_float {
|
|||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for $x {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
let ty = value.type_name();
|
||||
lua.coerce_number(value)?
|
||||
|
@ -444,6 +462,7 @@ impl<'lua, T> ToLua<'lua> for &[T]
|
|||
where
|
||||
T: Clone + ToLua<'lua>,
|
||||
{
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Table(
|
||||
lua.create_sequence_from(self.iter().cloned())?,
|
||||
|
@ -455,6 +474,7 @@ impl<'lua, T, const N: usize> ToLua<'lua> for [T; N]
|
|||
where
|
||||
T: ToLua<'lua>,
|
||||
{
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Table(lua.create_sequence_from(self)?))
|
||||
}
|
||||
|
@ -464,61 +484,75 @@ impl<'lua, T, const N: usize> FromLua<'lua> for [T; N]
|
|||
where
|
||||
T: FromLua<'lua>,
|
||||
{
|
||||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||
if let Value::Table(table) = value {
|
||||
let vec = table.sequence_values().collect::<Result<Vec<_>>>()?;
|
||||
vec.try_into()
|
||||
.map_err(|vec: Vec<T>| Error::FromLuaConversionError {
|
||||
from: "Table",
|
||||
to: "Array",
|
||||
message: Some(format!("expected table of length {}, got {}", N, vec.len())),
|
||||
})
|
||||
} else {
|
||||
Err(Error::FromLuaConversionError {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, _lua: &'lua Lua) -> Result<Self> {
|
||||
match value {
|
||||
#[cfg(feature = "luau")]
|
||||
Value::Vector(x, y, z) if N == 3 => Ok(mlua_expect!(
|
||||
vec![
|
||||
T::from_lua(Value::Number(x as _), _lua)?,
|
||||
T::from_lua(Value::Number(y as _), _lua)?,
|
||||
T::from_lua(Value::Number(z as _), _lua)?,
|
||||
]
|
||||
.try_into()
|
||||
.map_err(|_| ()),
|
||||
"cannot convert vector to array"
|
||||
)),
|
||||
Value::Table(table) => {
|
||||
let vec = table.sequence_values().collect::<Result<Vec<_>>>()?;
|
||||
vec.try_into()
|
||||
.map_err(|vec: Vec<T>| Error::FromLuaConversionError {
|
||||
from: "Table",
|
||||
to: "Array",
|
||||
message: Some(format!("expected table of length {}, got {}", N, vec.len())),
|
||||
})
|
||||
}
|
||||
_ => Err(Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "Array",
|
||||
message: Some("expected table".to_string()),
|
||||
})
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: ToLua<'lua>> ToLua<'lua> for Box<[T]> {
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Table(lua.create_sequence_from(self.into_vec())?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Box<[T]> {
|
||||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||
if let Value::Table(table) = value {
|
||||
table.sequence_values().collect()
|
||||
} else {
|
||||
Err(Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "Box<[T]>",
|
||||
message: Some("expected table".to_string()),
|
||||
})
|
||||
}
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
Ok(Vec::<T>::from_lua(value, lua)?.into_boxed_slice())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: ToLua<'lua>> ToLua<'lua> for Vec<T> {
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Table(lua.create_sequence_from(self)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Vec<T> {
|
||||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||
if let Value::Table(table) = value {
|
||||
table.sequence_values().collect()
|
||||
} else {
|
||||
Err(Error::FromLuaConversionError {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, _lua: &'lua Lua) -> Result<Self> {
|
||||
match value {
|
||||
#[cfg(feature = "luau")]
|
||||
Value::Vector(x, y, z) => Ok(vec![
|
||||
T::from_lua(Value::Number(x as _), _lua)?,
|
||||
T::from_lua(Value::Number(y as _), _lua)?,
|
||||
T::from_lua(Value::Number(z as _), _lua)?,
|
||||
]),
|
||||
Value::Table(table) => table.sequence_values().collect(),
|
||||
_ => Err(Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "Vec",
|
||||
message: Some("expected table".to_string()),
|
||||
})
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -526,6 +560,7 @@ impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Vec<T> {
|
|||
impl<'lua, K: Eq + Hash + ToLua<'lua>, V: ToLua<'lua>, S: BuildHasher> ToLua<'lua>
|
||||
for HashMap<K, V, S>
|
||||
{
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Table(lua.create_table_from(self)?))
|
||||
}
|
||||
|
@ -534,6 +569,7 @@ impl<'lua, K: Eq + Hash + ToLua<'lua>, V: ToLua<'lua>, S: BuildHasher> ToLua<'lu
|
|||
impl<'lua, K: Eq + Hash + FromLua<'lua>, V: FromLua<'lua>, S: BuildHasher + Default> FromLua<'lua>
|
||||
for HashMap<K, V, S>
|
||||
{
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||
if let Value::Table(table) = value {
|
||||
table.pairs().collect()
|
||||
|
@ -548,12 +584,14 @@ impl<'lua, K: Eq + Hash + FromLua<'lua>, V: FromLua<'lua>, S: BuildHasher + Defa
|
|||
}
|
||||
|
||||
impl<'lua, K: Ord + ToLua<'lua>, V: ToLua<'lua>> ToLua<'lua> for BTreeMap<K, V> {
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Table(lua.create_table_from(self)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, K: Ord + FromLua<'lua>, V: FromLua<'lua>> FromLua<'lua> for BTreeMap<K, V> {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||
if let Value::Table(table) = value {
|
||||
table.pairs().collect()
|
||||
|
@ -568,6 +606,7 @@ 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> {
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Table(lua.create_table_from(
|
||||
self.into_iter().map(|val| (val, true)),
|
||||
|
@ -576,6 +615,7 @@ impl<'lua, T: Eq + Hash + ToLua<'lua>, S: BuildHasher> ToLua<'lua> for HashSet<T
|
|||
}
|
||||
|
||||
impl<'lua, T: Eq + Hash + FromLua<'lua>, S: BuildHasher + Default> FromLua<'lua> for HashSet<T, S> {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||
match value {
|
||||
Value::Table(table) if table.len()? > 0 => table.sequence_values().collect(),
|
||||
|
@ -593,6 +633,7 @@ impl<'lua, T: Eq + Hash + FromLua<'lua>, S: BuildHasher + Default> FromLua<'lua>
|
|||
}
|
||||
|
||||
impl<'lua, T: Ord + ToLua<'lua>> ToLua<'lua> for BTreeSet<T> {
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Table(lua.create_table_from(
|
||||
self.into_iter().map(|val| (val, true)),
|
||||
|
@ -601,6 +642,7 @@ impl<'lua, T: Ord + ToLua<'lua>> ToLua<'lua> for BTreeSet<T> {
|
|||
}
|
||||
|
||||
impl<'lua, T: Ord + FromLua<'lua>> FromLua<'lua> for BTreeSet<T> {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||
match value {
|
||||
Value::Table(table) if table.len()? > 0 => table.sequence_values().collect(),
|
||||
|
|
|
@ -37,7 +37,8 @@ pub enum Error {
|
|||
/// Lua garbage collector error, aka `LUA_ERRGCMM`.
|
||||
///
|
||||
/// 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", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua53", feature = "lua52"))))]
|
||||
GarbageCollectorError(StdString),
|
||||
/// Potentially unsafe action in safe mode.
|
||||
SafetyError(StdString),
|
||||
|
@ -248,7 +249,7 @@ impl fmt::Display for Error {
|
|||
write!(fmt, "RegistryKey used from different Lua state")
|
||||
}
|
||||
Error::CallbackError { ref cause, ref traceback } => {
|
||||
writeln!(fmt, "callback error")?;
|
||||
writeln!(fmt, "{}", cause)?;
|
||||
// Trace errors down to the root
|
||||
let (mut cause, mut full_traceback) = (cause, None);
|
||||
while let Error::CallbackError { cause: ref cause2, traceback: ref traceback2 } = **cause {
|
||||
|
@ -268,7 +269,9 @@ impl fmt::Display for Error {
|
|||
} else {
|
||||
writeln!(fmt, "{}", traceback.trim_end())?;
|
||||
}
|
||||
write!(fmt, "caused by: {}", cause)
|
||||
|
||||
Ok(())
|
||||
// write!(fmt, "caused by: {}", cause)
|
||||
}
|
||||
Error::PreviouslyResumedPanic => {
|
||||
write!(fmt, "previously resumed panic returned again")
|
||||
|
|
|
@ -1,289 +0,0 @@
|
|||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2019-2021 A. Orlenko
|
||||
// Copyright (c) 2014 J.C. Moyer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <lauxlib.h>
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
|
||||
#ifndef LUA_EXTRASPACE
|
||||
#define LUA_EXTRASPACE (sizeof(void*))
|
||||
#endif
|
||||
|
||||
// Macros taken from https://gcc.gnu.org/onlinedocs/cpp/Stringification.html
|
||||
#define xstr(s) str(s)
|
||||
#define str(s) #s
|
||||
|
||||
typedef struct rs_item {
|
||||
int type;
|
||||
const char *name;
|
||||
union {
|
||||
int int_val;
|
||||
const char *str_val;
|
||||
LUA_INTEGER lua_int_val;
|
||||
};
|
||||
} rs_item;
|
||||
|
||||
|
||||
#define TY_INT 0
|
||||
#define RS_INT(name, val) \
|
||||
{ TY_INT, name, .int_val = val }
|
||||
|
||||
#if LUA_VERSION_NUM >= 503
|
||||
#define TY_LUAINT 1
|
||||
#define RS_LUAINT(name, val) \
|
||||
{ TY_LUAINT, name, .lua_int_val = val }
|
||||
#endif
|
||||
|
||||
#define TY_STR 2
|
||||
#define RS_STR(name, val) \
|
||||
{ TY_STR, name, .str_val = val }
|
||||
|
||||
#define TY_TYPE 3
|
||||
#define RS_TYPE(name, val) \
|
||||
{ TY_TYPE, name, .str_val = val }
|
||||
|
||||
#define TY_COMMENT 4
|
||||
#define RS_COMMENT(val) \
|
||||
{ TY_COMMENT, NULL, .str_val = val }
|
||||
|
||||
#define TY_RAW 5
|
||||
#define RS_RAW(val) \
|
||||
{ TY_RAW, NULL, .str_val = val }
|
||||
|
||||
const char *rs_int_type(int width) {
|
||||
switch (width) {
|
||||
default:
|
||||
case 2:
|
||||
return "i16";
|
||||
case 4:
|
||||
return "i32";
|
||||
case 8:
|
||||
return "i64";
|
||||
case 16:
|
||||
return "i128";
|
||||
}
|
||||
}
|
||||
|
||||
const char *rs_uint_type(int width) {
|
||||
switch (width) {
|
||||
default:
|
||||
case 2:
|
||||
return "u16";
|
||||
case 4:
|
||||
return "u32";
|
||||
case 8:
|
||||
return "u64";
|
||||
case 16:
|
||||
return "u128";
|
||||
}
|
||||
}
|
||||
|
||||
int try_write(char **str, char c, size_t n, size_t *written, size_t szstr) {
|
||||
if (szstr - *written < n) {
|
||||
return 0;
|
||||
}
|
||||
for (; n; n--, *written++)
|
||||
*(*str)++ = c;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// converts \ in a string to \\ so that it can be used as a rust string literal
|
||||
// ensures that `out` will always have a null terminating character
|
||||
size_t escape(const char *in, char *out, size_t szout) {
|
||||
size_t written = 0;
|
||||
char cur;
|
||||
|
||||
while ((cur = *in++)) {
|
||||
switch (cur) {
|
||||
case '\\':
|
||||
if (!try_write(&out, cur, 2, &written, szout))
|
||||
goto finalize;
|
||||
break;
|
||||
default:
|
||||
if (!try_write(&out, cur, 1, &written, szout))
|
||||
goto finalize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
finalize:
|
||||
if (written + 1 <= szout) {
|
||||
*out++ = '\0';
|
||||
written++;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
int write_int_item(FILE *f, const char *name, int value) {
|
||||
return fprintf(f, "pub const %s: c_int = %d;\n", name, value);
|
||||
}
|
||||
|
||||
#if LUA_VERSION_NUM >= 503
|
||||
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,
|
||||
value);
|
||||
}
|
||||
#endif
|
||||
|
||||
int write_str_item(FILE *f, const char *name, const char *value) {
|
||||
size_t len = strlen(value);
|
||||
size_t bufsz = len * 2 + 1;
|
||||
char *buf = malloc(bufsz);
|
||||
int ret;
|
||||
escape(value, buf, bufsz);
|
||||
ret = fprintf(f, "pub const %s: &str = \"%s\";\n", name, buf);
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int write_type(FILE *f, const char *name, const char *value) {
|
||||
return fprintf(f, "pub type %s = %s;\n", name, value);
|
||||
}
|
||||
|
||||
int write_comment(FILE *f, const char *value) {
|
||||
return fprintf(f, "/* %s */\n", value);
|
||||
}
|
||||
|
||||
int write_raw(FILE *f, const char *value) { return fputs(value, f) >= 0; }
|
||||
|
||||
int write_item(FILE *f, const rs_item *c) {
|
||||
switch (c->type) {
|
||||
case TY_INT:
|
||||
return write_int_item(f, c->name, c->int_val);
|
||||
#if LUA_VERSION_NUM >= 503
|
||||
case TY_LUAINT:
|
||||
return write_lua_int_item(f, c->name, c->lua_int_val);
|
||||
#endif
|
||||
case TY_STR:
|
||||
return write_str_item(f, c->name, c->str_val);
|
||||
case TY_TYPE:
|
||||
return write_type(f, c->name, c->str_val);
|
||||
case TY_COMMENT:
|
||||
return write_comment(f, c->str_val);
|
||||
case TY_RAW:
|
||||
return write_raw(f, c->str_val);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int write_items_(FILE *f, const rs_item items[], size_t num) {
|
||||
size_t i;
|
||||
for (i = 0; i < num; i++) {
|
||||
if (!write_item(f, &items[i]))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define write_items(f, cs) write_items_(f, cs, sizeof(cs) / sizeof(cs[0]))
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
if (argc <= 1) {
|
||||
printf("usage: %s <filename>\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const char *filename = argv[1];
|
||||
|
||||
FILE *f = fopen(filename, "w");
|
||||
|
||||
if (!f) {
|
||||
printf("could not open file: errno = %d\n", errno);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const rs_item glue_entries[] = {
|
||||
RS_COMMENT("this file was generated by glue.c; do not modify it by hand"),
|
||||
RS_RAW("use std::os::raw::*;\n"),
|
||||
|
||||
// == luaconf.h ==========================================================
|
||||
|
||||
RS_COMMENT("luaconf.h"),
|
||||
RS_INT("LUA_EXTRASPACE", LUA_EXTRASPACE),
|
||||
RS_INT("LUA_IDSIZE", LUA_IDSIZE),
|
||||
RS_TYPE("LUA_NUMBER",
|
||||
sizeof(LUA_NUMBER) > sizeof(float) ? "c_double" : "c_float"),
|
||||
RS_TYPE("LUA_INTEGER", rs_int_type(sizeof(LUA_INTEGER))),
|
||||
#if LUA_VERSION_NUM >= 502
|
||||
RS_TYPE("LUA_UNSIGNED", rs_uint_type(sizeof(LUA_UNSIGNED))),
|
||||
#else
|
||||
RS_TYPE("LUA_UNSIGNED", rs_uint_type(sizeof(size_t))),
|
||||
#endif
|
||||
|
||||
// == lua.h ==============================================================
|
||||
|
||||
RS_COMMENT("lua.h"),
|
||||
RS_INT("LUA_VERSION_NUM", LUA_VERSION_NUM),
|
||||
RS_INT("LUA_REGISTRYINDEX", LUA_REGISTRYINDEX),
|
||||
#if LUA_VERSION_NUM == 501
|
||||
RS_INT("LUA_ENVIRONINDEX", LUA_ENVIRONINDEX),
|
||||
RS_INT("LUA_GLOBALSINDEX", LUA_GLOBALSINDEX),
|
||||
#endif
|
||||
|
||||
// == lauxlib.h ==========================================================
|
||||
|
||||
RS_COMMENT("lauxlib.h"),
|
||||
#if LUA_VERSION_NUM >= 503
|
||||
RS_INT("LUAL_NUMSIZES", LUAL_NUMSIZES),
|
||||
#endif
|
||||
|
||||
// == lualib.h ===========================================================
|
||||
|
||||
RS_COMMENT("lualib.h"),
|
||||
RS_STR("LUA_COLIBNAME", LUA_COLIBNAME),
|
||||
RS_STR("LUA_TABLIBNAME", LUA_TABLIBNAME),
|
||||
RS_STR("LUA_IOLIBNAME", LUA_IOLIBNAME),
|
||||
RS_STR("LUA_OSLIBNAME", LUA_OSLIBNAME),
|
||||
RS_STR("LUA_STRLIBNAME", LUA_STRLIBNAME),
|
||||
#ifdef LUA_UTF8LIBNAME
|
||||
RS_STR("LUA_UTF8LIBNAME", LUA_UTF8LIBNAME),
|
||||
#endif
|
||||
#ifdef LUA_BITLIBNAME
|
||||
RS_STR("LUA_BITLIBNAME", LUA_BITLIBNAME),
|
||||
#endif
|
||||
RS_STR("LUA_MATHLIBNAME", LUA_MATHLIBNAME),
|
||||
RS_STR("LUA_DBLIBNAME", LUA_DBLIBNAME),
|
||||
RS_STR("LUA_LOADLIBNAME", LUA_LOADLIBNAME),
|
||||
#ifdef LUA_JITLIBNAME
|
||||
RS_STR("LUA_JITLIBNAME", LUA_JITLIBNAME),
|
||||
#endif
|
||||
#ifdef LUA_FFILIBNAME
|
||||
RS_STR("LUA_FFILIBNAME", LUA_FFILIBNAME),
|
||||
#endif
|
||||
};
|
||||
|
||||
if (!write_items(f, glue_entries)) {
|
||||
printf("%s: error generating %s; aborting\n", argv[0], filename);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -1,306 +0,0 @@
|
|||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2019-2021 A. Orlenko
|
||||
// Copyright (c) 2014 J.C. Moyer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
//! Contains definitions from `lauxlib.h`.
|
||||
|
||||
use std::os::raw::{c_char, c_int, c_long, c_void};
|
||||
use std::ptr;
|
||||
|
||||
use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State};
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub use super::glue::LUAL_NUMSIZES;
|
||||
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
pub use super::compat53::{luaL_getmetafield, luaL_newmetatable, luaL_requiref, luaL_tolstring};
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub use super::compat53::{
|
||||
luaL_checkstack, luaL_checkversion, luaL_getsubtable, luaL_len, luaL_loadbufferx,
|
||||
luaL_setfuncs, luaL_setmetatable, luaL_testudata, luaL_traceback,
|
||||
};
|
||||
|
||||
// extra error code for 'luaL_load'
|
||||
pub const LUA_ERRFILE: c_int = lua::LUA_ERRERR + 1;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct luaL_Reg {
|
||||
pub name: *const c_char,
|
||||
pub func: lua_CFunction,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_checkversion(L: *mut lua_State) {
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
luaL_checkversion_(
|
||||
L,
|
||||
lua::LUA_VERSION_NUM as lua_Number,
|
||||
LUAL_NUMSIZES as usize,
|
||||
);
|
||||
#[cfg(feature = "lua52")]
|
||||
luaL_checkversion_(L, lua::LUA_VERSION_NUM as lua_Number);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number, sz: usize);
|
||||
#[cfg(feature = "lua52")]
|
||||
pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number);
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
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"))]
|
||||
#[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_callmeta(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
|
||||
#[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_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_optlstring(
|
||||
L: *mut lua_State,
|
||||
arg: c_int,
|
||||
def: *const c_char,
|
||||
l: *mut usize,
|
||||
) -> *const c_char;
|
||||
pub fn luaL_checknumber(L: *mut lua_State, arg: c_int) -> lua_Number;
|
||||
pub fn luaL_optnumber(L: *mut lua_State, arg: c_int, def: lua_Number) -> lua_Number;
|
||||
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;
|
||||
|
||||
#[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_checktype(L: *mut lua_State, arg: c_int, t: c_int);
|
||||
pub fn luaL_checkany(L: *mut lua_State, arg: c_int);
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int;
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
#[link_name = "luaL_newmetatable"]
|
||||
pub fn luaL_newmetatable_old(L: *mut lua_State, tname: *const c_char) -> c_int;
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char);
|
||||
#[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_checkudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;
|
||||
|
||||
pub fn luaL_where(L: *mut lua_State, lvl: c_int);
|
||||
pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> !;
|
||||
|
||||
// TODO: test this
|
||||
pub fn luaL_checkoption(
|
||||
L: *mut lua_State,
|
||||
arg: c_int,
|
||||
def: *const c_char,
|
||||
lst: *const *const c_char,
|
||||
) -> c_int;
|
||||
|
||||
#[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;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub fn luaL_execresult(L: *mut lua_State, stat: c_int) -> c_int;
|
||||
}
|
||||
|
||||
// pre-defined references
|
||||
pub const LUA_NOREF: c_int = -2;
|
||||
pub const LUA_REFNIL: c_int = -1;
|
||||
|
||||
extern "C" {
|
||||
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);
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub fn luaL_loadfilex(L: *mut lua_State, filename: *const c_char, mode: *const c_char)
|
||||
-> c_int;
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub fn luaL_loadfile(L: *mut lua_State, filename: *const c_char) -> c_int;
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
|
||||
luaL_loadfilex(L, f, ptr::null())
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub fn luaL_loadbufferx(
|
||||
L: *mut lua_State,
|
||||
buff: *const c_char,
|
||||
sz: usize,
|
||||
name: *const c_char,
|
||||
mode: *const c_char,
|
||||
) -> c_int;
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub fn luaL_loadbuffer(
|
||||
L: *mut lua_State,
|
||||
buff: *const c_char,
|
||||
sz: usize,
|
||||
name: *const c_char,
|
||||
) -> c_int;
|
||||
pub fn luaL_loadstring(L: *mut lua_State, s: *const c_char) -> c_int;
|
||||
|
||||
pub fn luaL_newstate() -> *mut lua_State;
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer;
|
||||
|
||||
// TODO (lua54): luaL_addgsub
|
||||
|
||||
pub fn luaL_gsub(
|
||||
L: *mut lua_State,
|
||||
s: *const c_char,
|
||||
p: *const c_char,
|
||||
r: *const c_char,
|
||||
) -> *const c_char;
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub fn luaL_setfuncs(L: *mut lua_State, l: *const luaL_Reg, nup: c_int);
|
||||
|
||||
#[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;
|
||||
|
||||
#[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);
|
||||
|
||||
// Skip Lua 5.2 implementation in favor of the compat53 one
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn luaL_requiref(
|
||||
L: *mut lua_State,
|
||||
modname: *const c_char,
|
||||
openf: lua_CFunction,
|
||||
glb: c_int,
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[allow(unused_variables)]
|
||||
pub unsafe fn luaL_newlibtable(L: *mut lua_State, l: *const luaL_Reg) {
|
||||
// TODO: figure out how to pass an appropriate hint for the second param
|
||||
// this involves correcting the second parameter's type; in C this is
|
||||
// sizeof(l)/sizeof(l[0])
|
||||
lua::lua_createtable(L, 0, 0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_newlib(L: *mut lua_State, l: *const luaL_Reg) {
|
||||
luaL_checkversion(L);
|
||||
luaL_newlibtable(L, l);
|
||||
luaL_setfuncs(L, l, 0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_argcheck(L: *mut lua_State, cond: c_int, arg: c_int, extramsg: *const c_char) {
|
||||
if cond == 0 {
|
||||
luaL_argerror(L, arg, extramsg);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_checkstring(L: *mut lua_State, n: c_int) -> *const c_char {
|
||||
luaL_checklstring(L, n, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_optstring(L: *mut lua_State, n: c_int, d: *const c_char) -> *const c_char {
|
||||
luaL_optlstring(L, n, d, ptr::null_mut())
|
||||
}
|
||||
|
||||
// From 5.3 user manual:
|
||||
// Macros to project non-default integer types (luaL_checkint, luaL_optint,
|
||||
// luaL_checklong, luaL_optlong) were deprecated. Use their equivalent over
|
||||
// lua_Integer with a type cast (or, when possible, use lua_Integer in your
|
||||
// code).
|
||||
#[inline(always)]
|
||||
//#[deprecated]
|
||||
pub unsafe fn luaL_checkint(L: *mut lua_State, n: c_int) -> c_int {
|
||||
luaL_checkinteger(L, n) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
//#[deprecated]
|
||||
pub unsafe fn luaL_optint(L: *mut lua_State, n: c_int, d: c_int) -> c_int {
|
||||
luaL_optinteger(L, n, d as lua_Integer) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
//#[deprecated]
|
||||
pub unsafe fn luaL_checklong(L: *mut lua_State, n: c_int) -> c_long {
|
||||
luaL_checkinteger(L, n) as c_long
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
//#[deprecated]
|
||||
pub unsafe fn luaL_optlong(L: *mut lua_State, n: c_int, d: c_long) -> c_long {
|
||||
luaL_optinteger(L, n, d as lua_Integer) as c_long
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_typename(L: *mut lua_State, i: c_int) -> *const c_char {
|
||||
lua::lua_typename(L, lua::lua_type(L, i))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_dofile(L: *mut lua_State, filename: *const c_char) -> c_int {
|
||||
let status = luaL_loadfile(L, filename);
|
||||
if status == 0 {
|
||||
lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
|
||||
} else {
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_dostring(L: *mut lua_State, s: *const c_char) -> c_int {
|
||||
let status = luaL_loadstring(L, s);
|
||||
if status == 0 {
|
||||
lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
|
||||
} else {
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
|
||||
lua::lua_getfield(L, lua::LUA_REGISTRYINDEX, n);
|
||||
}
|
||||
|
||||
// luaL_opt would be implemented here but it is undocumented, so it's omitted
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_loadbuffer(
|
||||
L: *mut lua_State,
|
||||
s: *const c_char,
|
||||
sz: usize,
|
||||
n: *const c_char,
|
||||
) -> c_int {
|
||||
luaL_loadbufferx(L, s, sz, n, ptr::null())
|
||||
}
|
||||
|
||||
// TODO: Add buffer API
|
||||
|
||||
// omitted: old module system compatibility (removed in 5.4)
|
839
src/ffi/lua.rs
839
src/ffi/lua.rs
|
@ -1,839 +0,0 @@
|
|||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2019-2021 A. Orlenko
|
||||
// Copyright (c) 2014 J.C. Moyer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
//! Contains definitions from `lua.h`.
|
||||
|
||||
use std::marker::{PhantomData, PhantomPinned};
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
use std::os::raw::c_uchar;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
#[cfg(feature = "lua54")]
|
||||
use std::os::raw::{c_uint, c_ushort};
|
||||
use std::ptr;
|
||||
|
||||
use super::luaconf;
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub use super::glue::{LUA_ENVIRONINDEX, LUA_GLOBALSINDEX};
|
||||
pub use super::glue::{LUA_REGISTRYINDEX, LUA_VERSION_NUM};
|
||||
|
||||
#[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'
|
||||
pub const LUA_MULTRET: c_int = -1;
|
||||
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
pub use super::compat53::{
|
||||
lua_dump, lua_getextraspace, lua_getfield, lua_geti, lua_gettable, lua_getuservalue,
|
||||
lua_isinteger, lua_pushlstring, lua_rawget, lua_rawgeti, lua_rawgetp, lua_rotate, lua_seti,
|
||||
lua_stringtonumber, lua_tointegerx,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub use super::compat53::{
|
||||
lua_absindex, lua_arith, lua_compare, lua_copy, lua_len, lua_pushglobaltable, lua_pushstring,
|
||||
lua_rawlen, lua_rawsetp, lua_resume as lua_resume_53, lua_setuservalue, lua_tonumberx,
|
||||
lua_upvalueindex,
|
||||
};
|
||||
|
||||
#[cfg(feature = "lua52")]
|
||||
pub use super::compat53::lua_getglobal;
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[inline(always)]
|
||||
pub const fn lua_upvalueindex(i: c_int) -> c_int {
|
||||
LUA_REGISTRYINDEX - i
|
||||
}
|
||||
|
||||
// thread status
|
||||
pub const LUA_OK: c_int = 0;
|
||||
pub const LUA_YIELD: c_int = 1;
|
||||
pub const LUA_ERRRUN: c_int = 2;
|
||||
pub const LUA_ERRSYNTAX: c_int = 3;
|
||||
pub const LUA_ERRMEM: c_int = 4;
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
pub const LUA_ERRGCMM: c_int = 5;
|
||||
#[cfg(any(feature = "lua54", feature = "lua51", feature = "luajit"))]
|
||||
pub const LUA_ERRERR: c_int = 5;
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
pub const LUA_ERRERR: c_int = 6;
|
||||
|
||||
/// A raw Lua state associated with a thread.
|
||||
#[repr(C)]
|
||||
pub struct lua_State {
|
||||
_data: [u8; 0],
|
||||
_marker: PhantomData<(*mut u8, PhantomPinned)>,
|
||||
}
|
||||
|
||||
// basic types
|
||||
pub const LUA_TNONE: c_int = -1;
|
||||
|
||||
pub const LUA_TNIL: c_int = 0;
|
||||
pub const LUA_TBOOLEAN: c_int = 1;
|
||||
pub const LUA_TLIGHTUSERDATA: c_int = 2;
|
||||
pub const LUA_TNUMBER: c_int = 3;
|
||||
pub const LUA_TSTRING: c_int = 4;
|
||||
pub const LUA_TTABLE: c_int = 5;
|
||||
pub const LUA_TFUNCTION: c_int = 6;
|
||||
pub const LUA_TUSERDATA: c_int = 7;
|
||||
pub const LUA_TTHREAD: c_int = 8;
|
||||
|
||||
// Type produced by LuaJIT FFI module
|
||||
#[cfg(feature = "luajit")]
|
||||
pub const LUA_TCDATA: c_int = 10;
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
pub const LUA_NUMTYPES: c_int = 9;
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
pub const LUA_NUMTAGS: c_int = 9;
|
||||
|
||||
// minimum stack available to a C function
|
||||
pub const LUA_MINSTACK: c_int = 20;
|
||||
|
||||
// predefined values in the registry
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub const LUA_RIDX_MAINTHREAD: lua_Integer = 1;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub const LUA_RIDX_GLOBALS: lua_Integer = 2;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub const LUA_RIDX_LAST: lua_Integer = LUA_RIDX_GLOBALS;
|
||||
|
||||
// I believe `luaL_traceback` < 5.4 requires this much free stack to not error.
|
||||
// 5.4 uses `luaL_Buffer`
|
||||
pub const LUA_TRACEBACK_STACK: c_int = 11;
|
||||
|
||||
/// A Lua number, usually equivalent to `f64`.
|
||||
pub type lua_Number = luaconf::LUA_NUMBER;
|
||||
|
||||
/// A Lua integer, usually equivalent to `i64`.
|
||||
pub type lua_Integer = luaconf::LUA_INTEGER;
|
||||
|
||||
/// A Lua unsigned integer, usually equivalent to `u64`.
|
||||
pub type lua_Unsigned = luaconf::LUA_UNSIGNED;
|
||||
|
||||
// type for continuation-function contexts
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub type lua_KContext = luaconf::LUA_KCONTEXT;
|
||||
|
||||
/// Type for native C functions that can be passed to Lua.
|
||||
pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int;
|
||||
|
||||
// Type for continuation functions
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub type lua_KFunction =
|
||||
unsafe extern "C" fn(L: *mut lua_State, status: c_int, ctx: lua_KContext) -> c_int;
|
||||
|
||||
// Type for functions that read/write blocks when loading/dumping Lua chunks
|
||||
pub type lua_Reader =
|
||||
unsafe extern "C" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char;
|
||||
pub type lua_Writer =
|
||||
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.
|
||||
pub type lua_Alloc = unsafe extern "C" fn(
|
||||
ud: *mut c_void,
|
||||
ptr: *mut c_void,
|
||||
osize: usize,
|
||||
nsize: usize,
|
||||
) -> *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" {
|
||||
// state manipulation
|
||||
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_newthread(L: *mut lua_State) -> *mut lua_State;
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
#[link_name = "lua_resetthread"]
|
||||
pub fn lua_resetthread_54(L: *mut lua_State) -> c_int;
|
||||
#[cfg(all(feature = "luajit", feature = "vendored"))]
|
||||
#[link_name = "lua_resetthread"]
|
||||
pub fn lua_resetthread_jit(L: *mut lua_State, th: *mut lua_State);
|
||||
|
||||
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")]
|
||||
pub fn lua_version(L: *mut lua_State) -> *const lua_Number;
|
||||
|
||||
// basic stack manipulation
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
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_settop(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_pushvalue(L: *mut lua_State, idx: c_int);
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
pub fn lua_remove(L: *mut lua_State, idx: c_int);
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
pub fn lua_insert(L: *mut lua_State, idx: c_int);
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
pub fn lua_replace(L: *mut lua_State, idx: c_int);
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn lua_rotate(L: *mut lua_State, idx: c_int, n: c_int);
|
||||
#[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_checkstack(L: *mut lua_State, sz: c_int) -> c_int;
|
||||
|
||||
pub fn lua_xmove(from: *mut lua_State, to: *mut lua_State, n: c_int);
|
||||
|
||||
// access functions (stack -> C)
|
||||
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_iscfunction(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
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_type(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_typename(L: *mut lua_State, tp: c_int) -> *const c_char;
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub fn lua_tonumber(L: *mut lua_State, idx: c_int) -> lua_Number;
|
||||
#[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;
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub fn lua_tointeger(L: *mut lua_State, idx: c_int) -> lua_Integer;
|
||||
#[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_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;
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub fn lua_objlen(L: *mut lua_State, idx: c_int) -> usize;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
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_touserdata(L: *mut lua_State, idx: c_int) -> *mut c_void;
|
||||
pub fn lua_tothread(L: *mut lua_State, idx: c_int) -> *mut lua_State;
|
||||
pub fn lua_topointer(L: *mut lua_State, idx: c_int) -> *const c_void;
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored")))]
|
||||
pub unsafe fn lua_resetthread(_L: *mut lua_State, th: *mut lua_State) -> c_int {
|
||||
#[cfg(all(feature = "luajit", feature = "vendored"))]
|
||||
{
|
||||
lua_resetthread_jit(_L, th);
|
||||
LUA_OK
|
||||
}
|
||||
#[cfg(feature = "lua54")]
|
||||
lua_resetthread_54(th)
|
||||
}
|
||||
|
||||
// Comparison and arithmetic functions
|
||||
pub const LUA_OPADD: c_int = 0;
|
||||
pub const LUA_OPSUB: c_int = 1;
|
||||
pub const LUA_OPMUL: c_int = 2;
|
||||
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
pub const LUA_OPDIV: c_int = 3;
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
pub const LUA_OPMOD: c_int = 4;
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
pub const LUA_OPPOW: c_int = 5;
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
pub const LUA_OPUNM: c_int = 6;
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub const LUA_OPMOD: c_int = 3;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub const LUA_OPPOW: c_int = 4;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub const LUA_OPDIV: c_int = 5;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub const LUA_OPIDIV: c_int = 6;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub const LUA_OPBAND: c_int = 7;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub const LUA_OPBOR: c_int = 8;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub const LUA_OPBXOR: c_int = 9;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub const LUA_OPSHL: c_int = 10;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub const LUA_OPSHR: c_int = 11;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub const LUA_OPUNM: c_int = 12;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub const LUA_OPBNOT: c_int = 13;
|
||||
|
||||
extern "C" {
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub fn lua_arith(L: *mut lua_State, op: c_int);
|
||||
}
|
||||
|
||||
pub const LUA_OPEQ: c_int = 0;
|
||||
pub const LUA_OPLT: c_int = 1;
|
||||
pub const LUA_OPLE: c_int = 2;
|
||||
|
||||
extern "C" {
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub fn lua_equal(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"))]
|
||||
pub fn lua_lessthan(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
||||
#[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;
|
||||
}
|
||||
|
||||
// push functions (C -> stack)
|
||||
extern "C" {
|
||||
pub fn lua_pushnil(L: *mut lua_State);
|
||||
pub fn lua_pushnumber(L: *mut lua_State, n: lua_Number);
|
||||
pub fn lua_pushinteger(L: *mut lua_State, n: lua_Integer);
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
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"))]
|
||||
#[link_name = "lua_pushlstring"]
|
||||
pub fn lua_pushlstring_old(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char;
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char;
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[link_name = "lua_pushstring"]
|
||||
pub fn lua_pushstring_old(L: *mut lua_State, s: *const c_char) -> *const c_char;
|
||||
|
||||
// TODO: omitted:
|
||||
// lua_pushvfstring
|
||||
pub fn lua_pushfstring(L: *mut lua_State, fmt: *const c_char, ...) -> *const c_char;
|
||||
pub fn lua_pushcclosure(L: *mut lua_State, f: lua_CFunction, n: c_int);
|
||||
pub fn lua_pushboolean(L: *mut lua_State, b: c_int);
|
||||
pub fn lua_pushlightuserdata(L: *mut lua_State, p: *mut c_void);
|
||||
pub fn lua_pushthread(L: *mut lua_State) -> c_int;
|
||||
}
|
||||
|
||||
// get functions (Lua -> stack)
|
||||
extern "C" {
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int;
|
||||
#[cfg(feature = "lua52")]
|
||||
#[link_name = "lua_getglobal"]
|
||||
pub fn lua_getglobal_old(L: *mut lua_State, var: *const c_char);
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
#[link_name = "lua_gettable"]
|
||||
pub fn lua_gettable_old(L: *mut lua_State, idx: c_int);
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
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"))]
|
||||
#[link_name = "lua_getfield"]
|
||||
pub fn lua_getfield_old(L: *mut lua_State, idx: c_int, k: *const c_char);
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn lua_geti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int;
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
#[link_name = "lua_rawget"]
|
||||
pub fn lua_rawget_old(L: *mut lua_State, idx: c_int);
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int;
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
#[link_name = "lua_rawgeti"]
|
||||
pub fn lua_rawgeti_old(L: *mut lua_State, idx: c_int, n: lua_Integer);
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int;
|
||||
#[cfg(feature = "lua52")]
|
||||
#[link_name = "lua_rawgetp"]
|
||||
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);
|
||||
#[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_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")]
|
||||
pub fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
#[cfg(feature = "lua52")]
|
||||
#[link_name = "lua_getuservalue"]
|
||||
pub fn lua_getuservalue_old(L: *mut lua_State, idx: c_int);
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
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)
|
||||
extern "C" {
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
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_setfield(L: *mut lua_State, idx: c_int, k: *const c_char);
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
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_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer);
|
||||
#[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_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"))]
|
||||
pub fn lua_setuservalue(L: *mut lua_State, idx: c_int);
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
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)
|
||||
extern "C" {
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn lua_callk(
|
||||
L: *mut lua_State,
|
||||
nargs: c_int,
|
||||
nresults: c_int,
|
||||
ctx: lua_KContext,
|
||||
k: Option<lua_KFunction>,
|
||||
);
|
||||
#[cfg(feature = "lua52")]
|
||||
pub fn lua_callk(
|
||||
L: *mut lua_State,
|
||||
nargs: c_int,
|
||||
nresults: c_int,
|
||||
ctx: c_int,
|
||||
k: Option<lua_CFunction>,
|
||||
);
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn lua_pcallk(
|
||||
L: *mut lua_State,
|
||||
nargs: c_int,
|
||||
nresults: c_int,
|
||||
errfunc: c_int,
|
||||
ctx: lua_KContext,
|
||||
k: Option<lua_KFunction>,
|
||||
) -> c_int;
|
||||
#[cfg(feature = "lua52")]
|
||||
pub fn lua_pcallk(
|
||||
L: *mut lua_State,
|
||||
nargs: c_int,
|
||||
nresults: c_int,
|
||||
errfunc: c_int,
|
||||
ctx: c_int,
|
||||
k: Option<lua_CFunction>,
|
||||
) -> c_int;
|
||||
|
||||
#[cfg(feature = "lua52")]
|
||||
pub fn lua_getctx(L: *mut lua_State, ctx: *mut c_int) -> c_int;
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub fn lua_call(L: *mut lua_State, nargs: c_int, nresults: c_int);
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub fn lua_pcall(L: *mut lua_State, nargs: c_int, nresults: c_int, errfunc: c_int) -> c_int;
|
||||
|
||||
// TODO
|
||||
pub fn lua_load(
|
||||
L: *mut lua_State,
|
||||
reader: lua_Reader,
|
||||
dt: *mut c_void,
|
||||
chunkname: *const c_char,
|
||||
mode: *const c_char,
|
||||
) -> c_int;
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn lua_dump(
|
||||
L: *mut lua_State,
|
||||
writer: lua_Writer,
|
||||
data: *mut c_void,
|
||||
strip: c_int,
|
||||
) -> c_int;
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
#[link_name = "lua_dump"]
|
||||
pub fn lua_dump_old(L: *mut lua_State, writer: lua_Writer, data: *mut c_void) -> c_int;
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_call(L: *mut lua_State, n: c_int, r: c_int) {
|
||||
lua_callk(L, n, r, 0, None)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[inline(always)]
|
||||
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)
|
||||
}
|
||||
|
||||
// coroutine functions
|
||||
extern "C" {
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn lua_yieldk(
|
||||
L: *mut lua_State,
|
||||
nresults: c_int,
|
||||
ctx: lua_KContext,
|
||||
k: Option<lua_KFunction>,
|
||||
) -> c_int;
|
||||
#[cfg(feature = "lua52")]
|
||||
pub fn lua_yieldk(
|
||||
L: *mut lua_State,
|
||||
nresults: c_int,
|
||||
ctx: c_int,
|
||||
k: Option<lua_CFunction>,
|
||||
) -> c_int;
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
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"))]
|
||||
#[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"))]
|
||||
#[link_name = "lua_resume"]
|
||||
pub fn lua_resume_old(L: *mut lua_State, narg: c_int) -> c_int;
|
||||
|
||||
pub fn lua_status(L: *mut lua_State) -> c_int;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn lua_isyieldable(L: *mut lua_State) -> c_int;
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_yield(L: *mut lua_State, n: c_int) -> c_int {
|
||||
lua_yieldk(L, n, 0, None)
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "lua51",
|
||||
feature = "luajit"
|
||||
))]
|
||||
#[inline(always)]
|
||||
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: Option<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
|
||||
pub const LUA_GCSTOP: c_int = 0;
|
||||
pub const LUA_GCRESTART: c_int = 1;
|
||||
pub const LUA_GCCOLLECT: c_int = 2;
|
||||
pub const LUA_GCCOUNT: c_int = 3;
|
||||
pub const LUA_GCCOUNTB: c_int = 4;
|
||||
pub const LUA_GCSTEP: c_int = 5;
|
||||
pub const LUA_GCSETPAUSE: c_int = 6;
|
||||
pub const LUA_GCSETSTEPMUL: c_int = 7;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
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" {
|
||||
#[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;
|
||||
}
|
||||
|
||||
// miscellaneous functions
|
||||
extern "C" {
|
||||
pub fn lua_error(L: *mut lua_State) -> !;
|
||||
pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_concat(L: *mut lua_State, n: c_int);
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub fn lua_len(L: *mut lua_State, idx: c_int);
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
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_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
|
||||
// here, implemented as Rust functions
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
|
||||
(L as *mut c_char).offset(-super::glue::LUA_EXTRASPACE as isize) as *mut c_void
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number {
|
||||
lua_tonumberx(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
|
||||
lua_tointegerx(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pop(L: *mut lua_State, n: c_int) {
|
||||
lua_settop(L, -n - 1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_newtable(L: *mut lua_State) {
|
||||
lua_createtable(L, 0, 0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_register(L: *mut lua_State, n: *const c_char, f: lua_CFunction) {
|
||||
lua_pushcfunction(L, f);
|
||||
lua_setglobal(L, n)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) {
|
||||
lua_pushcclosure(L, f, 0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isfunction(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TFUNCTION) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_istable(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TTABLE) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_islightuserdata(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TLIGHTUSERDATA) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TNIL) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isboolean(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TBOOLEAN) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isthread(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TTHREAD) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnone(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TNONE) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnoneornil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) <= 0) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) -> *const c_char {
|
||||
use std::ffi::CString;
|
||||
let c_str = CString::new(s).unwrap();
|
||||
lua_pushlstring(L, c_str.as_ptr(), c_str.as_bytes().len())
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_setglobal(L: *mut lua_State, var: *const c_char) {
|
||||
lua_setfield(L, LUA_GLOBALSINDEX, var)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int {
|
||||
lua_getfield(L, LUA_GLOBALSINDEX, var)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushglobaltable(L: *mut lua_State) -> c_int {
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char {
|
||||
lua_tolstring(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_insert(L: *mut lua_State, idx: c_int) {
|
||||
lua_rotate(L, idx, 1)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_remove(L: *mut lua_State, idx: c_int) {
|
||||
lua_rotate(L, idx, -1);
|
||||
lua_pop(L, 1)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_replace(L: *mut lua_State, idx: c_int) {
|
||||
lua_copy(L, -1, idx);
|
||||
lua_pop(L, 1)
|
||||
}
|
||||
|
||||
// Debug API
|
||||
// Event codes
|
||||
pub const LUA_HOOKCALL: c_int = 0;
|
||||
pub const LUA_HOOKRET: c_int = 1;
|
||||
pub const LUA_HOOKLINE: c_int = 2;
|
||||
pub const LUA_HOOKCOUNT: c_int = 3;
|
||||
pub const LUA_HOOKTAILCALL: c_int = 4;
|
||||
|
||||
// Event masks
|
||||
pub const LUA_MASKCALL: c_int = 1 << (LUA_HOOKCALL as usize);
|
||||
pub const LUA_MASKRET: c_int = 1 << (LUA_HOOKRET as usize);
|
||||
pub const LUA_MASKLINE: c_int = 1 << (LUA_HOOKLINE as usize);
|
||||
pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
|
||||
|
||||
/// Type for functions to be called on debug events.
|
||||
pub type lua_Hook = unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug);
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_getstack(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getinfo(L: *mut lua_State, what: *const c_char, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getlocal(L: *mut lua_State, ar: *const lua_Debug, n: c_int) -> *const c_char;
|
||||
pub fn lua_setlocal(L: *mut lua_State, ar: *const lua_Debug, 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;
|
||||
|
||||
#[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;
|
||||
#[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_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_gethookmask(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 = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[repr(C)]
|
||||
pub struct lua_Debug {
|
||||
pub event: c_int,
|
||||
pub name: *const c_char,
|
||||
pub namewhat: *const c_char,
|
||||
pub what: *const c_char,
|
||||
pub source: *const c_char,
|
||||
#[cfg(feature = "lua54")]
|
||||
pub srclen: usize,
|
||||
pub currentline: c_int,
|
||||
pub linedefined: c_int,
|
||||
pub lastlinedefined: c_int,
|
||||
pub nups: c_uchar,
|
||||
pub nparams: c_uchar,
|
||||
pub isvararg: 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],
|
||||
// lua.h mentions this is for private use
|
||||
i_ci: *mut c_void,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[repr(C)]
|
||||
pub struct lua_Debug {
|
||||
pub event: c_int,
|
||||
pub name: *const c_char,
|
||||
pub namewhat: *const c_char,
|
||||
pub what: *const c_char,
|
||||
pub source: *const c_char,
|
||||
pub currentline: c_int,
|
||||
pub nups: c_int,
|
||||
pub linedefined: c_int,
|
||||
pub lastlinedefined: c_int,
|
||||
pub short_src: [c_char; luaconf::LUA_IDSIZE as usize],
|
||||
// lua.h mentions this is for private use
|
||||
i_ci: c_int,
|
||||
}
|
|
@ -1,69 +1,16 @@
|
|||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2019-2021 A. Orlenko
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//! MLua compatibility layer for Lua 5.1/JIT
|
||||
//!
|
||||
//! 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::convert::TryInto;
|
||||
use std::mem;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::ptr;
|
||||
|
||||
use super::lauxlib::{
|
||||
luaL_callmeta, luaL_error, luaL_getmetafield_old, luaL_loadbuffer, luaL_newmetatable_old,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
use super::lauxlib::{luaL_Reg, luaL_checktype, luaL_getmetatable};
|
||||
|
||||
#[cfg(feature = "lua52")]
|
||||
use super::lauxlib::{luaL_checkstack, luaL_getsubtable};
|
||||
|
||||
use super::lua::{
|
||||
self, lua_CFunction, lua_Debug, lua_Integer, lua_Number, lua_State, lua_Writer, lua_call,
|
||||
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_pushcfunction, lua_pushfstring, lua_pushinteger, lua_pushliteral, lua_pushlstring_old,
|
||||
lua_pushnil, lua_pushnumber, lua_pushthread, lua_pushvalue, lua_rawget_old, lua_rawgeti_old,
|
||||
lua_rawset, lua_replace, lua_setfield, lua_setglobal, lua_setmetatable, lua_settable,
|
||||
lua_toboolean, lua_tointeger, lua_tolstring, lua_tonumber, lua_topointer, lua_tostring,
|
||||
lua_touserdata, lua_type, lua_typename,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
use super::lua::{
|
||||
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_pushlightuserdata, lua_pushstring_old, lua_rawequal, lua_remove, lua_resume_old,
|
||||
lua_setfenv, lua_settop, LUA_OPADD, LUA_OPUNM,
|
||||
};
|
||||
|
||||
#[cfg(feature = "lua52")]
|
||||
use super::lua::{
|
||||
lua_absindex, lua_getglobal_old, lua_getuservalue_old, lua_pushstring, lua_rawgetp_old,
|
||||
lua_rawsetp, lua_tonumberx,
|
||||
};
|
||||
use super::lauxlib::*;
|
||||
use super::lua::*;
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
|
||||
while a < b {
|
||||
lua_pushvalue(L, a);
|
||||
|
@ -125,10 +72,9 @@ unsafe fn compat53_checkmode(
|
|||
);
|
||||
return err;
|
||||
}
|
||||
lua::LUA_OK
|
||||
LUA_OK
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) -> c_int {
|
||||
if level == 0 || lua_istable(L, -1) == 0 {
|
||||
return 0; // not found
|
||||
|
@ -137,7 +83,7 @@ unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) ->
|
|||
lua_pushnil(L); // start 'next' loop
|
||||
while lua_next(L, -2) != 0 {
|
||||
// for each pair in table
|
||||
if lua_type(L, -2) == lua::LUA_TSTRING {
|
||||
if lua_type(L, -2) == LUA_TSTRING {
|
||||
// ignore non-string keys
|
||||
if lua_rawequal(L, objidx, -1) != 0 {
|
||||
// found object?
|
||||
|
@ -154,25 +100,23 @@ unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) ->
|
|||
}
|
||||
lua_pop(L, 1); // remove value
|
||||
}
|
||||
return 0; // not found
|
||||
0 // not found
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
unsafe fn compat53_pushglobalfuncname(L: *mut lua_State, ar: *mut lua_Debug) -> c_int {
|
||||
let top = lua_gettop(L);
|
||||
lua_getinfo(L, cstr!("f"), ar); // push function
|
||||
lua_pushvalue(L, lua::LUA_GLOBALSINDEX);
|
||||
lua_pushvalue(L, LUA_GLOBALSINDEX);
|
||||
if compat53_findfield(L, top + 1, 2) != 0 {
|
||||
lua_copy(L, -1, top + 1); // move name to proper place
|
||||
lua_pop(L, 2); // remove pushed values
|
||||
return 1;
|
||||
1
|
||||
} else {
|
||||
lua_settop(L, top); // remove function and global table
|
||||
return 0;
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
unsafe fn compat53_pushfuncname(L: *mut lua_State, ar: *mut lua_Debug) {
|
||||
if *(*ar).namewhat != b'\0' as c_char {
|
||||
// is there a name?
|
||||
|
@ -197,75 +141,27 @@ unsafe fn compat53_pushfuncname(L: *mut lua_State, ar: *mut lua_Debug) {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn compat53_call_lua(L: *mut lua_State, code: &str, nargs: c_int, nret: c_int) {
|
||||
lua_rawgetp(L, lua::LUA_REGISTRYINDEX, code.as_ptr() as *const c_void);
|
||||
if lua_type(L, -1) != lua::LUA_TFUNCTION {
|
||||
lua_pop(L, 1);
|
||||
if luaL_loadbuffer(
|
||||
L,
|
||||
code.as_ptr() as *const c_char,
|
||||
code.as_bytes().len(),
|
||||
cstr!("=none"),
|
||||
) != 0
|
||||
{
|
||||
lua_error(L);
|
||||
}
|
||||
lua_pushvalue(L, -1);
|
||||
lua_rawsetp(L, lua::LUA_REGISTRYINDEX, code.as_ptr() as *const c_void);
|
||||
}
|
||||
lua_insert(L, -nargs - 1);
|
||||
lua_call(L, nargs, nret);
|
||||
}
|
||||
|
||||
//
|
||||
// lua ported functions
|
||||
//
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub fn lua_upvalueindex(i: c_int) -> c_int {
|
||||
lua::LUA_GLOBALSINDEX - i
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_absindex(L: *mut lua_State, mut idx: c_int) -> c_int {
|
||||
if idx < 0 && idx > lua::LUA_REGISTRYINDEX {
|
||||
if idx < 0 && idx > LUA_REGISTRYINDEX {
|
||||
idx += lua_gettop(L) + 1;
|
||||
}
|
||||
idx
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
static COMPAT53_ARITH_CODE: &str = r#"
|
||||
local op,a,b=...
|
||||
if op == 0 then return a+b
|
||||
elseif op == 1 then return a-b
|
||||
elseif op == 2 then return a*b
|
||||
elseif op == 3 then return a/b
|
||||
elseif op == 4 then return a%b
|
||||
elseif op == 5 then return a^b
|
||||
elseif op == 6 then return -a
|
||||
end
|
||||
"#;
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub unsafe fn lua_arith(L: *mut lua_State, op: c_int) {
|
||||
#[allow(clippy::manual_range_contains)]
|
||||
if op < LUA_OPADD || op > LUA_OPUNM {
|
||||
luaL_error(L, cstr!("invalid 'op' argument for lua_arith"));
|
||||
}
|
||||
luaL_checkstack(L, 5, cstr!("not enough stack slots"));
|
||||
if op == LUA_OPUNM {
|
||||
lua_pushvalue(L, -1);
|
||||
}
|
||||
lua_pushnumber(L, op as lua_Number);
|
||||
lua_insert(L, -3);
|
||||
compat53_call_lua(L, COMPAT53_ARITH_CODE, 3, 1);
|
||||
}
|
||||
|
||||
pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
|
||||
idx = lua_absindex(L, idx);
|
||||
if n > 0 {
|
||||
// Faster version
|
||||
for _ in 0..n {
|
||||
lua_insert(L, idx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let n_elems = lua_gettop(L) - idx + 1;
|
||||
if n < 0 {
|
||||
n += n_elems;
|
||||
|
@ -279,7 +175,6 @@ pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int) {
|
||||
let abs_to = lua_absindex(L, toidx);
|
||||
|
@ -290,32 +185,30 @@ pub unsafe fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int) {
|
|||
|
||||
#[inline(always)]
|
||||
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_TNUMBER {
|
||||
let n = lua_tonumber(L, idx);
|
||||
let i = lua_tointeger(L, idx);
|
||||
if (n - i as lua_Number).abs() < lua_Number::EPSILON {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
|
||||
lua_tointegerx(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tonumberx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Number {
|
||||
let n = lua_tonumber(L, i);
|
||||
if !isnum.is_null() {
|
||||
*isnum = if n != 0.0 || lua_isnumber(L, i) != 0 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
*isnum = (n != 0.0 || lua_isnumber(L, i) != 0) as c_int;
|
||||
}
|
||||
return n;
|
||||
n
|
||||
}
|
||||
|
||||
// Implemented for Lua 5.2 as well
|
||||
// See https://github.com/keplerproject/lua-compat-5.3/issues/40
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
|
||||
let mut ok = 0;
|
||||
|
@ -330,80 +223,45 @@ pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) ->
|
|||
if !isnum.is_null() {
|
||||
*isnum = 0;
|
||||
}
|
||||
return 0;
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize {
|
||||
lua_objlen(L, idx)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_compare(L: *mut lua_State, mut idx1: c_int, mut idx2: c_int, op: c_int) -> c_int {
|
||||
match op {
|
||||
lua::LUA_OPEQ => lua_equal(L, idx1, idx2),
|
||||
lua::LUA_OPLT => lua_lessthan(L, idx1, idx2),
|
||||
lua::LUA_OPLE => {
|
||||
luaL_checkstack(L, 5, cstr!("not enough stack slots"));
|
||||
idx1 = lua_absindex(L, idx1);
|
||||
idx2 = lua_absindex(L, idx2);
|
||||
lua_pushvalue(L, idx1);
|
||||
lua_pushvalue(L, idx2);
|
||||
compat53_call_lua(L, "local a,b=...\nreturn a<=b\n", 2, 1);
|
||||
let result = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
result
|
||||
}
|
||||
_ => luaL_error(L, cstr!("invalid 'op' argument for lua_compare")),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
|
||||
if l == 0 {
|
||||
lua_pushlstring_old(L, cstr!(""), 0);
|
||||
lua_pushlstring_(L, cstr!(""), 0);
|
||||
} else {
|
||||
lua_pushlstring_old(L, s, l);
|
||||
lua_pushlstring_(L, s, l);
|
||||
}
|
||||
lua_tostring(L, -1)
|
||||
}
|
||||
|
||||
#[cfg(feature = "lua52")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
|
||||
if l == 0 {
|
||||
lua_pushlstring_old(L, cstr!(""), 0)
|
||||
} else {
|
||||
lua_pushlstring_old(L, s, l)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char {
|
||||
lua_pushstring_old(L, s);
|
||||
lua_pushstring_(L, s);
|
||||
lua_tostring(L, -1)
|
||||
}
|
||||
|
||||
#[cfg(feature = "lua52")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int {
|
||||
lua_getglobal_old(L, var);
|
||||
lua_getglobal_(L, var);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int {
|
||||
lua_gettable_old(L, idx);
|
||||
lua_gettable_(L, idx);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int {
|
||||
lua_getfield_old(L, idx, k);
|
||||
lua_getfield_(L, idx, k);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
|
@ -411,54 +269,35 @@ pub unsafe fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c
|
|||
pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_int {
|
||||
idx = lua_absindex(L, idx);
|
||||
lua_pushinteger(L, n);
|
||||
lua_gettable(L, idx);
|
||||
lua_type(L, -1)
|
||||
lua_gettable(L, idx)
|
||||
}
|
||||
|
||||
// A new version which returns c_int
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int {
|
||||
lua_rawget_old(L, idx);
|
||||
lua_rawget_(L, idx);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
// A new version which returns c_int
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
|
||||
lua_rawgeti_old(L, idx, n);
|
||||
let n = n.try_into().expect("cannot convert index to lua_Integer");
|
||||
lua_rawgeti_(L, idx, n);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int {
|
||||
let abs_i = lua_absindex(L, idx);
|
||||
lua_pushlightuserdata(L, p as *mut c_void);
|
||||
lua_rawget(L, abs_i);
|
||||
lua_type(L, -1)
|
||||
lua_rawget(L, abs_i)
|
||||
}
|
||||
|
||||
#[cfg(feature = "lua52")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int {
|
||||
lua_rawgetp_old(L, idx, p);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
|
||||
lua_getfenv(L, idx);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
#[cfg(feature = "lua52")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
|
||||
lua_getuservalue_old(L, idx);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
|
||||
luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
|
||||
|
@ -468,7 +307,12 @@ pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
|
|||
lua_settable(L, idx);
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) {
|
||||
let n = n.try_into().expect("cannot convert index from lua_Integer");
|
||||
lua_rawseti_(L, idx, n)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) {
|
||||
let abs_i = lua_absindex(L, idx);
|
||||
|
@ -478,10 +322,9 @@ pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) {
|
|||
lua_rawset(L, abs_i);
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_setuservalue(L: *mut lua_State, idx: c_int) {
|
||||
luaL_checktype(L, -1, lua::LUA_TTABLE);
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
lua_setfenv(L, idx);
|
||||
}
|
||||
|
||||
|
@ -492,28 +335,21 @@ pub unsafe fn lua_dump(
|
|||
data: *mut c_void,
|
||||
_strip: c_int,
|
||||
) -> c_int {
|
||||
lua_dump_old(L, writer, data)
|
||||
lua_dump_(L, writer, data)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_resume(L: *mut lua_State, _from: *mut lua_State, narg: c_int) -> c_int {
|
||||
lua_resume_old(L, narg)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) {
|
||||
match lua_type(L, idx) {
|
||||
lua::LUA_TSTRING => {
|
||||
LUA_TSTRING => {
|
||||
lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
|
||||
}
|
||||
lua::LUA_TTABLE => {
|
||||
LUA_TTABLE => {
|
||||
if luaL_callmeta(L, idx, cstr!("__len")) == 0 {
|
||||
lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
|
||||
}
|
||||
}
|
||||
lua::LUA_TUSERDATA if luaL_callmeta(L, idx, cstr!("__len")) != 0 => {}
|
||||
LUA_TUSERDATA if luaL_callmeta(L, idx, cstr!("__len")) != 0 => {}
|
||||
_ => {
|
||||
luaL_error(
|
||||
L,
|
||||
|
@ -524,88 +360,32 @@ pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_stringtonumber(L: *mut lua_State, s: *const c_char) -> usize {
|
||||
use std::str::FromStr;
|
||||
|
||||
let cs = CStr::from_ptr(s);
|
||||
if let Ok(rs) = cs.to_str() {
|
||||
if let Ok(n) = f64::from_str(rs.trim()) {
|
||||
lua_pushnumber(L, n as lua_Number);
|
||||
return cs.to_bytes_with_nul().len();
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[allow(clippy::branches_sharing_code)]
|
||||
pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
|
||||
use super::glue::LUA_EXTRASPACE;
|
||||
|
||||
luaL_checkstack(L, 4, cstr!("not enough stack slots available"));
|
||||
lua_pushliteral(L, "__compat53_extraspace");
|
||||
lua_pushvalue(L, -1);
|
||||
lua_rawget(L, lua::LUA_REGISTRYINDEX);
|
||||
if lua_istable(L, -1) == 0 {
|
||||
lua_pop(L, 1);
|
||||
lua_createtable(L, 0, 2);
|
||||
lua_createtable(L, 0, 1);
|
||||
lua_pushliteral(L, "k");
|
||||
lua_setfield(L, -2, cstr!("__mode"));
|
||||
lua_setmetatable(L, -2);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_rawset(L, lua::LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_replace(L, -2);
|
||||
let is_main = lua_pushthread(L);
|
||||
lua_rawget(L, -2);
|
||||
let mut _ptr = lua_touserdata(L, -1);
|
||||
if _ptr.is_null() {
|
||||
lua_pop(L, 1);
|
||||
_ptr = lua_newuserdata(L, LUA_EXTRASPACE as usize);
|
||||
if is_main != 0 {
|
||||
// mem::size_of::<c_void>() == 1
|
||||
ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE as usize);
|
||||
lua_pushthread(L);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_rawset(L, -4);
|
||||
lua_pushboolean(L, 1);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_rawset(L, -4);
|
||||
} else {
|
||||
lua_pushboolean(L, 1);
|
||||
lua_rawget(L, -3);
|
||||
let mptr = lua_touserdata(L, -1);
|
||||
if !mptr.is_null() {
|
||||
ptr::copy_nonoverlapping(mptr, _ptr, LUA_EXTRASPACE as usize)
|
||||
} else {
|
||||
ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE as usize);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
lua_pushthread(L);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_rawset(L, -4);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 2);
|
||||
return _ptr;
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
|
||||
lua_pushvalue(L, lua::LUA_GLOBALSINDEX);
|
||||
lua_pushvalue(L, LUA_GLOBALSINDEX);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
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_(L, narg);
|
||||
if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
|
||||
*nres = lua_gettop(L);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
//
|
||||
// lauxlib ported functions
|
||||
//
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
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_MINSTACK) == 0 {
|
||||
if !msg.is_null() {
|
||||
luaL_error(L, cstr!("stack overflow (%s)"), msg);
|
||||
} else {
|
||||
|
@ -615,23 +395,19 @@ pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char)
|
|||
}
|
||||
}
|
||||
|
||||
pub unsafe fn luaL_checkversion(_L: *mut lua_State) {
|
||||
// Void
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int {
|
||||
if luaL_getmetafield_old(L, obj, e) != 0 {
|
||||
if luaL_getmetafield_(L, obj, e) != 0 {
|
||||
lua_type(L, -1)
|
||||
} else {
|
||||
lua::LUA_TNIL
|
||||
LUA_TNIL
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int {
|
||||
if luaL_newmetatable_old(L, tname) != 0 {
|
||||
lua_pushstring(L, tname);
|
||||
if luaL_newmetatable_(L, tname) != 0 {
|
||||
lua_pushstring_(L, tname);
|
||||
lua_setfield(L, -2, cstr!("__name"));
|
||||
1
|
||||
} else {
|
||||
|
@ -639,7 +415,6 @@ pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_in
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_loadbufferx(
|
||||
L: *mut lua_State,
|
||||
|
@ -648,32 +423,30 @@ pub unsafe fn luaL_loadbufferx(
|
|||
name: *const c_char,
|
||||
mode: *const c_char,
|
||||
) -> c_int {
|
||||
let status = if sz > 0 && *buff as u8 == lua::LUA_SIGNATURE[0] {
|
||||
compat53_checkmode(L, mode, cstr!("binary"), lua::LUA_ERRSYNTAX)
|
||||
let status = if sz > 0 && *buff as u8 == LUA_SIGNATURE[0] {
|
||||
compat53_checkmode(L, mode, cstr!("binary"), LUA_ERRSYNTAX)
|
||||
} else {
|
||||
compat53_checkmode(L, mode, cstr!("text"), lua::LUA_ERRSYNTAX)
|
||||
compat53_checkmode(L, mode, cstr!("text"), LUA_ERRSYNTAX)
|
||||
};
|
||||
if status != lua::LUA_OK {
|
||||
if status != LUA_OK {
|
||||
return status;
|
||||
}
|
||||
luaL_loadbuffer(L, buff, sz, name)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer {
|
||||
let mut isnum = 0;
|
||||
luaL_checkstack(L, 1, cstr!("not enough stack slots"));
|
||||
lua_len(L, idx);
|
||||
let res = lua_tointegerx(L, -1, &mut isnum);
|
||||
lua::lua_pop(L, 1);
|
||||
lua_pop(L, 1);
|
||||
if isnum == 0 {
|
||||
luaL_error(L, cstr!("object length is not an integer"));
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub unsafe fn luaL_traceback(
|
||||
L: *mut lua_State,
|
||||
L1: *mut lua_State,
|
||||
|
@ -717,13 +490,13 @@ pub unsafe fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) ->
|
|||
if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
|
||||
let t = lua_type(L, idx);
|
||||
match t {
|
||||
lua::LUA_TNIL => {
|
||||
LUA_TNIL => {
|
||||
lua_pushliteral(L, "nil");
|
||||
}
|
||||
lua::LUA_TSTRING | lua::LUA_TNUMBER => {
|
||||
LUA_TSTRING | LUA_TNUMBER => {
|
||||
lua_pushvalue(L, idx);
|
||||
}
|
||||
lua::LUA_TBOOLEAN => {
|
||||
LUA_TBOOLEAN => {
|
||||
if lua_toboolean(L, idx) == 0 {
|
||||
lua_pushliteral(L, "false");
|
||||
} else {
|
||||
|
@ -732,13 +505,13 @@ pub unsafe fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) ->
|
|||
}
|
||||
_ => {
|
||||
let tt = luaL_getmetafield(L, idx, cstr!("__name"));
|
||||
let name = if tt == lua::LUA_TSTRING {
|
||||
let name = if tt == LUA_TSTRING {
|
||||
lua_tostring(L, -1)
|
||||
} else {
|
||||
lua_typename(L, t)
|
||||
};
|
||||
lua_pushfstring(L, cstr!("%s: %p"), name, lua_topointer(L, idx));
|
||||
if tt != lua::LUA_TNIL {
|
||||
if tt != LUA_TNIL {
|
||||
lua_replace(L, -2);
|
||||
}
|
||||
}
|
||||
|
@ -749,7 +522,6 @@ pub unsafe fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) ->
|
|||
lua_tolstring(L, -1, len)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) {
|
||||
luaL_checkstack(L, 1, cstr!("not enough stack slots"));
|
||||
|
@ -757,57 +529,19 @@ pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) {
|
|||
lua_setmetatable(L, -2);
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
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);
|
||||
luaL_checkstack(L, 2, cstr!("not enough stack slots"));
|
||||
if p.is_null() || lua_getmetatable(L, i) == 0 {
|
||||
return ptr::null_mut();
|
||||
} else {
|
||||
luaL_getmetatable(L, tname);
|
||||
let res = lua_rawequal(L, -1, -2);
|
||||
lua_pop(L, 2);
|
||||
if res == 0 {
|
||||
p = ptr::null_mut();
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
#[inline(always)]
|
||||
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"));
|
||||
while !(*l).name.is_null() {
|
||||
// fill the table with given functions
|
||||
l = l.offset(1);
|
||||
lua_pushstring(L, (*l).name);
|
||||
for _ in 0..nup {
|
||||
// copy upvalues to the top
|
||||
lua_pushvalue(L, -(nup + 1));
|
||||
}
|
||||
lua_pushcclosure(L, (*l).func, nup); // closure with those upvalues
|
||||
lua_settable(L, -(nup + 3)); // table must be below the upvalues, the name and the closure
|
||||
}
|
||||
lua_pop(L, nup); // remove upvalues
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub unsafe fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int {
|
||||
let abs_i = lua_absindex(L, idx);
|
||||
luaL_checkstack(L, 3, cstr!("not enough stack slots"));
|
||||
lua_pushstring(L, fname);
|
||||
lua_gettable(L, abs_i);
|
||||
if lua_istable(L, -1) != 0 {
|
||||
lua_pushstring_(L, fname);
|
||||
if lua_gettable(L, abs_i) == LUA_TTABLE {
|
||||
return 1;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
lua_newtable(L);
|
||||
lua_pushstring(L, fname);
|
||||
lua_pushstring_(L, fname);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, abs_i);
|
||||
return 0;
|
||||
0
|
||||
}
|
||||
|
||||
pub unsafe fn luaL_requiref(
|
||||
|
@ -817,12 +551,12 @@ pub unsafe fn luaL_requiref(
|
|||
glb: c_int,
|
||||
) {
|
||||
luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
|
||||
luaL_getsubtable(L, lua::LUA_REGISTRYINDEX, cstr!("_LOADED"));
|
||||
if lua_getfield(L, -1, modname) == lua::LUA_TNIL {
|
||||
luaL_getsubtable(L, LUA_REGISTRYINDEX, cstr!("_LOADED"));
|
||||
if lua_getfield(L, -1, modname) == LUA_TNIL {
|
||||
lua_pop(L, 1);
|
||||
lua_pushcfunction(L, openf);
|
||||
lua_pushstring(L, modname);
|
||||
#[cfg(any(feature = "lua52", feature = "lua51"))]
|
||||
#[cfg(feature = "lua51")]
|
||||
{
|
||||
lua_call(L, 1, 1);
|
||||
lua_pushvalue(L, -1);
|
||||
|
@ -834,11 +568,10 @@ pub unsafe fn luaL_requiref(
|
|||
lua_getfield(L, -1, modname);
|
||||
}
|
||||
}
|
||||
if cfg!(any(feature = "lua52", feature = "lua51")) && glb != 0 {
|
||||
if glb != 0 {
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setglobal(L, modname);
|
||||
}
|
||||
if cfg!(feature = "luajit") && glb == 0 {
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_setglobal(L, modname);
|
||||
}
|
145
src/ffi/lua51/lauxlib.rs
Normal file
145
src/ffi/lua51/lauxlib.rs
Normal file
|
@ -0,0 +1,145 @@
|
|||
//! Contains definitions from `lauxlib.h`.
|
||||
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::ptr;
|
||||
|
||||
use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State};
|
||||
|
||||
// Extra error code for 'luaL_load'
|
||||
pub const LUA_ERRFILE: c_int = lua::LUA_ERRERR + 1;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct luaL_Reg {
|
||||
pub name: *const c_char,
|
||||
pub func: lua_CFunction,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn luaL_register(L: *mut lua_State, libname: *const c_char, l: *const luaL_Reg);
|
||||
#[link_name = "luaL_getmetafield"]
|
||||
pub fn luaL_getmetafield_(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_typerror(L: *mut lua_State, narg: c_int, tname: *const c_char) -> c_int;
|
||||
pub fn luaL_argerror(L: *mut lua_State, narg: c_int, extramsg: *const c_char) -> c_int;
|
||||
pub fn luaL_checklstring(L: *mut lua_State, narg: c_int, l: *mut usize) -> *const c_char;
|
||||
pub fn luaL_optlstring(
|
||||
L: *mut lua_State,
|
||||
narg: c_int,
|
||||
def: *const c_char,
|
||||
l: *mut usize,
|
||||
) -> *const c_char;
|
||||
pub fn luaL_checknumber(L: *mut lua_State, narg: c_int) -> lua_Number;
|
||||
pub fn luaL_optnumber(L: *mut lua_State, narg: c_int, def: lua_Number) -> lua_Number;
|
||||
pub fn luaL_checkinteger(L: *mut lua_State, narg: c_int) -> lua_Integer;
|
||||
pub fn luaL_optinteger(L: *mut lua_State, narg: c_int, def: lua_Integer) -> lua_Integer;
|
||||
#[link_name = "luaL_checkstack"]
|
||||
pub fn luaL_checkstack_(L: *mut lua_State, sz: c_int, msg: *const c_char);
|
||||
pub fn luaL_checktype(L: *mut lua_State, narg: c_int, t: c_int);
|
||||
pub fn luaL_checkany(L: *mut lua_State, narg: c_int);
|
||||
|
||||
#[link_name = "luaL_newmetatable"]
|
||||
pub fn luaL_newmetatable_(L: *mut lua_State, tname: *const c_char) -> c_int;
|
||||
pub fn luaL_checkudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;
|
||||
|
||||
pub fn luaL_where(L: *mut lua_State, lvl: c_int);
|
||||
pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> !;
|
||||
|
||||
pub fn luaL_checkoption(
|
||||
L: *mut lua_State,
|
||||
narg: c_int,
|
||||
def: *const c_char,
|
||||
lst: *const *const c_char,
|
||||
) -> c_int;
|
||||
}
|
||||
|
||||
// Pre-defined references
|
||||
pub const LUA_NOREF: c_int = -2;
|
||||
pub const LUA_REFNIL: c_int = -1;
|
||||
|
||||
extern "C" {
|
||||
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#ref: c_int);
|
||||
|
||||
pub fn luaL_loadfile(L: *mut lua_State, filename: *const c_char) -> c_int;
|
||||
pub fn luaL_loadbuffer(
|
||||
L: *mut lua_State,
|
||||
buff: *const c_char,
|
||||
sz: usize,
|
||||
name: *const c_char,
|
||||
) -> c_int;
|
||||
pub fn luaL_loadstring(L: *mut lua_State, s: *const c_char) -> c_int;
|
||||
|
||||
pub fn luaL_newstate() -> *mut lua_State;
|
||||
|
||||
pub fn luaL_gsub(
|
||||
L: *mut lua_State,
|
||||
s: *const c_char,
|
||||
p: *const c_char,
|
||||
r: *const c_char,
|
||||
) -> *const c_char;
|
||||
|
||||
pub fn luaL_findtable(
|
||||
L: *mut lua_State,
|
||||
idx: c_int,
|
||||
fname: *const c_char,
|
||||
szhint: c_int,
|
||||
) -> *const c_char;
|
||||
}
|
||||
|
||||
//
|
||||
// Some useful macros (implemented as Rust functions)
|
||||
//
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_argcheck(L: *mut lua_State, cond: c_int, narg: c_int, extramsg: *const c_char) {
|
||||
if cond == 0 {
|
||||
luaL_argerror(L, narg, extramsg);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_checkstring(L: *mut lua_State, n: c_int) -> *const c_char {
|
||||
luaL_checklstring(L, n, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_optstring(L: *mut lua_State, n: c_int, d: *const c_char) -> *const c_char {
|
||||
luaL_optlstring(L, n, d, ptr::null_mut())
|
||||
}
|
||||
|
||||
// Deprecated from 5.3: luaL_checkint, luaL_optint, luaL_checklong, luaL_optlong
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_typename(L: *mut lua_State, i: c_int) -> *const c_char {
|
||||
lua::lua_typename(L, lua::lua_type(L, i))
|
||||
}
|
||||
|
||||
pub unsafe fn luaL_dofile(L: *mut lua_State, filename: *const c_char) -> c_int {
|
||||
let status = luaL_loadfile(L, filename);
|
||||
if status == 0 {
|
||||
lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
|
||||
} else {
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_dostring(L: *mut lua_State, s: *const c_char) -> c_int {
|
||||
let status = luaL_loadstring(L, s);
|
||||
if status == 0 {
|
||||
lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
|
||||
} else {
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
|
||||
lua::lua_getfield_(L, lua::LUA_REGISTRYINDEX, n);
|
||||
}
|
||||
|
||||
// TODO: luaL_opt
|
||||
|
||||
//
|
||||
// TODO: Generic Buffer Manipulation
|
||||
//
|
389
src/ffi/lua51/lua.rs
Normal file
389
src/ffi/lua51/lua.rs
Normal file
|
@ -0,0 +1,389 @@
|
|||
//! Contains definitions from `lua.h`.
|
||||
|
||||
use std::marker::{PhantomData, PhantomPinned};
|
||||
use std::os::raw::{c_char, c_double, c_int, c_void};
|
||||
use std::ptr;
|
||||
|
||||
// Mark for precompiled code (`<esc>Lua`)
|
||||
#[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'
|
||||
pub const LUA_MULTRET: c_int = -1;
|
||||
|
||||
//
|
||||
// Pseudo-indices
|
||||
//
|
||||
pub const LUA_REGISTRYINDEX: c_int = -10000;
|
||||
pub const LUA_ENVIRONINDEX: c_int = -10001;
|
||||
pub const LUA_GLOBALSINDEX: c_int = -10002;
|
||||
|
||||
pub const fn lua_upvalueindex(i: c_int) -> c_int {
|
||||
LUA_GLOBALSINDEX - i
|
||||
}
|
||||
|
||||
//
|
||||
// Thread status
|
||||
//
|
||||
pub const LUA_OK: c_int = 0;
|
||||
pub const LUA_YIELD: c_int = 1;
|
||||
pub const LUA_ERRRUN: c_int = 2;
|
||||
pub const LUA_ERRSYNTAX: c_int = 3;
|
||||
pub const LUA_ERRMEM: c_int = 4;
|
||||
pub const LUA_ERRERR: c_int = 5;
|
||||
|
||||
/// A raw Lua state associated with a thread.
|
||||
#[repr(C)]
|
||||
pub struct lua_State {
|
||||
_data: [u8; 0],
|
||||
_marker: PhantomData<(*mut u8, PhantomPinned)>,
|
||||
}
|
||||
|
||||
//
|
||||
// Basic types
|
||||
//
|
||||
pub const LUA_TNONE: c_int = -1;
|
||||
|
||||
pub const LUA_TNIL: c_int = 0;
|
||||
pub const LUA_TBOOLEAN: c_int = 1;
|
||||
pub const LUA_TLIGHTUSERDATA: c_int = 2;
|
||||
pub const LUA_TNUMBER: c_int = 3;
|
||||
pub const LUA_TSTRING: c_int = 4;
|
||||
pub const LUA_TTABLE: c_int = 5;
|
||||
pub const LUA_TFUNCTION: c_int = 6;
|
||||
pub const LUA_TUSERDATA: c_int = 7;
|
||||
pub const LUA_TTHREAD: c_int = 8;
|
||||
|
||||
/// Type produced by LuaJIT FFI module
|
||||
#[cfg(feature = "luajit")]
|
||||
pub const LUA_TCDATA: c_int = 10;
|
||||
|
||||
/// Minimum Lua stack available to a C function
|
||||
pub const LUA_MINSTACK: c_int = 20;
|
||||
|
||||
/// A Lua number, usually equivalent to `f64`
|
||||
pub type lua_Number = c_double;
|
||||
|
||||
/// A Lua integer, usually equivalent to `i64`
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
pub type lua_Integer = i32;
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub type lua_Integer = i64;
|
||||
|
||||
/// Type for native C functions that can be passed to Lua.
|
||||
pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int;
|
||||
|
||||
// Type for functions that read/write blocks when loading/dumping Lua chunks
|
||||
pub type lua_Reader =
|
||||
unsafe extern "C" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char;
|
||||
pub type lua_Writer =
|
||||
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
|
||||
pub type lua_Alloc = unsafe extern "C" fn(
|
||||
ud: *mut c_void,
|
||||
ptr: *mut c_void,
|
||||
osize: usize,
|
||||
nsize: usize,
|
||||
) -> *mut c_void;
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// State manipulation
|
||||
//
|
||||
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_newthread(L: *mut lua_State) -> *mut lua_State;
|
||||
|
||||
#[cfg(all(feature = "luajit", feature = "vendored"))]
|
||||
pub fn lua_resetthread(L: *mut lua_State, th: *mut lua_State);
|
||||
|
||||
pub fn lua_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction;
|
||||
|
||||
//
|
||||
// Basic stack manipulation
|
||||
//
|
||||
pub fn lua_gettop(L: *mut lua_State) -> c_int;
|
||||
pub fn lua_settop(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_pushvalue(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_remove(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_insert(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_replace(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_checkstack(L: *mut lua_State, sz: c_int) -> c_int;
|
||||
|
||||
pub fn lua_xmove(from: *mut lua_State, to: *mut lua_State, n: c_int);
|
||||
|
||||
//
|
||||
// Access functions (stack -> C)
|
||||
//
|
||||
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_iscfunction(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_typename(L: *mut lua_State, tp: c_int) -> *const c_char;
|
||||
|
||||
pub fn lua_equal(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;
|
||||
pub fn lua_lessthan(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
||||
|
||||
pub fn lua_tonumber(L: *mut lua_State, idx: c_int) -> lua_Number;
|
||||
#[link_name = "lua_tointeger"]
|
||||
pub fn lua_tointeger_(L: *mut lua_State, idx: c_int) -> lua_Integer;
|
||||
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_objlen(L: *mut lua_State, idx: c_int) -> usize;
|
||||
pub fn lua_tocfunction(L: *mut lua_State, idx: c_int) -> Option<lua_CFunction>;
|
||||
pub fn lua_touserdata(L: *mut lua_State, idx: c_int) -> *mut c_void;
|
||||
pub fn lua_tothread(L: *mut lua_State, idx: c_int) -> *mut lua_State;
|
||||
pub fn lua_topointer(L: *mut lua_State, idx: c_int) -> *const c_void;
|
||||
|
||||
//
|
||||
// Push functions (C -> stack)
|
||||
//
|
||||
pub fn lua_pushnil(L: *mut lua_State);
|
||||
pub fn lua_pushnumber(L: *mut lua_State, n: lua_Number);
|
||||
pub fn lua_pushinteger(L: *mut lua_State, n: lua_Integer);
|
||||
#[link_name = "lua_pushlstring"]
|
||||
pub fn lua_pushlstring_(L: *mut lua_State, s: *const c_char, l: usize);
|
||||
#[link_name = "lua_pushstring"]
|
||||
pub fn lua_pushstring_(L: *mut lua_State, s: *const c_char);
|
||||
// lua_pushvfstring
|
||||
pub fn lua_pushfstring(L: *mut lua_State, fmt: *const c_char, ...) -> *const c_char;
|
||||
pub fn lua_pushcclosure(L: *mut lua_State, f: lua_CFunction, n: c_int);
|
||||
pub fn lua_pushboolean(L: *mut lua_State, b: c_int);
|
||||
pub fn lua_pushlightuserdata(L: *mut lua_State, p: *mut c_void);
|
||||
pub fn lua_pushthread(L: *mut lua_State) -> c_int;
|
||||
|
||||
//
|
||||
// Get functions (Lua -> stack)
|
||||
//
|
||||
#[link_name = "lua_gettable"]
|
||||
pub fn lua_gettable_(L: *mut lua_State, idx: c_int);
|
||||
#[link_name = "lua_getfield"]
|
||||
pub fn lua_getfield_(L: *mut lua_State, idx: c_int, k: *const c_char);
|
||||
#[link_name = "lua_rawget"]
|
||||
pub fn lua_rawget_(L: *mut lua_State, idx: c_int);
|
||||
#[link_name = "lua_rawgeti"]
|
||||
pub fn lua_rawgeti_(L: *mut lua_State, idx: c_int, n: c_int);
|
||||
pub fn lua_createtable(L: *mut lua_State, narr: c_int, nrec: c_int);
|
||||
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_getfenv(L: *mut lua_State, idx: c_int);
|
||||
|
||||
//
|
||||
// Set functions (stack -> Lua)
|
||||
//
|
||||
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_rawset(L: *mut lua_State, idx: c_int);
|
||||
#[link_name = "lua_rawseti"]
|
||||
pub fn lua_rawseti_(L: *mut lua_State, idx: c_int, n: c_int);
|
||||
pub fn lua_setmetatable(L: *mut lua_State, objindex: c_int) -> c_int;
|
||||
pub fn lua_setfenv(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
|
||||
//
|
||||
// 'load' and 'call' functions (load and run Lua code)
|
||||
//
|
||||
pub fn lua_call(L: *mut lua_State, nargs: c_int, nresults: c_int);
|
||||
pub fn lua_pcall(L: *mut lua_State, nargs: c_int, nresults: c_int, errfunc: c_int) -> c_int;
|
||||
pub fn lua_cpcall(L: *mut lua_State, f: lua_CFunction, ud: *mut c_void) -> c_int;
|
||||
pub fn lua_load(
|
||||
L: *mut lua_State,
|
||||
reader: lua_Reader,
|
||||
data: *mut c_void,
|
||||
chunkname: *const c_char,
|
||||
) -> c_int;
|
||||
|
||||
#[link_name = "lua_dump"]
|
||||
pub fn lua_dump_(L: *mut lua_State, writer: lua_Writer, data: *mut c_void) -> c_int;
|
||||
|
||||
//
|
||||
// Coroutine functions
|
||||
//
|
||||
pub fn lua_yield(L: *mut lua_State, nresults: c_int) -> c_int;
|
||||
#[link_name = "lua_resume"]
|
||||
pub fn lua_resume_(L: *mut lua_State, narg: c_int) -> c_int;
|
||||
pub fn lua_status(L: *mut lua_State) -> c_int;
|
||||
}
|
||||
|
||||
//
|
||||
// Garbage-collection function and options
|
||||
//
|
||||
pub const LUA_GCSTOP: c_int = 0;
|
||||
pub const LUA_GCRESTART: c_int = 1;
|
||||
pub const LUA_GCCOLLECT: c_int = 2;
|
||||
pub const LUA_GCCOUNT: c_int = 3;
|
||||
pub const LUA_GCCOUNTB: c_int = 4;
|
||||
pub const LUA_GCSTEP: c_int = 5;
|
||||
pub const LUA_GCSETPAUSE: c_int = 6;
|
||||
pub const LUA_GCSETSTEPMUL: c_int = 7;
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int;
|
||||
}
|
||||
|
||||
//
|
||||
// Miscellaneous functions
|
||||
//
|
||||
extern "C" {
|
||||
pub fn lua_error(L: *mut lua_State) -> !;
|
||||
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_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);
|
||||
}
|
||||
|
||||
//
|
||||
// Some useful macros (implemented as Rust functions)
|
||||
//
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pop(L: *mut lua_State, n: c_int) {
|
||||
lua_settop(L, -n - 1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_newtable(L: *mut lua_State) {
|
||||
lua_createtable(L, 0, 0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_register(L: *mut lua_State, n: *const c_char, f: lua_CFunction) {
|
||||
lua_pushcfunction(L, f);
|
||||
lua_setglobal(L, n)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) {
|
||||
lua_pushcclosure(L, f, 0)
|
||||
}
|
||||
|
||||
// TODO: lua_strlen
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isfunction(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TFUNCTION) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_istable(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TTABLE) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_islightuserdata(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TLIGHTUSERDATA) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TNIL) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isboolean(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TBOOLEAN) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isthread(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TTHREAD) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnone(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TNONE) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnoneornil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) <= LUA_TNIL) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) {
|
||||
use std::ffi::CString;
|
||||
let c_str = CString::new(s).unwrap();
|
||||
lua_pushlstring_(L, c_str.as_ptr(), c_str.as_bytes().len())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_setglobal(L: *mut lua_State, var: *const c_char) {
|
||||
lua_setfield(L, LUA_GLOBALSINDEX, var)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getglobal_(L: *mut lua_State, var: *const c_char) {
|
||||
lua_getfield_(L, LUA_GLOBALSINDEX, var)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char {
|
||||
lua_tolstring(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_xpush(from: *mut lua_State, to: *mut lua_State, idx: c_int) {
|
||||
lua_pushvalue(from, idx);
|
||||
lua_xmove(from, to, 1);
|
||||
}
|
||||
|
||||
//
|
||||
// Debug API
|
||||
//
|
||||
|
||||
// Maximum size for the description of the source of a function in debug information.
|
||||
const LUA_IDSIZE: usize = 60;
|
||||
|
||||
// Event codes
|
||||
pub const LUA_HOOKCALL: c_int = 0;
|
||||
pub const LUA_HOOKRET: c_int = 1;
|
||||
pub const LUA_HOOKLINE: c_int = 2;
|
||||
pub const LUA_HOOKCOUNT: c_int = 3;
|
||||
pub const LUA_HOOKTAILCALL: c_int = 4;
|
||||
|
||||
// Event masks
|
||||
pub const LUA_MASKCALL: c_int = 1 << (LUA_HOOKCALL as usize);
|
||||
pub const LUA_MASKRET: c_int = 1 << (LUA_HOOKRET as usize);
|
||||
pub const LUA_MASKLINE: c_int = 1 << (LUA_HOOKLINE as usize);
|
||||
pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
|
||||
|
||||
/// Type for functions to be called on debug events.
|
||||
pub type lua_Hook = unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug);
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_getstack(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getinfo(L: *mut lua_State, what: *const c_char, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getlocal(L: *mut lua_State, ar: *const lua_Debug, n: c_int) -> *const c_char;
|
||||
pub fn lua_setlocal(L: *mut lua_State, ar: *const lua_Debug, 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_sethook(
|
||||
L: *mut lua_State,
|
||||
func: Option<lua_Hook>,
|
||||
mask: c_int,
|
||||
count: c_int,
|
||||
) -> c_int;
|
||||
pub fn lua_gethook(L: *mut lua_State) -> Option<lua_Hook>;
|
||||
pub fn lua_gethookmask(L: *mut lua_State) -> c_int;
|
||||
pub fn lua_gethookcount(L: *mut lua_State) -> c_int;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct lua_Debug {
|
||||
pub event: c_int,
|
||||
pub name: *const c_char,
|
||||
pub namewhat: *const c_char,
|
||||
pub what: *const c_char,
|
||||
pub source: *const c_char,
|
||||
pub currentline: c_int,
|
||||
pub nups: c_int,
|
||||
pub linedefined: c_int,
|
||||
pub lastlinedefined: c_int,
|
||||
pub short_src: [c_char; LUA_IDSIZE],
|
||||
// lua.h mentions this is for private use
|
||||
i_ci: c_int,
|
||||
}
|
42
src/ffi/lua51/lualib.rs
Normal file
42
src/ffi/lua51/lualib.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
//! Contains definitions from `lualib.h`.
|
||||
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use super::lua::lua_State;
|
||||
|
||||
pub const LUA_COLIBNAME: &str = "coroutine";
|
||||
pub const LUA_TABLIBNAME: &str = "table";
|
||||
pub const LUA_IOLIBNAME: &str = "io";
|
||||
pub const LUA_OSLIBNAME: &str = "os";
|
||||
pub const LUA_STRLIBNAME: &str = "string";
|
||||
pub const LUA_MATHLIBNAME: &str = "math";
|
||||
pub const LUA_DBLIBNAME: &str = "debug";
|
||||
pub const LUA_LOADLIBNAME: &str = "package";
|
||||
|
||||
#[cfg(feature = "luajit")]
|
||||
pub const LUA_BITLIBNAME: &str = "bit";
|
||||
#[cfg(feature = "luajit")]
|
||||
pub const LUA_JITLIBNAME: &str = "jit";
|
||||
#[cfg(feature = "luajit")]
|
||||
pub const LUA_FFILIBNAME: &str = "ffi";
|
||||
|
||||
extern "C" {
|
||||
pub fn luaopen_base(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_os(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_string(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_math(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_debug(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_package(L: *mut lua_State) -> c_int;
|
||||
|
||||
#[cfg(feature = "luajit")]
|
||||
pub fn luaopen_bit(L: *mut lua_State) -> c_int;
|
||||
#[cfg(feature = "luajit")]
|
||||
pub fn luaopen_jit(L: *mut lua_State) -> c_int;
|
||||
#[cfg(feature = "luajit")]
|
||||
pub fn luaopen_ffi(L: *mut lua_State) -> c_int;
|
||||
|
||||
// open all builtin libraries
|
||||
pub fn luaL_openlibs(L: *mut lua_State);
|
||||
}
|
11
src/ffi/lua51/mod.rs
Normal file
11
src/ffi/lua51/mod.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
//! Low level bindings to Lua 5.1.
|
||||
|
||||
pub use compat::*;
|
||||
pub use lauxlib::*;
|
||||
pub use lua::*;
|
||||
pub use lualib::*;
|
||||
|
||||
pub mod compat;
|
||||
pub mod lauxlib;
|
||||
pub mod lua;
|
||||
pub mod lualib;
|
265
src/ffi/lua52/compat.rs
Normal file
265
src/ffi/lua52/compat.rs
Normal file
|
@ -0,0 +1,265 @@
|
|||
//! MLua compatibility layer for Lua 5.2
|
||||
//!
|
||||
//! Based on github.com/keplerproject/lua-compat-5.3
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::ptr;
|
||||
|
||||
use super::lauxlib::*;
|
||||
use super::lua::*;
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
|
||||
while a < b {
|
||||
lua_pushvalue(L, a);
|
||||
lua_pushvalue(L, b);
|
||||
lua_replace(L, a);
|
||||
lua_replace(L, b);
|
||||
a += 1;
|
||||
b -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// lua ported functions
|
||||
//
|
||||
|
||||
pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
|
||||
idx = lua_absindex(L, idx);
|
||||
if n > 0 {
|
||||
// Faster version
|
||||
for _ in 0..n {
|
||||
lua_insert(L, idx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let n_elems = lua_gettop(L) - idx + 1;
|
||||
if n < 0 {
|
||||
n += n_elems;
|
||||
}
|
||||
if n > 0 && n < n_elems {
|
||||
luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
|
||||
n = n_elems - n;
|
||||
compat53_reverse(L, idx, idx + n - 1);
|
||||
compat53_reverse(L, idx + n, idx + n_elems - 1);
|
||||
compat53_reverse(L, idx, idx + n_elems - 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
|
||||
if lua_type(L, idx) == LUA_TNUMBER {
|
||||
let n = lua_tonumber(L, idx);
|
||||
let i = lua_tointeger(L, idx);
|
||||
if (n - i as lua_Number).abs() < lua_Number::EPSILON {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
|
||||
lua_tointegerx(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
// Implemented for Lua 5.2 as well
|
||||
// See https://github.com/keplerproject/lua-compat-5.3/issues/40
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
|
||||
let mut ok = 0;
|
||||
let n = lua_tonumberx(L, i, &mut ok);
|
||||
let n_int = n as lua_Integer;
|
||||
if ok != 0 && (n - n_int as lua_Number).abs() < lua_Number::EPSILON {
|
||||
if !isnum.is_null() {
|
||||
*isnum = 1;
|
||||
}
|
||||
return n_int;
|
||||
}
|
||||
if !isnum.is_null() {
|
||||
*isnum = 0;
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
|
||||
if l == 0 {
|
||||
lua_pushlstring_(L, cstr!(""), 0)
|
||||
} else {
|
||||
lua_pushlstring_(L, s, l)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int {
|
||||
lua_getglobal_(L, var);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int {
|
||||
lua_gettable_(L, idx);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int {
|
||||
lua_getfield_(L, idx, k);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_int {
|
||||
idx = lua_absindex(L, idx);
|
||||
lua_pushinteger(L, n);
|
||||
lua_gettable(L, idx)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int {
|
||||
lua_rawget_(L, idx);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
|
||||
let n = n.try_into().expect("cannot convert index to lua_Integer");
|
||||
lua_rawgeti_(L, idx, n);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int {
|
||||
lua_rawgetp_(L, idx, p);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
|
||||
lua_getuservalue_(L, idx);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
|
||||
luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
|
||||
idx = lua_absindex(L, idx);
|
||||
lua_pushinteger(L, n);
|
||||
lua_insert(L, -2);
|
||||
lua_settable(L, idx);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) {
|
||||
let n = n.try_into().expect("cannot convert index from lua_Integer");
|
||||
lua_rawseti_(L, idx, n)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_dump(
|
||||
L: *mut lua_State,
|
||||
writer: lua_Writer,
|
||||
data: *mut c_void,
|
||||
_strip: c_int,
|
||||
) -> c_int {
|
||||
lua_dump_(L, writer, data)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
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_(L, from, narg);
|
||||
if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
|
||||
*nres = lua_gettop(L);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
//
|
||||
// lauxlib ported functions
|
||||
//
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int {
|
||||
if luaL_getmetafield_(L, obj, e) != 0 {
|
||||
lua_type(L, -1)
|
||||
} else {
|
||||
LUA_TNIL
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int {
|
||||
if luaL_newmetatable_(L, tname) != 0 {
|
||||
lua_pushstring(L, tname);
|
||||
lua_setfield(L, -2, cstr!("__name"));
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char {
|
||||
if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
|
||||
let t = lua_type(L, idx);
|
||||
match t {
|
||||
LUA_TNIL => {
|
||||
lua_pushliteral(L, "nil");
|
||||
}
|
||||
LUA_TSTRING | LUA_TNUMBER => {
|
||||
lua_pushvalue(L, idx);
|
||||
}
|
||||
LUA_TBOOLEAN => {
|
||||
if lua_toboolean(L, idx) == 0 {
|
||||
lua_pushliteral(L, "false");
|
||||
} else {
|
||||
lua_pushliteral(L, "true");
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let tt = luaL_getmetafield(L, idx, cstr!("__name"));
|
||||
let name = if tt == LUA_TSTRING {
|
||||
lua_tostring(L, -1)
|
||||
} else {
|
||||
lua_typename(L, t)
|
||||
};
|
||||
lua_pushfstring(L, cstr!("%s: %p"), name, lua_topointer(L, idx));
|
||||
if tt != LUA_TNIL {
|
||||
lua_replace(L, -2);
|
||||
}
|
||||
}
|
||||
};
|
||||
} else if lua_isstring(L, -1) == 0 {
|
||||
luaL_error(L, cstr!("'__tostring' must return a string"));
|
||||
}
|
||||
lua_tolstring(L, -1, len)
|
||||
}
|
||||
|
||||
pub unsafe fn luaL_requiref(
|
||||
L: *mut lua_State,
|
||||
modname: *const c_char,
|
||||
openf: lua_CFunction,
|
||||
glb: c_int,
|
||||
) {
|
||||
luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
|
||||
luaL_getsubtable(L, LUA_REGISTRYINDEX, cstr!("_LOADED"));
|
||||
if lua_getfield(L, -1, modname) == LUA_TNIL {
|
||||
lua_pop(L, 1);
|
||||
lua_pushcfunction(L, openf);
|
||||
lua_pushstring(L, modname);
|
||||
lua_call(L, 1, 1);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -3, modname);
|
||||
}
|
||||
if glb != 0 {
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setglobal(L, modname);
|
||||
}
|
||||
lua_replace(L, -2);
|
||||
}
|
184
src/ffi/lua52/lauxlib.rs
Normal file
184
src/ffi/lua52/lauxlib.rs
Normal file
|
@ -0,0 +1,184 @@
|
|||
//! Contains definitions from `lauxlib.h`.
|
||||
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::ptr;
|
||||
|
||||
use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State, lua_Unsigned};
|
||||
|
||||
// Extra error code for 'luaL_load'
|
||||
pub const LUA_ERRFILE: c_int = lua::LUA_ERRERR + 1;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct luaL_Reg {
|
||||
pub name: *const c_char,
|
||||
pub func: lua_CFunction,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number);
|
||||
|
||||
#[link_name = "luaL_getmetafield"]
|
||||
pub fn luaL_getmetafield_(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;
|
||||
#[link_name = "luaL_tolstring"]
|
||||
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, extramsg: *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_optlstring(
|
||||
L: *mut lua_State,
|
||||
arg: c_int,
|
||||
def: *const c_char,
|
||||
l: *mut usize,
|
||||
) -> *const c_char;
|
||||
pub fn luaL_checknumber(L: *mut lua_State, arg: c_int) -> lua_Number;
|
||||
pub fn luaL_optnumber(L: *mut lua_State, arg: c_int, def: lua_Number) -> lua_Number;
|
||||
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_checkunsigned(L: *mut lua_State, arg: c_int) -> lua_Unsigned;
|
||||
pub fn luaL_optunsigned(L: *mut lua_State, arg: c_int, def: lua_Unsigned) -> lua_Unsigned;
|
||||
|
||||
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_checkany(L: *mut lua_State, arg: c_int);
|
||||
|
||||
#[link_name = "luaL_newmetatable"]
|
||||
pub fn luaL_newmetatable_(L: *mut lua_State, tname: *const c_char) -> c_int;
|
||||
pub fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char);
|
||||
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_where(L: *mut lua_State, lvl: c_int);
|
||||
pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> !;
|
||||
|
||||
pub fn luaL_checkoption(
|
||||
L: *mut lua_State,
|
||||
arg: c_int,
|
||||
def: *const c_char,
|
||||
lst: *const *const c_char,
|
||||
) -> c_int;
|
||||
|
||||
pub fn luaL_fileresult(L: *mut lua_State, stat: c_int, fname: *const c_char) -> c_int;
|
||||
pub fn luaL_execresult(L: *mut lua_State, stat: c_int) -> c_int;
|
||||
}
|
||||
|
||||
// Pre-defined references
|
||||
pub const LUA_NOREF: c_int = -2;
|
||||
pub const LUA_REFNIL: c_int = -1;
|
||||
|
||||
extern "C" {
|
||||
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#ref: c_int);
|
||||
|
||||
pub fn luaL_loadfilex(L: *mut lua_State, filename: *const c_char, mode: *const c_char)
|
||||
-> c_int;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
|
||||
luaL_loadfilex(L, f, ptr::null())
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn luaL_loadbufferx(
|
||||
L: *mut lua_State,
|
||||
buff: *const c_char,
|
||||
sz: usize,
|
||||
name: *const c_char,
|
||||
mode: *const c_char,
|
||||
) -> c_int;
|
||||
pub fn luaL_loadstring(L: *mut lua_State, s: *const c_char) -> c_int;
|
||||
|
||||
pub fn luaL_newstate() -> *mut lua_State;
|
||||
|
||||
pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer;
|
||||
|
||||
pub fn luaL_gsub(
|
||||
L: *mut lua_State,
|
||||
s: *const c_char,
|
||||
p: *const c_char,
|
||||
r: *const c_char,
|
||||
) -> *const c_char;
|
||||
|
||||
pub fn luaL_setfuncs(L: *mut lua_State, l: *const luaL_Reg, nup: c_int);
|
||||
|
||||
pub fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int;
|
||||
|
||||
pub fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, level: c_int);
|
||||
|
||||
#[link_name = "luaL_requiref"]
|
||||
pub fn luaL_requiref_(
|
||||
L: *mut lua_State,
|
||||
modname: *const c_char,
|
||||
openf: lua_CFunction,
|
||||
glb: c_int,
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Some useful macros (implemented as Rust functions)
|
||||
//
|
||||
|
||||
// TODO: luaL_newlibtable, luaL_newlib
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_argcheck(L: *mut lua_State, cond: c_int, arg: c_int, extramsg: *const c_char) {
|
||||
if cond == 0 {
|
||||
luaL_argerror(L, arg, extramsg);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_checkstring(L: *mut lua_State, n: c_int) -> *const c_char {
|
||||
luaL_checklstring(L, n, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_optstring(L: *mut lua_State, n: c_int, d: *const c_char) -> *const c_char {
|
||||
luaL_optlstring(L, n, d, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_typename(L: *mut lua_State, i: c_int) -> *const c_char {
|
||||
lua::lua_typename(L, lua::lua_type(L, i))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_dofile(L: *mut lua_State, filename: *const c_char) -> c_int {
|
||||
let status = luaL_loadfile(L, filename);
|
||||
if status == 0 {
|
||||
lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
|
||||
} else {
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_dostring(L: *mut lua_State, s: *const c_char) -> c_int {
|
||||
let status = luaL_loadstring(L, s);
|
||||
if status == 0 {
|
||||
lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
|
||||
} else {
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
|
||||
lua::lua_getfield_(L, lua::LUA_REGISTRYINDEX, n);
|
||||
}
|
||||
|
||||
// luaL_opt would be implemented here but it is undocumented, so it's omitted
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_loadbuffer(
|
||||
L: *mut lua_State,
|
||||
s: *const c_char,
|
||||
sz: usize,
|
||||
n: *const c_char,
|
||||
) -> c_int {
|
||||
luaL_loadbufferx(L, s, sz, n, ptr::null())
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: Generic Buffer Manipulation
|
||||
//
|
476
src/ffi/lua52/lua.rs
Normal file
476
src/ffi/lua52/lua.rs
Normal file
|
@ -0,0 +1,476 @@
|
|||
//! Contains definitions from `lua.h`.
|
||||
|
||||
use std::marker::{PhantomData, PhantomPinned};
|
||||
use std::os::raw::{c_char, c_double, c_int, c_uchar, c_uint, c_void};
|
||||
use std::ptr;
|
||||
|
||||
// Mark for precompiled code (`<esc>Lua`)
|
||||
pub const LUA_SIGNATURE: &[u8] = b"\x1bLua";
|
||||
|
||||
// Option for multiple returns in 'lua_pcall' and 'lua_call'
|
||||
pub const LUA_MULTRET: c_int = -1;
|
||||
|
||||
// Size of the Lua stack
|
||||
pub const LUAI_MAXSTACK: c_int = 1000000;
|
||||
|
||||
//
|
||||
// Pseudo-indices
|
||||
//
|
||||
pub const LUA_REGISTRYINDEX: c_int = -LUAI_MAXSTACK - 1000;
|
||||
|
||||
pub const fn lua_upvalueindex(i: c_int) -> c_int {
|
||||
LUA_REGISTRYINDEX - i
|
||||
}
|
||||
|
||||
//
|
||||
// Thread status
|
||||
//
|
||||
pub const LUA_OK: c_int = 0;
|
||||
pub const LUA_YIELD: c_int = 1;
|
||||
pub const LUA_ERRRUN: c_int = 2;
|
||||
pub const LUA_ERRSYNTAX: c_int = 3;
|
||||
pub const LUA_ERRMEM: c_int = 4;
|
||||
pub const LUA_ERRGCMM: c_int = 5;
|
||||
pub const LUA_ERRERR: c_int = 6;
|
||||
|
||||
/// A raw Lua state associated with a thread.
|
||||
#[repr(C)]
|
||||
pub struct lua_State {
|
||||
_data: [u8; 0],
|
||||
_marker: PhantomData<(*mut u8, PhantomPinned)>,
|
||||
}
|
||||
|
||||
//
|
||||
// Basic types
|
||||
//
|
||||
pub const LUA_TNONE: c_int = -1;
|
||||
|
||||
pub const LUA_TNIL: c_int = 0;
|
||||
pub const LUA_TBOOLEAN: c_int = 1;
|
||||
pub const LUA_TLIGHTUSERDATA: c_int = 2;
|
||||
pub const LUA_TNUMBER: c_int = 3;
|
||||
pub const LUA_TSTRING: c_int = 4;
|
||||
pub const LUA_TTABLE: c_int = 5;
|
||||
pub const LUA_TFUNCTION: c_int = 6;
|
||||
pub const LUA_TUSERDATA: c_int = 7;
|
||||
pub const LUA_TTHREAD: c_int = 8;
|
||||
|
||||
pub const LUA_NUMTAGS: c_int = 9;
|
||||
|
||||
/// Minimum Lua stack available to a C function
|
||||
pub const LUA_MINSTACK: c_int = 20;
|
||||
|
||||
// Predefined values in the registry
|
||||
pub const LUA_RIDX_MAINTHREAD: lua_Integer = 1;
|
||||
pub const LUA_RIDX_GLOBALS: lua_Integer = 2;
|
||||
pub const LUA_RIDX_LAST: lua_Integer = LUA_RIDX_GLOBALS;
|
||||
|
||||
/// A Lua number, usually equivalent to `f64`
|
||||
pub type lua_Number = c_double;
|
||||
|
||||
/// A Lua integer, usually equivalent to `i64`
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
pub type lua_Integer = i32;
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub type lua_Integer = i64;
|
||||
|
||||
/// A Lua unsigned integer, equivalent to `u32` in Lua 5.2
|
||||
pub type lua_Unsigned = c_uint;
|
||||
|
||||
/// Type for native C functions that can be passed to Lua
|
||||
pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int;
|
||||
|
||||
// Type for functions that read/write blocks when loading/dumping Lua chunks
|
||||
pub type lua_Reader =
|
||||
unsafe extern "C" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char;
|
||||
pub type lua_Writer =
|
||||
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
|
||||
pub type lua_Alloc = unsafe extern "C" fn(
|
||||
ud: *mut c_void,
|
||||
ptr: *mut c_void,
|
||||
osize: usize,
|
||||
nsize: usize,
|
||||
) -> *mut c_void;
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// State manipulation
|
||||
//
|
||||
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_newthread(L: *mut lua_State) -> *mut lua_State;
|
||||
|
||||
pub fn lua_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction;
|
||||
|
||||
pub fn lua_version(L: *mut lua_State) -> *const lua_Number;
|
||||
|
||||
//
|
||||
// Basic stack manipulation
|
||||
//
|
||||
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_settop(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_pushvalue(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_remove(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_insert(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_replace(L: *mut lua_State, idx: 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_xmove(from: *mut lua_State, to: *mut lua_State, n: c_int);
|
||||
|
||||
//
|
||||
// Access functions (stack -> C)
|
||||
//
|
||||
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_iscfunction(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_typename(L: *mut lua_State, tp: c_int) -> *const c_char;
|
||||
|
||||
pub fn lua_tonumberx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Number;
|
||||
#[link_name = "lua_tointegerx"]
|
||||
pub fn lua_tointegerx_(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Integer;
|
||||
pub fn lua_tounsignedx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Unsigned;
|
||||
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_rawlen(L: *mut lua_State, idx: c_int) -> usize;
|
||||
pub fn lua_tocfunction(L: *mut lua_State, idx: c_int) -> Option<lua_CFunction>;
|
||||
pub fn lua_touserdata(L: *mut lua_State, idx: c_int) -> *mut c_void;
|
||||
pub fn lua_tothread(L: *mut lua_State, idx: c_int) -> *mut lua_State;
|
||||
pub fn lua_topointer(L: *mut lua_State, idx: c_int) -> *const c_void;
|
||||
}
|
||||
|
||||
//
|
||||
// Comparison and arithmetic functions
|
||||
//
|
||||
pub const LUA_OPADD: c_int = 0;
|
||||
pub const LUA_OPSUB: c_int = 1;
|
||||
pub const LUA_OPMUL: c_int = 2;
|
||||
pub const LUA_OPDIV: c_int = 3;
|
||||
pub const LUA_OPMOD: c_int = 4;
|
||||
pub const LUA_OPPOW: c_int = 5;
|
||||
pub const LUA_OPUNM: c_int = 6;
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_arith(L: *mut lua_State, op: c_int);
|
||||
}
|
||||
|
||||
pub const LUA_OPEQ: c_int = 0;
|
||||
pub const LUA_OPLT: c_int = 1;
|
||||
pub const LUA_OPLE: c_int = 2;
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_rawequal(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
||||
pub fn lua_compare(L: *mut lua_State, idx1: c_int, idx2: c_int, op: c_int) -> c_int;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// Push functions (C -> stack)
|
||||
//
|
||||
pub fn lua_pushnil(L: *mut lua_State);
|
||||
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_pushunsigned(L: *mut lua_State, n: lua_Unsigned);
|
||||
#[link_name = "lua_pushlstring"]
|
||||
pub fn lua_pushlstring_(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char;
|
||||
pub fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char;
|
||||
// lua_pushvfstring
|
||||
pub fn lua_pushfstring(L: *mut lua_State, fmt: *const c_char, ...) -> *const c_char;
|
||||
pub fn lua_pushcclosure(L: *mut lua_State, f: lua_CFunction, n: c_int);
|
||||
pub fn lua_pushboolean(L: *mut lua_State, b: c_int);
|
||||
pub fn lua_pushlightuserdata(L: *mut lua_State, p: *mut c_void);
|
||||
pub fn lua_pushthread(L: *mut lua_State) -> c_int;
|
||||
|
||||
//
|
||||
// Get functions (Lua -> stack)
|
||||
//
|
||||
#[link_name = "lua_getglobal"]
|
||||
pub fn lua_getglobal_(L: *mut lua_State, name: *const c_char);
|
||||
#[link_name = "lua_gettable"]
|
||||
pub fn lua_gettable_(L: *mut lua_State, idx: c_int);
|
||||
#[link_name = "lua_getfield"]
|
||||
pub fn lua_getfield_(L: *mut lua_State, idx: c_int, k: *const c_char);
|
||||
#[link_name = "lua_rawget"]
|
||||
pub fn lua_rawget_(L: *mut lua_State, idx: c_int);
|
||||
#[link_name = "lua_rawgeti"]
|
||||
pub fn lua_rawgeti_(L: *mut lua_State, idx: c_int, n: c_int);
|
||||
#[link_name = "lua_rawgetp"]
|
||||
pub fn lua_rawgetp_(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_newuserdata(L: *mut lua_State, sz: usize) -> *mut c_void;
|
||||
pub fn lua_getmetatable(L: *mut lua_State, objindex: c_int) -> c_int;
|
||||
#[link_name = "lua_getuservalue"]
|
||||
pub fn lua_getuservalue_(L: *mut lua_State, idx: c_int);
|
||||
|
||||
//
|
||||
// Set functions (stack -> Lua)
|
||||
//
|
||||
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_setfield(L: *mut lua_State, idx: c_int, k: *const c_char);
|
||||
pub fn lua_rawset(L: *mut lua_State, idx: c_int);
|
||||
#[link_name = "lua_rawseti"]
|
||||
pub fn lua_rawseti_(L: *mut lua_State, idx: c_int, n: c_int);
|
||||
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_setuservalue(L: *mut lua_State, idx: c_int);
|
||||
|
||||
//
|
||||
// 'load' and 'call' functions (load and run Lua code)
|
||||
//
|
||||
pub fn lua_callk(
|
||||
L: *mut lua_State,
|
||||
nargs: c_int,
|
||||
nresults: c_int,
|
||||
ctx: c_int,
|
||||
k: Option<lua_CFunction>,
|
||||
);
|
||||
pub fn lua_pcallk(
|
||||
L: *mut lua_State,
|
||||
nargs: c_int,
|
||||
nresults: c_int,
|
||||
errfunc: c_int,
|
||||
ctx: c_int,
|
||||
k: Option<lua_CFunction>,
|
||||
) -> c_int;
|
||||
|
||||
pub fn lua_getctx(L: *mut lua_State, ctx: *mut c_int) -> c_int;
|
||||
|
||||
pub fn lua_load(
|
||||
L: *mut lua_State,
|
||||
reader: lua_Reader,
|
||||
data: *mut c_void,
|
||||
chunkname: *const c_char,
|
||||
mode: *const c_char,
|
||||
) -> c_int;
|
||||
#[link_name = "lua_dump"]
|
||||
pub fn lua_dump_(L: *mut lua_State, writer: lua_Writer, data: *mut c_void) -> c_int;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_call(L: *mut lua_State, n: c_int, r: c_int) {
|
||||
lua_callk(L, n, r, 0, None)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
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)
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// Coroutine functions
|
||||
//
|
||||
pub fn lua_yieldk(
|
||||
L: *mut lua_State,
|
||||
nresults: c_int,
|
||||
ctx: c_int,
|
||||
k: Option<lua_CFunction>,
|
||||
) -> c_int;
|
||||
#[link_name = "lua_resume"]
|
||||
pub fn lua_resume_(L: *mut lua_State, from: *mut lua_State, narg: c_int) -> c_int;
|
||||
pub fn lua_status(L: *mut lua_State) -> c_int;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_yield(L: *mut lua_State, n: c_int) -> c_int {
|
||||
lua_yieldk(L, n, 0, None)
|
||||
}
|
||||
|
||||
//
|
||||
// Garbage-collection function and options
|
||||
//
|
||||
pub const LUA_GCSTOP: c_int = 0;
|
||||
pub const LUA_GCRESTART: c_int = 1;
|
||||
pub const LUA_GCCOLLECT: c_int = 2;
|
||||
pub const LUA_GCCOUNT: c_int = 3;
|
||||
pub const LUA_GCCOUNTB: c_int = 4;
|
||||
pub const LUA_GCSTEP: c_int = 5;
|
||||
pub const LUA_GCSETPAUSE: c_int = 6;
|
||||
pub const LUA_GCSETSTEPMUL: c_int = 7;
|
||||
pub const LUA_GCSETMAJORINC: c_int = 8;
|
||||
pub const LUA_GCISRUNNING: c_int = 9;
|
||||
pub const LUA_GCGEN: c_int = 10;
|
||||
pub const LUA_GCINC: c_int = 11;
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// Miscellaneous functions
|
||||
//
|
||||
pub fn lua_error(L: *mut lua_State) -> !;
|
||||
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_len(L: *mut lua_State, idx: c_int);
|
||||
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);
|
||||
}
|
||||
|
||||
//
|
||||
// Some useful macros (implemented as Rust functions)
|
||||
//
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number {
|
||||
lua_tonumberx(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tointeger_(L: *mut lua_State, i: c_int) -> lua_Integer {
|
||||
lua_tointegerx_(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tounsigned(L: *mut lua_State, i: c_int) -> lua_Unsigned {
|
||||
lua_tounsignedx(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pop(L: *mut lua_State, n: c_int) {
|
||||
lua_settop(L, -n - 1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_newtable(L: *mut lua_State) {
|
||||
lua_createtable(L, 0, 0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_register(L: *mut lua_State, n: *const c_char, f: lua_CFunction) {
|
||||
lua_pushcfunction(L, f);
|
||||
lua_setglobal(L, n)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) {
|
||||
lua_pushcclosure(L, f, 0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isfunction(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TFUNCTION) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_istable(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TTABLE) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_islightuserdata(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TLIGHTUSERDATA) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TNIL) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isboolean(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TBOOLEAN) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isthread(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TTHREAD) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnone(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TNONE) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnoneornil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) <= 0) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) -> *const c_char {
|
||||
use std::ffi::CString;
|
||||
let c_str = CString::new(s).unwrap();
|
||||
lua_pushlstring_(L, c_str.as_ptr(), c_str.as_bytes().len())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
|
||||
lua_rawgeti_(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS as _)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char {
|
||||
lua_tolstring(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_xpush(from: *mut lua_State, to: *mut lua_State, idx: c_int) {
|
||||
lua_pushvalue(from, idx);
|
||||
lua_xmove(from, to, 1);
|
||||
}
|
||||
|
||||
//
|
||||
// Debug API
|
||||
//
|
||||
|
||||
// Maximum size for the description of the source of a function in debug information.
|
||||
const LUA_IDSIZE: usize = 60;
|
||||
|
||||
// Event codes
|
||||
pub const LUA_HOOKCALL: c_int = 0;
|
||||
pub const LUA_HOOKRET: c_int = 1;
|
||||
pub const LUA_HOOKLINE: c_int = 2;
|
||||
pub const LUA_HOOKCOUNT: c_int = 3;
|
||||
pub const LUA_HOOKTAILCALL: c_int = 4;
|
||||
|
||||
// Event masks
|
||||
pub const LUA_MASKCALL: c_int = 1 << (LUA_HOOKCALL as usize);
|
||||
pub const LUA_MASKRET: c_int = 1 << (LUA_HOOKRET as usize);
|
||||
pub const LUA_MASKLINE: c_int = 1 << (LUA_HOOKLINE as usize);
|
||||
pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
|
||||
|
||||
/// Type for functions to be called on debug events.
|
||||
pub type lua_Hook = unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug);
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_getstack(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getinfo(L: *mut lua_State, what: *const c_char, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getlocal(L: *mut lua_State, ar: *const lua_Debug, n: c_int) -> *const c_char;
|
||||
pub fn lua_setlocal(L: *mut lua_State, ar: *const lua_Debug, 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_upvalueid(L: *mut lua_State, fidx: c_int, n: c_int) -> *mut c_void;
|
||||
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: Option<lua_Hook>, mask: c_int, count: c_int);
|
||||
pub fn lua_gethook(L: *mut lua_State) -> Option<lua_Hook>;
|
||||
pub fn lua_gethookmask(L: *mut lua_State) -> c_int;
|
||||
pub fn lua_gethookcount(L: *mut lua_State) -> c_int;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct lua_Debug {
|
||||
pub event: c_int,
|
||||
pub name: *const c_char,
|
||||
pub namewhat: *const c_char,
|
||||
pub what: *const c_char,
|
||||
pub source: *const c_char,
|
||||
pub currentline: c_int,
|
||||
pub linedefined: c_int,
|
||||
pub lastlinedefined: c_int,
|
||||
pub nups: c_uchar,
|
||||
pub nparams: c_uchar,
|
||||
pub isvararg: c_char,
|
||||
pub istailcall: c_char,
|
||||
pub short_src: [c_char; LUA_IDSIZE],
|
||||
// lua.h mentions this is for private use
|
||||
i_ci: *mut c_void,
|
||||
}
|
31
src/ffi/lua52/lualib.rs
Normal file
31
src/ffi/lua52/lualib.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
//! Contains definitions from `lualib.h`.
|
||||
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use super::lua::lua_State;
|
||||
|
||||
pub const LUA_COLIBNAME: &str = "coroutine";
|
||||
pub const LUA_TABLIBNAME: &str = "table";
|
||||
pub const LUA_IOLIBNAME: &str = "io";
|
||||
pub const LUA_OSLIBNAME: &str = "os";
|
||||
pub const LUA_STRLIBNAME: &str = "string";
|
||||
pub const LUA_BITLIBNAME: &str = "bit32";
|
||||
pub const LUA_MATHLIBNAME: &str = "math";
|
||||
pub const LUA_DBLIBNAME: &str = "debug";
|
||||
pub const LUA_LOADLIBNAME: &str = "package";
|
||||
|
||||
extern "C" {
|
||||
pub fn luaopen_base(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_io(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_bit32(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_math(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_debug(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_package(L: *mut lua_State) -> c_int;
|
||||
|
||||
// open all builtin libraries
|
||||
pub fn luaL_openlibs(L: *mut lua_State);
|
||||
}
|
11
src/ffi/lua52/mod.rs
Normal file
11
src/ffi/lua52/mod.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
//! Low level bindings to Lua 5.2.
|
||||
|
||||
pub use compat::*;
|
||||
pub use lauxlib::*;
|
||||
pub use lua::*;
|
||||
pub use lualib::*;
|
||||
|
||||
pub mod compat;
|
||||
pub mod lauxlib;
|
||||
pub mod lua;
|
||||
pub mod lualib;
|
19
src/ffi/lua53/compat.rs
Normal file
19
src/ffi/lua53/compat.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
//! MLua compatibility layer for Lua 5.2
|
||||
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use super::lua::*;
|
||||
|
||||
#[inline(always)]
|
||||
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_(L, from, narg);
|
||||
if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
|
||||
*nres = lua_gettop(L);
|
||||
}
|
||||
ret
|
||||
}
|
184
src/ffi/lua53/lauxlib.rs
Normal file
184
src/ffi/lua53/lauxlib.rs
Normal file
|
@ -0,0 +1,184 @@
|
|||
//! Contains definitions from `lauxlib.h`.
|
||||
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::ptr;
|
||||
|
||||
use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State};
|
||||
|
||||
// Extra error code for 'luaL_loadfilex'
|
||||
pub const LUA_ERRFILE: c_int = lua::LUA_ERRERR + 1;
|
||||
|
||||
// Key, in the registry, for table of loaded modules
|
||||
pub const LUA_LOADED_TABLE: &str = "_LOADED";
|
||||
|
||||
// Key, in the registry, for table of preloaded loaders
|
||||
pub const LUA_PRELOAD_TABLE: &str = "_PRELOAD";
|
||||
|
||||
#[repr(C)]
|
||||
pub struct luaL_Reg {
|
||||
pub name: *const c_char,
|
||||
pub func: lua_CFunction,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number, sz: usize);
|
||||
|
||||
pub fn luaL_getmetafield(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_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, extramsg: *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_optlstring(
|
||||
L: *mut lua_State,
|
||||
arg: c_int,
|
||||
def: *const c_char,
|
||||
l: *mut usize,
|
||||
) -> *const c_char;
|
||||
pub fn luaL_checknumber(L: *mut lua_State, arg: c_int) -> lua_Number;
|
||||
pub fn luaL_optnumber(L: *mut lua_State, arg: c_int, def: lua_Number) -> lua_Number;
|
||||
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_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_checkany(L: *mut lua_State, arg: c_int);
|
||||
|
||||
pub fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int;
|
||||
pub fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char);
|
||||
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_where(L: *mut lua_State, lvl: c_int);
|
||||
pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> !;
|
||||
|
||||
pub fn luaL_checkoption(
|
||||
L: *mut lua_State,
|
||||
arg: c_int,
|
||||
def: *const c_char,
|
||||
lst: *const *const c_char,
|
||||
) -> c_int;
|
||||
|
||||
pub fn luaL_fileresult(L: *mut lua_State, stat: c_int, fname: *const c_char) -> c_int;
|
||||
pub fn luaL_execresult(L: *mut lua_State, stat: c_int) -> c_int;
|
||||
}
|
||||
|
||||
// Pre-defined references
|
||||
pub const LUA_NOREF: c_int = -2;
|
||||
pub const LUA_REFNIL: c_int = -1;
|
||||
|
||||
extern "C" {
|
||||
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#ref: c_int);
|
||||
|
||||
pub fn luaL_loadfilex(L: *mut lua_State, filename: *const c_char, mode: *const c_char)
|
||||
-> c_int;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
|
||||
luaL_loadfilex(L, f, ptr::null())
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn luaL_loadbufferx(
|
||||
L: *mut lua_State,
|
||||
buff: *const c_char,
|
||||
sz: usize,
|
||||
name: *const c_char,
|
||||
mode: *const c_char,
|
||||
) -> c_int;
|
||||
pub fn luaL_loadstring(L: *mut lua_State, s: *const c_char) -> c_int;
|
||||
|
||||
pub fn luaL_newstate() -> *mut lua_State;
|
||||
|
||||
pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer;
|
||||
|
||||
pub fn luaL_gsub(
|
||||
L: *mut lua_State,
|
||||
s: *const c_char,
|
||||
p: *const c_char,
|
||||
r: *const c_char,
|
||||
) -> *const c_char;
|
||||
|
||||
pub fn luaL_setfuncs(L: *mut lua_State, l: *const luaL_Reg, nup: c_int);
|
||||
|
||||
pub fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int;
|
||||
|
||||
pub fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, level: c_int);
|
||||
|
||||
pub fn luaL_requiref(
|
||||
L: *mut lua_State,
|
||||
modname: *const c_char,
|
||||
openf: lua_CFunction,
|
||||
glb: c_int,
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Some useful macros (implemented as Rust functions)
|
||||
//
|
||||
|
||||
// TODO: luaL_newlibtable, luaL_newlib
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_argcheck(L: *mut lua_State, cond: c_int, arg: c_int, extramsg: *const c_char) {
|
||||
if cond == 0 {
|
||||
luaL_argerror(L, arg, extramsg);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_checkstring(L: *mut lua_State, n: c_int) -> *const c_char {
|
||||
luaL_checklstring(L, n, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_optstring(L: *mut lua_State, n: c_int, d: *const c_char) -> *const c_char {
|
||||
luaL_optlstring(L, n, d, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_typename(L: *mut lua_State, i: c_int) -> *const c_char {
|
||||
lua::lua_typename(L, lua::lua_type(L, i))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_dofile(L: *mut lua_State, filename: *const c_char) -> c_int {
|
||||
let status = luaL_loadfile(L, filename);
|
||||
if status == 0 {
|
||||
lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
|
||||
} else {
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_dostring(L: *mut lua_State, s: *const c_char) -> c_int {
|
||||
let status = luaL_loadstring(L, s);
|
||||
if status == 0 {
|
||||
lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
|
||||
} else {
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
|
||||
lua::lua_getfield(L, lua::LUA_REGISTRYINDEX, n);
|
||||
}
|
||||
|
||||
// luaL_opt would be implemented here but it is undocumented, so it's omitted
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_loadbuffer(
|
||||
L: *mut lua_State,
|
||||
s: *const c_char,
|
||||
sz: usize,
|
||||
n: *const c_char,
|
||||
) -> c_int {
|
||||
luaL_loadbufferx(L, s, sz, n, ptr::null())
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: Generic Buffer Manipulation
|
||||
//
|
500
src/ffi/lua53/lua.rs
Normal file
500
src/ffi/lua53/lua.rs
Normal file
|
@ -0,0 +1,500 @@
|
|||
//! Contains definitions from `lua.h`.
|
||||
|
||||
use std::marker::{PhantomData, PhantomPinned};
|
||||
use std::mem;
|
||||
use std::os::raw::{c_char, c_double, c_int, c_uchar, c_void};
|
||||
use std::ptr;
|
||||
|
||||
// Mark for precompiled code (`<esc>Lua`)
|
||||
pub const LUA_SIGNATURE: &[u8] = b"\x1bLua";
|
||||
|
||||
// Option for multiple returns in 'lua_pcall' and 'lua_call'
|
||||
pub const LUA_MULTRET: c_int = -1;
|
||||
|
||||
// Size of the Lua stack
|
||||
pub const LUAI_MAXSTACK: c_int = 1000000;
|
||||
|
||||
// Size of a raw memory area associated with a Lua state with very fast access.
|
||||
pub const LUA_EXTRASPACE: usize = mem::size_of::<*const ()>();
|
||||
|
||||
//
|
||||
// Pseudo-indices
|
||||
//
|
||||
pub const LUA_REGISTRYINDEX: c_int = -LUAI_MAXSTACK - 1000;
|
||||
|
||||
pub const fn lua_upvalueindex(i: c_int) -> c_int {
|
||||
LUA_REGISTRYINDEX - i
|
||||
}
|
||||
|
||||
//
|
||||
// Thread status
|
||||
//
|
||||
pub const LUA_OK: c_int = 0;
|
||||
pub const LUA_YIELD: c_int = 1;
|
||||
pub const LUA_ERRRUN: c_int = 2;
|
||||
pub const LUA_ERRSYNTAX: c_int = 3;
|
||||
pub const LUA_ERRMEM: c_int = 4;
|
||||
pub const LUA_ERRGCMM: c_int = 5;
|
||||
pub const LUA_ERRERR: c_int = 6;
|
||||
|
||||
/// A raw Lua state associated with a thread.
|
||||
#[repr(C)]
|
||||
pub struct lua_State {
|
||||
_data: [u8; 0],
|
||||
_marker: PhantomData<(*mut u8, PhantomPinned)>,
|
||||
}
|
||||
|
||||
//
|
||||
// Basic types
|
||||
//
|
||||
pub const LUA_TNONE: c_int = -1;
|
||||
|
||||
pub const LUA_TNIL: c_int = 0;
|
||||
pub const LUA_TBOOLEAN: c_int = 1;
|
||||
pub const LUA_TLIGHTUSERDATA: c_int = 2;
|
||||
pub const LUA_TNUMBER: c_int = 3;
|
||||
pub const LUA_TSTRING: c_int = 4;
|
||||
pub const LUA_TTABLE: c_int = 5;
|
||||
pub const LUA_TFUNCTION: c_int = 6;
|
||||
pub const LUA_TUSERDATA: c_int = 7;
|
||||
pub const LUA_TTHREAD: c_int = 8;
|
||||
|
||||
pub const LUA_NUMTAGS: c_int = 9;
|
||||
|
||||
/// Minimum Lua stack available to a C function
|
||||
pub const LUA_MINSTACK: c_int = 20;
|
||||
|
||||
// Predefined values in the registry
|
||||
pub const LUA_RIDX_MAINTHREAD: lua_Integer = 1;
|
||||
pub const LUA_RIDX_GLOBALS: lua_Integer = 2;
|
||||
pub const LUA_RIDX_LAST: lua_Integer = LUA_RIDX_GLOBALS;
|
||||
|
||||
/// A Lua number, usually equivalent to `f64`
|
||||
pub type lua_Number = c_double;
|
||||
|
||||
/// A Lua integer, usually equivalent to `i64`
|
||||
pub type lua_Integer = i64;
|
||||
|
||||
/// A Lua unsigned integer, usually equivalent to `u64`
|
||||
pub type lua_Unsigned = u64;
|
||||
|
||||
/// Type for continuation-function contexts
|
||||
pub type lua_KContext = isize;
|
||||
|
||||
/// Type for native C functions that can be passed to Lua
|
||||
pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int;
|
||||
|
||||
/// Type for continuation functions
|
||||
pub type lua_KFunction =
|
||||
unsafe extern "C" fn(L: *mut lua_State, status: c_int, ctx: lua_KContext) -> c_int;
|
||||
|
||||
// Type for functions that read/write blocks when loading/dumping Lua chunks
|
||||
pub type lua_Reader =
|
||||
unsafe extern "C" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char;
|
||||
pub type lua_Writer =
|
||||
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
|
||||
pub type lua_Alloc = unsafe extern "C" fn(
|
||||
ud: *mut c_void,
|
||||
ptr: *mut c_void,
|
||||
osize: usize,
|
||||
nsize: usize,
|
||||
) -> *mut c_void;
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// State manipulation
|
||||
//
|
||||
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_newthread(L: *mut lua_State) -> *mut lua_State;
|
||||
|
||||
pub fn lua_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction;
|
||||
|
||||
pub fn lua_version(L: *mut lua_State) -> *const lua_Number;
|
||||
|
||||
//
|
||||
// Basic stack manipulation
|
||||
//
|
||||
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_settop(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_pushvalue(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_rotate(L: *mut lua_State, idx: c_int, n: 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_xmove(from: *mut lua_State, to: *mut lua_State, n: c_int);
|
||||
|
||||
//
|
||||
// Access functions (stack -> C)
|
||||
//
|
||||
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_iscfunction(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_type(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_typename(L: *mut lua_State, tp: c_int) -> *const c_char;
|
||||
|
||||
pub fn lua_tonumberx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Number;
|
||||
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_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char;
|
||||
pub fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize;
|
||||
pub fn lua_tocfunction(L: *mut lua_State, idx: c_int) -> Option<lua_CFunction>;
|
||||
pub fn lua_touserdata(L: *mut lua_State, idx: c_int) -> *mut c_void;
|
||||
pub fn lua_tothread(L: *mut lua_State, idx: c_int) -> *mut lua_State;
|
||||
pub fn lua_topointer(L: *mut lua_State, idx: c_int) -> *const c_void;
|
||||
}
|
||||
|
||||
//
|
||||
// Comparison and arithmetic functions
|
||||
//
|
||||
pub const LUA_OPADD: c_int = 0;
|
||||
pub const LUA_OPSUB: c_int = 1;
|
||||
pub const LUA_OPMUL: c_int = 2;
|
||||
pub const LUA_OPMOD: c_int = 3;
|
||||
pub const LUA_OPPOW: c_int = 4;
|
||||
pub const LUA_OPDIV: c_int = 5;
|
||||
pub const LUA_OPIDIV: c_int = 6;
|
||||
pub const LUA_OPBAND: c_int = 7;
|
||||
pub const LUA_OPBOR: c_int = 8;
|
||||
pub const LUA_OPBXOR: c_int = 9;
|
||||
pub const LUA_OPSHL: c_int = 10;
|
||||
pub const LUA_OPSHR: c_int = 11;
|
||||
pub const LUA_OPUNM: c_int = 12;
|
||||
pub const LUA_OPBNOT: c_int = 13;
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_arith(L: *mut lua_State, op: c_int);
|
||||
}
|
||||
|
||||
pub const LUA_OPEQ: c_int = 0;
|
||||
pub const LUA_OPLT: c_int = 1;
|
||||
pub const LUA_OPLE: c_int = 2;
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_rawequal(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
||||
pub fn lua_compare(L: *mut lua_State, idx1: c_int, idx2: c_int, op: c_int) -> c_int;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// Push functions (C -> stack)
|
||||
//
|
||||
pub fn lua_pushnil(L: *mut lua_State);
|
||||
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_pushlstring(L: *mut lua_State, s: *const c_char, len: usize) -> *const c_char;
|
||||
pub fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char;
|
||||
// lua_pushvfstring
|
||||
pub fn lua_pushfstring(L: *mut lua_State, fmt: *const c_char, ...) -> *const c_char;
|
||||
pub fn lua_pushcclosure(L: *mut lua_State, f: lua_CFunction, n: c_int);
|
||||
pub fn lua_pushboolean(L: *mut lua_State, b: c_int);
|
||||
pub fn lua_pushlightuserdata(L: *mut lua_State, p: *mut c_void);
|
||||
pub fn lua_pushthread(L: *mut lua_State) -> c_int;
|
||||
|
||||
//
|
||||
// Get functions (Lua -> stack)
|
||||
//
|
||||
pub fn lua_getglobal(L: *mut lua_State, name: *const c_char) -> c_int;
|
||||
pub fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int;
|
||||
pub fn lua_geti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int;
|
||||
pub fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int;
|
||||
pub fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int;
|
||||
|
||||
pub fn lua_createtable(L: *mut lua_State, narr: c_int, nrec: c_int);
|
||||
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_getuservalue(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
|
||||
//
|
||||
// Set functions (stack -> Lua)
|
||||
//
|
||||
pub fn lua_setglobal(L: *mut lua_State, name: *const c_char);
|
||||
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_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_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer);
|
||||
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_setuservalue(L: *mut lua_State, idx: c_int);
|
||||
|
||||
//
|
||||
// 'load' and 'call' functions (load and run Lua code)
|
||||
//
|
||||
pub fn lua_callk(
|
||||
L: *mut lua_State,
|
||||
nargs: c_int,
|
||||
nresults: c_int,
|
||||
ctx: lua_KContext,
|
||||
k: Option<lua_KFunction>,
|
||||
);
|
||||
pub fn lua_pcallk(
|
||||
L: *mut lua_State,
|
||||
nargs: c_int,
|
||||
nresults: c_int,
|
||||
errfunc: c_int,
|
||||
ctx: lua_KContext,
|
||||
k: Option<lua_KFunction>,
|
||||
) -> c_int;
|
||||
|
||||
pub fn lua_load(
|
||||
L: *mut lua_State,
|
||||
reader: lua_Reader,
|
||||
data: *mut c_void,
|
||||
chunkname: *const c_char,
|
||||
mode: *const c_char,
|
||||
) -> c_int;
|
||||
|
||||
pub fn lua_dump(
|
||||
L: *mut lua_State,
|
||||
writer: lua_Writer,
|
||||
data: *mut c_void,
|
||||
strip: c_int,
|
||||
) -> c_int;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_call(L: *mut lua_State, n: c_int, r: c_int) {
|
||||
lua_callk(L, n, r, 0, None)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
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)
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// Coroutine functions
|
||||
//
|
||||
pub fn lua_yieldk(
|
||||
L: *mut lua_State,
|
||||
nresults: c_int,
|
||||
ctx: lua_KContext,
|
||||
k: Option<lua_KFunction>,
|
||||
) -> c_int;
|
||||
#[link_name = "lua_resume"]
|
||||
pub fn lua_resume_(L: *mut lua_State, from: *mut lua_State, narg: c_int) -> c_int;
|
||||
pub fn lua_status(L: *mut lua_State) -> c_int;
|
||||
pub fn lua_isyieldable(L: *mut lua_State) -> c_int;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_yield(L: *mut lua_State, n: c_int) -> c_int {
|
||||
lua_yieldk(L, n, 0, None)
|
||||
}
|
||||
|
||||
//
|
||||
// Garbage-collection function and options
|
||||
//
|
||||
pub const LUA_GCSTOP: c_int = 0;
|
||||
pub const LUA_GCRESTART: c_int = 1;
|
||||
pub const LUA_GCCOLLECT: c_int = 2;
|
||||
pub const LUA_GCCOUNT: c_int = 3;
|
||||
pub const LUA_GCCOUNTB: c_int = 4;
|
||||
pub const LUA_GCSTEP: c_int = 5;
|
||||
pub const LUA_GCSETPAUSE: c_int = 6;
|
||||
pub const LUA_GCSETSTEPMUL: c_int = 7;
|
||||
pub const LUA_GCISRUNNING: c_int = 9;
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// Miscellaneous functions
|
||||
//
|
||||
pub fn lua_error(L: *mut lua_State) -> !;
|
||||
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_len(L: *mut lua_State, idx: c_int);
|
||||
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_setallocf(L: *mut lua_State, f: lua_Alloc, ud: *mut c_void);
|
||||
}
|
||||
|
||||
//
|
||||
// Some useful macros (implemented as Rust functions)
|
||||
//
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
|
||||
(L as *mut c_char).sub(LUA_EXTRASPACE) as *mut c_void
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number {
|
||||
lua_tonumberx(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
|
||||
lua_tointegerx(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pop(L: *mut lua_State, n: c_int) {
|
||||
lua_settop(L, -n - 1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_newtable(L: *mut lua_State) {
|
||||
lua_createtable(L, 0, 0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_register(L: *mut lua_State, n: *const c_char, f: lua_CFunction) {
|
||||
lua_pushcfunction(L, f);
|
||||
lua_setglobal(L, n)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) {
|
||||
lua_pushcclosure(L, f, 0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isfunction(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TFUNCTION) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_istable(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TTABLE) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_islightuserdata(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TLIGHTUSERDATA) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TNIL) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isboolean(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TBOOLEAN) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isthread(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TTHREAD) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnone(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TNONE) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnoneornil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) <= 0) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) -> *const c_char {
|
||||
use std::ffi::CString;
|
||||
let c_str = CString::new(s).unwrap();
|
||||
lua_pushlstring(L, c_str.as_ptr(), c_str.as_bytes().len())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushglobaltable(L: *mut lua_State) -> c_int {
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char {
|
||||
lua_tolstring(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_insert(L: *mut lua_State, idx: c_int) {
|
||||
lua_rotate(L, idx, 1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_remove(L: *mut lua_State, idx: c_int) {
|
||||
lua_rotate(L, idx, -1);
|
||||
lua_pop(L, 1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_replace(L: *mut lua_State, idx: c_int) {
|
||||
lua_copy(L, -1, idx);
|
||||
lua_pop(L, 1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_xpush(from: *mut lua_State, to: *mut lua_State, idx: c_int) {
|
||||
lua_pushvalue(from, idx);
|
||||
lua_xmove(from, to, 1);
|
||||
}
|
||||
|
||||
//
|
||||
// Debug API
|
||||
//
|
||||
|
||||
// Maximum size for the description of the source of a function in debug information.
|
||||
const LUA_IDSIZE: usize = 60;
|
||||
|
||||
// Event codes
|
||||
pub const LUA_HOOKCALL: c_int = 0;
|
||||
pub const LUA_HOOKRET: c_int = 1;
|
||||
pub const LUA_HOOKLINE: c_int = 2;
|
||||
pub const LUA_HOOKCOUNT: c_int = 3;
|
||||
pub const LUA_HOOKTAILCALL: c_int = 4;
|
||||
|
||||
// Event masks
|
||||
pub const LUA_MASKCALL: c_int = 1 << (LUA_HOOKCALL as usize);
|
||||
pub const LUA_MASKRET: c_int = 1 << (LUA_HOOKRET as usize);
|
||||
pub const LUA_MASKLINE: c_int = 1 << (LUA_HOOKLINE as usize);
|
||||
pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
|
||||
|
||||
/// Type for functions to be called on debug events.
|
||||
pub type lua_Hook = unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug);
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_getstack(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getinfo(L: *mut lua_State, what: *const c_char, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getlocal(L: *mut lua_State, ar: *const lua_Debug, n: c_int) -> *const c_char;
|
||||
pub fn lua_setlocal(L: *mut lua_State, ar: *const lua_Debug, 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_upvalueid(L: *mut lua_State, fidx: c_int, n: c_int) -> *mut c_void;
|
||||
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: Option<lua_Hook>, mask: c_int, count: c_int);
|
||||
pub fn lua_gethook(L: *mut lua_State) -> Option<lua_Hook>;
|
||||
pub fn lua_gethookmask(L: *mut lua_State) -> c_int;
|
||||
pub fn lua_gethookcount(L: *mut lua_State) -> c_int;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct lua_Debug {
|
||||
pub event: c_int,
|
||||
pub name: *const c_char,
|
||||
pub namewhat: *const c_char,
|
||||
pub what: *const c_char,
|
||||
pub source: *const c_char,
|
||||
pub currentline: c_int,
|
||||
pub linedefined: c_int,
|
||||
pub lastlinedefined: c_int,
|
||||
pub nups: c_uchar,
|
||||
pub nparams: c_uchar,
|
||||
pub isvararg: c_char,
|
||||
pub istailcall: c_char,
|
||||
pub short_src: [c_char; LUA_IDSIZE],
|
||||
// lua.h mentions this is for private use
|
||||
i_ci: *mut c_void,
|
||||
}
|
33
src/ffi/lua53/lualib.rs
Normal file
33
src/ffi/lua53/lualib.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
//! Contains definitions from `lualib.h`.
|
||||
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use super::lua::lua_State;
|
||||
|
||||
pub const LUA_COLIBNAME: &str = "coroutine";
|
||||
pub const LUA_TABLIBNAME: &str = "table";
|
||||
pub const LUA_IOLIBNAME: &str = "io";
|
||||
pub const LUA_OSLIBNAME: &str = "os";
|
||||
pub const LUA_STRLIBNAME: &str = "string";
|
||||
pub const LUA_UTF8LIBNAME: &str = "utf8";
|
||||
pub const LUA_BITLIBNAME: &str = "bit32";
|
||||
pub const LUA_MATHLIBNAME: &str = "math";
|
||||
pub const LUA_DBLIBNAME: &str = "debug";
|
||||
pub const LUA_LOADLIBNAME: &str = "package";
|
||||
|
||||
extern "C" {
|
||||
pub fn luaopen_base(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_io(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_utf8(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_bit32(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_math(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_debug(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_package(L: *mut lua_State) -> c_int;
|
||||
|
||||
// open all builtin libraries
|
||||
pub fn luaL_openlibs(L: *mut lua_State);
|
||||
}
|
11
src/ffi/lua53/mod.rs
Normal file
11
src/ffi/lua53/mod.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
//! Low level bindings to Lua 5.3.
|
||||
|
||||
pub use compat::*;
|
||||
pub use lauxlib::*;
|
||||
pub use lua::*;
|
||||
pub use lualib::*;
|
||||
|
||||
pub mod compat;
|
||||
pub mod lauxlib;
|
||||
pub mod lua;
|
||||
pub mod lualib;
|
186
src/ffi/lua54/lauxlib.rs
Normal file
186
src/ffi/lua54/lauxlib.rs
Normal file
|
@ -0,0 +1,186 @@
|
|||
//! Contains definitions from `lauxlib.h`.
|
||||
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::ptr;
|
||||
|
||||
use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State};
|
||||
|
||||
// Extra error code for 'luaL_loadfilex'
|
||||
pub const LUA_ERRFILE: c_int = lua::LUA_ERRERR + 1;
|
||||
|
||||
// Key, in the registry, for table of loaded modules
|
||||
pub const LUA_LOADED_TABLE: &str = "_LOADED";
|
||||
|
||||
// Key, in the registry, for table of preloaded loaders
|
||||
pub const LUA_PRELOAD_TABLE: &str = "_PRELOAD";
|
||||
|
||||
#[repr(C)]
|
||||
pub struct luaL_Reg {
|
||||
pub name: *const c_char,
|
||||
pub func: lua_CFunction,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number, sz: usize);
|
||||
|
||||
pub fn luaL_getmetafield(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_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, extramsg: *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_optlstring(
|
||||
L: *mut lua_State,
|
||||
arg: c_int,
|
||||
def: *const c_char,
|
||||
l: *mut usize,
|
||||
) -> *const c_char;
|
||||
pub fn luaL_checknumber(L: *mut lua_State, arg: c_int) -> lua_Number;
|
||||
pub fn luaL_optnumber(L: *mut lua_State, arg: c_int, def: lua_Number) -> lua_Number;
|
||||
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_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_checkany(L: *mut lua_State, arg: c_int);
|
||||
|
||||
pub fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int;
|
||||
pub fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char);
|
||||
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_where(L: *mut lua_State, lvl: c_int);
|
||||
pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> !;
|
||||
|
||||
pub fn luaL_checkoption(
|
||||
L: *mut lua_State,
|
||||
arg: c_int,
|
||||
def: *const c_char,
|
||||
lst: *const *const c_char,
|
||||
) -> c_int;
|
||||
|
||||
pub fn luaL_fileresult(L: *mut lua_State, stat: c_int, fname: *const c_char) -> c_int;
|
||||
pub fn luaL_execresult(L: *mut lua_State, stat: c_int) -> c_int;
|
||||
}
|
||||
|
||||
// Pre-defined references
|
||||
pub const LUA_NOREF: c_int = -2;
|
||||
pub const LUA_REFNIL: c_int = -1;
|
||||
|
||||
extern "C" {
|
||||
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#ref: c_int);
|
||||
|
||||
pub fn luaL_loadfilex(L: *mut lua_State, filename: *const c_char, mode: *const c_char)
|
||||
-> c_int;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
|
||||
luaL_loadfilex(L, f, ptr::null())
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn luaL_loadbufferx(
|
||||
L: *mut lua_State,
|
||||
buff: *const c_char,
|
||||
sz: usize,
|
||||
name: *const c_char,
|
||||
mode: *const c_char,
|
||||
) -> c_int;
|
||||
pub fn luaL_loadstring(L: *mut lua_State, s: *const c_char) -> c_int;
|
||||
|
||||
pub fn luaL_newstate() -> *mut lua_State;
|
||||
|
||||
pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer;
|
||||
|
||||
// TODO: luaL_addgsub
|
||||
|
||||
pub fn luaL_gsub(
|
||||
L: *mut lua_State,
|
||||
s: *const c_char,
|
||||
p: *const c_char,
|
||||
r: *const c_char,
|
||||
) -> *const c_char;
|
||||
|
||||
pub fn luaL_setfuncs(L: *mut lua_State, l: *const luaL_Reg, nup: c_int);
|
||||
|
||||
pub fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int;
|
||||
|
||||
pub fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, level: c_int);
|
||||
|
||||
pub fn luaL_requiref(
|
||||
L: *mut lua_State,
|
||||
modname: *const c_char,
|
||||
openf: lua_CFunction,
|
||||
glb: c_int,
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Some useful macros (implemented as Rust functions)
|
||||
//
|
||||
|
||||
// TODO: luaL_newlibtable, luaL_newlib
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_argcheck(L: *mut lua_State, cond: c_int, arg: c_int, extramsg: *const c_char) {
|
||||
if cond == 0 {
|
||||
luaL_argerror(L, arg, extramsg);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_checkstring(L: *mut lua_State, n: c_int) -> *const c_char {
|
||||
luaL_checklstring(L, n, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_optstring(L: *mut lua_State, n: c_int, d: *const c_char) -> *const c_char {
|
||||
luaL_optlstring(L, n, d, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_typename(L: *mut lua_State, i: c_int) -> *const c_char {
|
||||
lua::lua_typename(L, lua::lua_type(L, i))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_dofile(L: *mut lua_State, filename: *const c_char) -> c_int {
|
||||
let status = luaL_loadfile(L, filename);
|
||||
if status == 0 {
|
||||
lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
|
||||
} else {
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_dostring(L: *mut lua_State, s: *const c_char) -> c_int {
|
||||
let status = luaL_loadstring(L, s);
|
||||
if status == 0 {
|
||||
lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
|
||||
} else {
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
|
||||
lua::lua_getfield(L, lua::LUA_REGISTRYINDEX, n);
|
||||
}
|
||||
|
||||
// luaL_opt would be implemented here but it is undocumented, so it's omitted
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_loadbuffer(
|
||||
L: *mut lua_State,
|
||||
s: *const c_char,
|
||||
sz: usize,
|
||||
n: *const c_char,
|
||||
) -> c_int {
|
||||
luaL_loadbufferx(L, s, sz, n, ptr::null())
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: Generic Buffer Manipulation
|
||||
//
|
539
src/ffi/lua54/lua.rs
Normal file
539
src/ffi/lua54/lua.rs
Normal file
|
@ -0,0 +1,539 @@
|
|||
//! Contains definitions from `lua.h`.
|
||||
|
||||
use std::marker::{PhantomData, PhantomPinned};
|
||||
use std::mem;
|
||||
use std::os::raw::{c_char, c_double, c_int, c_uchar, c_ushort, c_void};
|
||||
use std::ptr;
|
||||
|
||||
// Mark for precompiled code (`<esc>Lua`)
|
||||
pub const LUA_SIGNATURE: &[u8] = b"\x1bLua";
|
||||
|
||||
// Option for multiple returns in 'lua_pcall' and 'lua_call'
|
||||
pub const LUA_MULTRET: c_int = -1;
|
||||
|
||||
// Size of the Lua stack
|
||||
pub const LUAI_MAXSTACK: c_int = 1000000;
|
||||
|
||||
// Size of a raw memory area associated with a Lua state with very fast access.
|
||||
pub const LUA_EXTRASPACE: usize = mem::size_of::<*const ()>();
|
||||
|
||||
//
|
||||
// Pseudo-indices
|
||||
//
|
||||
pub const LUA_REGISTRYINDEX: c_int = -LUAI_MAXSTACK - 1000;
|
||||
|
||||
pub const fn lua_upvalueindex(i: c_int) -> c_int {
|
||||
LUA_REGISTRYINDEX - i
|
||||
}
|
||||
|
||||
//
|
||||
// Thread status
|
||||
//
|
||||
pub const LUA_OK: c_int = 0;
|
||||
pub const LUA_YIELD: c_int = 1;
|
||||
pub const LUA_ERRRUN: c_int = 2;
|
||||
pub const LUA_ERRSYNTAX: c_int = 3;
|
||||
pub const LUA_ERRMEM: c_int = 4;
|
||||
pub const LUA_ERRERR: c_int = 5;
|
||||
|
||||
/// A raw Lua state associated with a thread.
|
||||
#[repr(C)]
|
||||
pub struct lua_State {
|
||||
_data: [u8; 0],
|
||||
_marker: PhantomData<(*mut u8, PhantomPinned)>,
|
||||
}
|
||||
|
||||
//
|
||||
// Basic types
|
||||
//
|
||||
pub const LUA_TNONE: c_int = -1;
|
||||
|
||||
pub const LUA_TNIL: c_int = 0;
|
||||
pub const LUA_TBOOLEAN: c_int = 1;
|
||||
pub const LUA_TLIGHTUSERDATA: c_int = 2;
|
||||
pub const LUA_TNUMBER: c_int = 3;
|
||||
pub const LUA_TSTRING: c_int = 4;
|
||||
pub const LUA_TTABLE: c_int = 5;
|
||||
pub const LUA_TFUNCTION: c_int = 6;
|
||||
pub const LUA_TUSERDATA: c_int = 7;
|
||||
pub const LUA_TTHREAD: c_int = 8;
|
||||
|
||||
pub const LUA_NUMTYPES: c_int = 9;
|
||||
|
||||
/// Minimum Lua stack available to a C function
|
||||
pub const LUA_MINSTACK: c_int = 20;
|
||||
|
||||
// Predefined values in the registry
|
||||
pub const LUA_RIDX_MAINTHREAD: lua_Integer = 1;
|
||||
pub const LUA_RIDX_GLOBALS: lua_Integer = 2;
|
||||
pub const LUA_RIDX_LAST: lua_Integer = LUA_RIDX_GLOBALS;
|
||||
|
||||
/// A Lua number, usually equivalent to `f64`
|
||||
pub type lua_Number = c_double;
|
||||
|
||||
/// A Lua integer, usually equivalent to `i64`
|
||||
pub type lua_Integer = i64;
|
||||
|
||||
/// A Lua unsigned integer, usually equivalent to `u64`
|
||||
pub type lua_Unsigned = u64;
|
||||
|
||||
/// Type for continuation-function contexts
|
||||
pub type lua_KContext = isize;
|
||||
|
||||
/// Type for native C functions that can be passed to Lua
|
||||
pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int;
|
||||
|
||||
/// Type for continuation functions
|
||||
pub type lua_KFunction =
|
||||
unsafe extern "C" fn(L: *mut lua_State, status: c_int, ctx: lua_KContext) -> c_int;
|
||||
|
||||
// Type for functions that read/write blocks when loading/dumping Lua chunks
|
||||
pub type lua_Reader =
|
||||
unsafe extern "C" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char;
|
||||
pub type lua_Writer =
|
||||
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
|
||||
pub type lua_Alloc = unsafe extern "C" fn(
|
||||
ud: *mut c_void,
|
||||
ptr: *mut c_void,
|
||||
osize: usize,
|
||||
nsize: usize,
|
||||
) -> *mut c_void;
|
||||
|
||||
/// Type for warning functions
|
||||
pub type lua_WarnFunction =
|
||||
unsafe extern "C" fn(ud: *mut c_void, msg: *const c_char, tocont: c_int);
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// State manipulation
|
||||
//
|
||||
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_newthread(L: *mut lua_State) -> *mut lua_State;
|
||||
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_version(L: *mut lua_State) -> lua_Number;
|
||||
|
||||
//
|
||||
// Basic stack manipulation
|
||||
//
|
||||
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_settop(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_pushvalue(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_rotate(L: *mut lua_State, idx: c_int, n: 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_xmove(from: *mut lua_State, to: *mut lua_State, n: c_int);
|
||||
|
||||
//
|
||||
// Access functions (stack -> C)
|
||||
//
|
||||
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_iscfunction(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_type(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_typename(L: *mut lua_State, tp: c_int) -> *const c_char;
|
||||
|
||||
pub fn lua_tonumberx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Number;
|
||||
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_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char;
|
||||
pub fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize;
|
||||
pub fn lua_tocfunction(L: *mut lua_State, idx: c_int) -> Option<lua_CFunction>;
|
||||
pub fn lua_touserdata(L: *mut lua_State, idx: c_int) -> *mut c_void;
|
||||
pub fn lua_tothread(L: *mut lua_State, idx: c_int) -> *mut lua_State;
|
||||
pub fn lua_topointer(L: *mut lua_State, idx: c_int) -> *const c_void;
|
||||
}
|
||||
|
||||
//
|
||||
// Comparison and arithmetic functions
|
||||
//
|
||||
pub const LUA_OPADD: c_int = 0;
|
||||
pub const LUA_OPSUB: c_int = 1;
|
||||
pub const LUA_OPMUL: c_int = 2;
|
||||
pub const LUA_OPMOD: c_int = 3;
|
||||
pub const LUA_OPPOW: c_int = 4;
|
||||
pub const LUA_OPDIV: c_int = 5;
|
||||
pub const LUA_OPIDIV: c_int = 6;
|
||||
pub const LUA_OPBAND: c_int = 7;
|
||||
pub const LUA_OPBOR: c_int = 8;
|
||||
pub const LUA_OPBXOR: c_int = 9;
|
||||
pub const LUA_OPSHL: c_int = 10;
|
||||
pub const LUA_OPSHR: c_int = 11;
|
||||
pub const LUA_OPUNM: c_int = 12;
|
||||
pub const LUA_OPBNOT: c_int = 13;
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_arith(L: *mut lua_State, op: c_int);
|
||||
}
|
||||
|
||||
pub const LUA_OPEQ: c_int = 0;
|
||||
pub const LUA_OPLT: c_int = 1;
|
||||
pub const LUA_OPLE: c_int = 2;
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_rawequal(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
||||
pub fn lua_compare(L: *mut lua_State, idx1: c_int, idx2: c_int, op: c_int) -> c_int;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// Push functions (C -> stack)
|
||||
//
|
||||
pub fn lua_pushnil(L: *mut lua_State);
|
||||
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_pushlstring(L: *mut lua_State, s: *const c_char, len: usize) -> *const c_char;
|
||||
pub fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char;
|
||||
// lua_pushvfstring
|
||||
pub fn lua_pushfstring(L: *mut lua_State, fmt: *const c_char, ...) -> *const c_char;
|
||||
pub fn lua_pushcclosure(L: *mut lua_State, f: lua_CFunction, n: c_int);
|
||||
pub fn lua_pushboolean(L: *mut lua_State, b: c_int);
|
||||
pub fn lua_pushlightuserdata(L: *mut lua_State, p: *mut c_void);
|
||||
pub fn lua_pushthread(L: *mut lua_State) -> c_int;
|
||||
|
||||
//
|
||||
// Get functions (Lua -> stack)
|
||||
//
|
||||
pub fn lua_getglobal(L: *mut lua_State, name: *const c_char) -> c_int;
|
||||
pub fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int;
|
||||
pub fn lua_geti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int;
|
||||
pub fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int;
|
||||
pub fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int;
|
||||
|
||||
pub fn lua_createtable(L: *mut lua_State, narr: c_int, nrec: c_int);
|
||||
pub fn lua_newuserdatauv(L: *mut lua_State, sz: usize, nuvalue: c_int) -> *mut c_void;
|
||||
pub fn lua_getmetatable(L: *mut lua_State, objindex: c_int) -> c_int;
|
||||
pub fn lua_getiuservalue(L: *mut lua_State, idx: c_int, n: c_int) -> c_int;
|
||||
|
||||
//
|
||||
// Set functions (stack -> Lua)
|
||||
//
|
||||
pub fn lua_setglobal(L: *mut lua_State, name: *const c_char);
|
||||
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_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_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer);
|
||||
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_setiuservalue(L: *mut lua_State, idx: c_int, n: c_int) -> c_int;
|
||||
|
||||
//
|
||||
// 'load' and 'call' functions (load and run Lua code)
|
||||
//
|
||||
pub fn lua_callk(
|
||||
L: *mut lua_State,
|
||||
nargs: c_int,
|
||||
nresults: c_int,
|
||||
ctx: lua_KContext,
|
||||
k: Option<lua_KFunction>,
|
||||
);
|
||||
pub fn lua_pcallk(
|
||||
L: *mut lua_State,
|
||||
nargs: c_int,
|
||||
nresults: c_int,
|
||||
errfunc: c_int,
|
||||
ctx: lua_KContext,
|
||||
k: Option<lua_KFunction>,
|
||||
) -> c_int;
|
||||
|
||||
pub fn lua_load(
|
||||
L: *mut lua_State,
|
||||
reader: lua_Reader,
|
||||
data: *mut c_void,
|
||||
chunkname: *const c_char,
|
||||
mode: *const c_char,
|
||||
) -> c_int;
|
||||
|
||||
pub fn lua_dump(
|
||||
L: *mut lua_State,
|
||||
writer: lua_Writer,
|
||||
data: *mut c_void,
|
||||
strip: c_int,
|
||||
) -> c_int;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_call(L: *mut lua_State, n: c_int, r: c_int) {
|
||||
lua_callk(L, n, r, 0, None)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
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)
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// Coroutine functions
|
||||
//
|
||||
pub fn lua_yieldk(
|
||||
L: *mut lua_State,
|
||||
nresults: c_int,
|
||||
ctx: lua_KContext,
|
||||
k: Option<lua_KFunction>,
|
||||
) -> c_int;
|
||||
pub fn lua_resume(
|
||||
L: *mut lua_State,
|
||||
from: *mut lua_State,
|
||||
narg: c_int,
|
||||
nres: *mut c_int,
|
||||
) -> c_int;
|
||||
pub fn lua_status(L: *mut lua_State) -> c_int;
|
||||
pub fn lua_isyieldable(L: *mut lua_State) -> c_int;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_yield(L: *mut lua_State, n: c_int) -> c_int {
|
||||
lua_yieldk(L, n, 0, None)
|
||||
}
|
||||
|
||||
//
|
||||
// Warning-related functions
|
||||
//
|
||||
extern "C" {
|
||||
pub fn lua_setwarnf(L: *mut lua_State, f: Option<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
|
||||
//
|
||||
pub const LUA_GCSTOP: c_int = 0;
|
||||
pub const LUA_GCRESTART: c_int = 1;
|
||||
pub const LUA_GCCOLLECT: c_int = 2;
|
||||
pub const LUA_GCCOUNT: c_int = 3;
|
||||
pub const LUA_GCCOUNTB: c_int = 4;
|
||||
pub const LUA_GCSTEP: c_int = 5;
|
||||
pub const LUA_GCSETPAUSE: c_int = 6;
|
||||
pub const LUA_GCSETSTEPMUL: c_int = 7;
|
||||
pub const LUA_GCISRUNNING: c_int = 9;
|
||||
pub const LUA_GCGEN: c_int = 10;
|
||||
pub const LUA_GCINC: c_int = 11;
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_gc(L: *mut lua_State, what: c_int, ...) -> c_int;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// Miscellaneous functions
|
||||
//
|
||||
pub fn lua_error(L: *mut lua_State) -> !;
|
||||
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_len(L: *mut lua_State, idx: c_int);
|
||||
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_setallocf(L: *mut lua_State, f: lua_Alloc, ud: *mut c_void);
|
||||
|
||||
pub fn lua_toclose(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_closeslot(L: *mut lua_State, idx: c_int);
|
||||
}
|
||||
|
||||
//
|
||||
// Some useful macros (implemented as Rust functions)
|
||||
//
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
|
||||
(L as *mut c_char).sub(LUA_EXTRASPACE) as *mut c_void
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number {
|
||||
lua_tonumberx(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
|
||||
lua_tointegerx(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pop(L: *mut lua_State, n: c_int) {
|
||||
lua_settop(L, -n - 1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_newtable(L: *mut lua_State) {
|
||||
lua_createtable(L, 0, 0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_register(L: *mut lua_State, n: *const c_char, f: lua_CFunction) {
|
||||
lua_pushcfunction(L, f);
|
||||
lua_setglobal(L, n)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) {
|
||||
lua_pushcclosure(L, f, 0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isfunction(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TFUNCTION) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_istable(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TTABLE) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_islightuserdata(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TLIGHTUSERDATA) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TNIL) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isboolean(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TBOOLEAN) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isthread(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TTHREAD) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnone(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TNONE) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnoneornil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) <= 0) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) -> *const c_char {
|
||||
use std::ffi::CString;
|
||||
let c_str = CString::new(s).unwrap();
|
||||
lua_pushlstring(L, c_str.as_ptr(), c_str.as_bytes().len())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushglobaltable(L: *mut lua_State) -> c_int {
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char {
|
||||
lua_tolstring(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_insert(L: *mut lua_State, idx: c_int) {
|
||||
lua_rotate(L, idx, 1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_remove(L: *mut lua_State, idx: c_int) {
|
||||
lua_rotate(L, idx, -1);
|
||||
lua_pop(L, 1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_replace(L: *mut lua_State, idx: c_int) {
|
||||
lua_copy(L, -1, idx);
|
||||
lua_pop(L, 1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_xpush(from: *mut lua_State, to: *mut lua_State, idx: c_int) {
|
||||
lua_pushvalue(from, idx);
|
||||
lua_xmove(from, to, 1);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_newuserdata(L: *mut lua_State, sz: usize) -> *mut c_void {
|
||||
lua_newuserdatauv(L, sz, 1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
|
||||
lua_getiuservalue(L, idx, 1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_setuservalue(L: *mut lua_State, idx: c_int) -> c_int {
|
||||
lua_setiuservalue(L, idx, 1)
|
||||
}
|
||||
|
||||
//
|
||||
// Debug API
|
||||
//
|
||||
|
||||
// Maximum size for the description of the source of a function in debug information.
|
||||
const LUA_IDSIZE: usize = 60;
|
||||
|
||||
// Event codes
|
||||
pub const LUA_HOOKCALL: c_int = 0;
|
||||
pub const LUA_HOOKRET: c_int = 1;
|
||||
pub const LUA_HOOKLINE: c_int = 2;
|
||||
pub const LUA_HOOKCOUNT: c_int = 3;
|
||||
pub const LUA_HOOKTAILCALL: c_int = 4;
|
||||
|
||||
// Event masks
|
||||
pub const LUA_MASKCALL: c_int = 1 << (LUA_HOOKCALL as usize);
|
||||
pub const LUA_MASKRET: c_int = 1 << (LUA_HOOKRET as usize);
|
||||
pub const LUA_MASKLINE: c_int = 1 << (LUA_HOOKLINE as usize);
|
||||
pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
|
||||
|
||||
/// Type for functions to be called on debug events.
|
||||
pub type lua_Hook = unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug);
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_getstack(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getinfo(L: *mut lua_State, what: *const c_char, ar: *mut lua_Debug) -> c_int;
|
||||
pub fn lua_getlocal(L: *mut lua_State, ar: *const lua_Debug, n: c_int) -> *const c_char;
|
||||
pub fn lua_setlocal(L: *mut lua_State, ar: *const lua_Debug, 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_upvalueid(L: *mut lua_State, fidx: c_int, n: c_int) -> *mut c_void;
|
||||
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: Option<lua_Hook>, mask: c_int, count: c_int);
|
||||
pub fn lua_gethook(L: *mut lua_State) -> Option<lua_Hook>;
|
||||
pub fn lua_gethookmask(L: *mut lua_State) -> c_int;
|
||||
pub fn lua_gethookcount(L: *mut lua_State) -> c_int;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct lua_Debug {
|
||||
pub event: c_int,
|
||||
pub name: *const c_char,
|
||||
pub namewhat: *const c_char,
|
||||
pub what: *const c_char,
|
||||
pub source: *const c_char,
|
||||
pub srclen: usize,
|
||||
pub currentline: c_int,
|
||||
pub linedefined: c_int,
|
||||
pub lastlinedefined: c_int,
|
||||
pub nups: c_uchar,
|
||||
pub nparams: c_uchar,
|
||||
pub isvararg: c_char,
|
||||
pub istailcall: c_char,
|
||||
pub ftransfer: c_ushort,
|
||||
pub ntransfer: c_ushort,
|
||||
pub short_src: [c_char; LUA_IDSIZE],
|
||||
// lua.h mentions this is for private use
|
||||
i_ci: *mut c_void,
|
||||
}
|
31
src/ffi/lua54/lualib.rs
Normal file
31
src/ffi/lua54/lualib.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
//! Contains definitions from `lualib.h`.
|
||||
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use super::lua::lua_State;
|
||||
|
||||
pub const LUA_COLIBNAME: &str = "coroutine";
|
||||
pub const LUA_TABLIBNAME: &str = "table";
|
||||
pub const LUA_IOLIBNAME: &str = "io";
|
||||
pub const LUA_OSLIBNAME: &str = "os";
|
||||
pub const LUA_STRLIBNAME: &str = "string";
|
||||
pub const LUA_UTF8LIBNAME: &str = "utf8";
|
||||
pub const LUA_MATHLIBNAME: &str = "math";
|
||||
pub const LUA_DBLIBNAME: &str = "debug";
|
||||
pub const LUA_LOADLIBNAME: &str = "package";
|
||||
|
||||
extern "C" {
|
||||
pub fn luaopen_base(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_io(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_utf8(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_math(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_debug(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_package(L: *mut lua_State) -> c_int;
|
||||
|
||||
// open all builtin libraries
|
||||
pub fn luaL_openlibs(L: *mut lua_State);
|
||||
}
|
9
src/ffi/lua54/mod.rs
Normal file
9
src/ffi/lua54/mod.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
//! Low level bindings to Lua 5.4.
|
||||
|
||||
pub use lauxlib::*;
|
||||
pub use lua::*;
|
||||
pub use lualib::*;
|
||||
|
||||
pub mod lauxlib;
|
||||
pub mod lua;
|
||||
pub mod lualib;
|
|
@ -1,36 +0,0 @@
|
|||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2019-2021 A. Orlenko
|
||||
// Copyright (c) 2014 J.C. Moyer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
//! Contains definitions from `luaconf.h`.
|
||||
|
||||
pub use super::glue::LUA_INTEGER;
|
||||
pub use super::glue::LUA_NUMBER;
|
||||
pub use super::glue::LUA_UNSIGNED;
|
||||
|
||||
pub use super::glue::LUA_IDSIZE;
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub use super::glue::LUAL_NUMSIZES;
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub type LUA_KCONTEXT = isize; // intptr_t
|
|
@ -1,67 +0,0 @@
|
|||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2019-2021 A. Orlenko
|
||||
// Copyright (c) 2014 J.C. Moyer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
//! Contains definitions from `lualib.h`.
|
||||
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use super::lua::lua_State;
|
||||
|
||||
pub use super::glue::{
|
||||
LUA_COLIBNAME, LUA_DBLIBNAME, LUA_IOLIBNAME, LUA_LOADLIBNAME, LUA_MATHLIBNAME, LUA_OSLIBNAME,
|
||||
LUA_STRLIBNAME, LUA_TABLIBNAME,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub use super::glue::LUA_UTF8LIBNAME;
|
||||
|
||||
#[cfg(any(feature = "lua52", feature = "luajit"))]
|
||||
pub use super::glue::LUA_BITLIBNAME;
|
||||
|
||||
#[cfg(feature = "luajit")]
|
||||
pub use super::glue::{LUA_FFILIBNAME, LUA_JITLIBNAME};
|
||||
|
||||
extern "C" {
|
||||
pub fn luaopen_base(L: *mut lua_State) -> c_int;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub fn luaopen_coroutine(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_os(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_string(L: *mut lua_State) -> c_int;
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub fn luaopen_utf8(L: *mut lua_State) -> c_int;
|
||||
#[cfg(feature = "lua52")]
|
||||
pub fn luaopen_bit32(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_math(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_debug(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_package(L: *mut lua_State) -> c_int;
|
||||
#[cfg(feature = "luajit")]
|
||||
pub fn luaopen_bit(L: *mut lua_State) -> c_int;
|
||||
#[cfg(feature = "luajit")]
|
||||
pub fn luaopen_jit(L: *mut lua_State) -> c_int;
|
||||
#[cfg(feature = "luajit")]
|
||||
pub fn luaopen_ffi(L: *mut lua_State) -> c_int;
|
||||
|
||||
pub fn luaL_openlibs(L: *mut lua_State);
|
||||
}
|
521
src/ffi/luau/compat.rs
Normal file
521
src/ffi/luau/compat.rs
Normal file
|
@ -0,0 +1,521 @@
|
|||
//! MLua compatibility layer for Roblox Luau.
|
||||
//!
|
||||
//! Based on github.com/keplerproject/lua-compat-5.3
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::ptr;
|
||||
|
||||
use super::lauxlib::*;
|
||||
use super::lua::*;
|
||||
use super::luacode::*;
|
||||
|
||||
unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
|
||||
while a < b {
|
||||
lua_pushvalue(L, a);
|
||||
lua_pushvalue(L, b);
|
||||
lua_replace(L, a);
|
||||
lua_replace(L, b);
|
||||
a += 1;
|
||||
b -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
const COMPAT53_LEVELS1: c_int = 12; // size of the first part of the stack
|
||||
const COMPAT53_LEVELS2: c_int = 10; // size of the second part of the stack
|
||||
|
||||
unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) -> c_int {
|
||||
if level == 0 || lua_istable(L, -1) == 0 {
|
||||
return 0; // not found
|
||||
}
|
||||
|
||||
lua_pushnil(L); // start 'next' loop
|
||||
while lua_next(L, -2) != 0 {
|
||||
// for each pair in table
|
||||
if lua_type(L, -2) == LUA_TSTRING {
|
||||
// ignore non-string keys
|
||||
if lua_rawequal(L, objidx, -1) != 0 {
|
||||
// found object?
|
||||
lua_pop(L, 1); // remove value (but keep name)
|
||||
return 1;
|
||||
} else if compat53_findfield(L, objidx, level - 1) != 0 {
|
||||
// try recursively
|
||||
lua_remove(L, -2); // remove table (but keep name)
|
||||
lua_pushliteral(L, ".");
|
||||
lua_insert(L, -2); // place '.' between the two names
|
||||
lua_concat(L, 3);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1); // remove value
|
||||
}
|
||||
0 // not found
|
||||
}
|
||||
|
||||
unsafe fn compat53_pushglobalfuncname(
|
||||
L: *mut lua_State,
|
||||
level: c_int,
|
||||
ar: *mut lua_Debug,
|
||||
) -> c_int {
|
||||
let top = lua_gettop(L);
|
||||
// push function
|
||||
lua_getinfo(L, level, cstr!("f"), ar);
|
||||
lua_pushvalue(L, LUA_GLOBALSINDEX);
|
||||
if compat53_findfield(L, top + 1, 2) != 0 {
|
||||
lua_copy(L, -1, top + 1); // move name to proper place
|
||||
lua_pop(L, 2); // remove pushed values
|
||||
1
|
||||
} else {
|
||||
lua_settop(L, top); // remove function and global table
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn compat53_pushfuncname(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) {
|
||||
if !(*ar).name.is_null() {
|
||||
// is there a name?
|
||||
lua_pushfstring(L, cstr!("function '%s'"), (*ar).name);
|
||||
} else if compat53_pushglobalfuncname(L, level, ar) != 0 {
|
||||
lua_pushfstring(L, cstr!("function '%s'"), lua_tostring(L, -1));
|
||||
lua_remove(L, -2); // remove name
|
||||
} else {
|
||||
lua_pushliteral(L, "?");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// lua ported functions
|
||||
//
|
||||
|
||||
pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
|
||||
idx = lua_absindex(L, idx);
|
||||
if n > 0 {
|
||||
// Faster version
|
||||
for _ in 0..n {
|
||||
lua_insert(L, idx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let n_elems = lua_gettop(L) - idx + 1;
|
||||
if n < 0 {
|
||||
n += n_elems;
|
||||
}
|
||||
if n > 0 && n < n_elems {
|
||||
luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
|
||||
n = n_elems - n;
|
||||
compat53_reverse(L, idx, idx + n - 1);
|
||||
compat53_reverse(L, idx + n, idx + n_elems - 1);
|
||||
compat53_reverse(L, idx, idx + n_elems - 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int) {
|
||||
let abs_to = lua_absindex(L, toidx);
|
||||
luaL_checkstack(L, 1, cstr!("not enough stack slots"));
|
||||
lua_pushvalue(L, fromidx);
|
||||
lua_replace(L, abs_to);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
|
||||
if lua_type(L, idx) == LUA_TNUMBER {
|
||||
let n = lua_tonumber(L, idx);
|
||||
let i = lua_tointeger(L, idx);
|
||||
if (n - i as lua_Number).abs() < lua_Number::EPSILON {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
|
||||
lua_tointegerx(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
|
||||
let mut ok = 0;
|
||||
let n = lua_tonumberx(L, i, &mut ok);
|
||||
let n_int = n as lua_Integer;
|
||||
if ok != 0 && (n - n_int as lua_Number).abs() < lua_Number::EPSILON {
|
||||
if !isnum.is_null() {
|
||||
*isnum = 1;
|
||||
}
|
||||
return n_int;
|
||||
}
|
||||
if !isnum.is_null() {
|
||||
*isnum = 0;
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize {
|
||||
lua_objlen(L, idx)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
|
||||
if l == 0 {
|
||||
lua_pushlstring_(L, cstr!(""), 0);
|
||||
} else {
|
||||
lua_pushlstring_(L, s, l);
|
||||
}
|
||||
lua_tostring(L, -1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char {
|
||||
lua_pushstring_(L, s);
|
||||
lua_tostring(L, -1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_int {
|
||||
idx = lua_absindex(L, idx);
|
||||
lua_pushinteger(L, n);
|
||||
lua_gettable(L, idx)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
|
||||
lua_rawgeti_(L, idx, n)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int {
|
||||
let abs_i = lua_absindex(L, idx);
|
||||
lua_pushlightuserdata(L, p as *mut c_void);
|
||||
lua_rawget(L, abs_i)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getuservalue(L: *mut lua_State, mut idx: c_int) -> c_int {
|
||||
luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
|
||||
idx = lua_absindex(L, idx);
|
||||
lua_pushliteral(L, "__mlua_uservalues");
|
||||
if lua_rawget(L, LUA_REGISTRYINDEX) != LUA_TTABLE {
|
||||
return LUA_TNIL;
|
||||
}
|
||||
lua_pushvalue(L, idx);
|
||||
lua_rawget(L, -2);
|
||||
lua_remove(L, -2);
|
||||
lua_type(L, -1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
|
||||
luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
|
||||
idx = lua_absindex(L, idx);
|
||||
lua_pushinteger(L, n);
|
||||
lua_insert(L, -2);
|
||||
lua_settable(L, idx);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) {
|
||||
lua_rawseti_(L, idx, n)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) {
|
||||
let abs_i = lua_absindex(L, idx);
|
||||
luaL_checkstack(L, 1, cstr!("not enough stack slots"));
|
||||
lua_pushlightuserdata(L, p as *mut c_void);
|
||||
lua_insert(L, -2);
|
||||
lua_rawset(L, abs_i);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_setuservalue(L: *mut lua_State, mut idx: c_int) {
|
||||
luaL_checkstack(L, 4, cstr!("not enough stack slots available"));
|
||||
idx = lua_absindex(L, idx);
|
||||
lua_pushliteral(L, "__mlua_uservalues");
|
||||
lua_pushvalue(L, -1);
|
||||
if lua_rawget(L, LUA_REGISTRYINDEX) != LUA_TTABLE {
|
||||
lua_pop(L, 1);
|
||||
lua_createtable(L, 0, 2); // main table
|
||||
lua_createtable(L, 0, 1); // metatable
|
||||
lua_pushliteral(L, "k");
|
||||
lua_setfield(L, -2, cstr!("__mode"));
|
||||
lua_setmetatable(L, -2);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_replace(L, -2);
|
||||
lua_pushvalue(L, idx);
|
||||
lua_pushvalue(L, -3);
|
||||
lua_remove(L, -4);
|
||||
lua_rawset(L, -3);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) {
|
||||
match lua_type(L, idx) {
|
||||
LUA_TSTRING => {
|
||||
lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
|
||||
}
|
||||
LUA_TTABLE => {
|
||||
if luaL_callmeta(L, idx, cstr!("__len")) == 0 {
|
||||
lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
|
||||
}
|
||||
}
|
||||
LUA_TUSERDATA if luaL_callmeta(L, idx, cstr!("__len")) != 0 => {}
|
||||
_ => {
|
||||
luaL_error(
|
||||
L,
|
||||
cstr!("attempt to get length of a %s value"),
|
||||
lua_typename(L, lua_type(L, idx)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
|
||||
lua_pushvalue(L, LUA_GLOBALSINDEX);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
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_(L, from, narg);
|
||||
if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
|
||||
*nres = lua_gettop(L);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
//
|
||||
// lauxlib ported functions
|
||||
//
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char) {
|
||||
if lua_checkstack(L, sz + LUA_MINSTACK) == 0 {
|
||||
if !msg.is_null() {
|
||||
luaL_error(L, cstr!("stack overflow (%s)"), msg);
|
||||
} else {
|
||||
lua_pushliteral(L, "stack overflow");
|
||||
lua_error(L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int {
|
||||
if luaL_getmetafield_(L, obj, e) != 0 {
|
||||
lua_type(L, -1)
|
||||
} else {
|
||||
LUA_TNIL
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int {
|
||||
if luaL_newmetatable_(L, tname) != 0 {
|
||||
lua_pushstring(L, tname);
|
||||
lua_setfield(L, -2, cstr!("__name"));
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn luaL_loadbufferx(
|
||||
L: *mut lua_State,
|
||||
data: *const c_char,
|
||||
mut size: usize,
|
||||
name: *const c_char,
|
||||
mode: *const c_char,
|
||||
) -> c_int {
|
||||
extern "C" {
|
||||
fn free(p: *mut c_void);
|
||||
}
|
||||
|
||||
let chunk_is_text = size == 0 || (*data as u8) >= b'\n';
|
||||
if !mode.is_null() {
|
||||
let modeb = CStr::from_ptr(mode).to_bytes();
|
||||
if !chunk_is_text && !modeb.contains(&b'b') {
|
||||
lua_pushfstring(
|
||||
L,
|
||||
cstr!("attempt to load a binary chunk (mode is '%s')"),
|
||||
mode,
|
||||
);
|
||||
return LUA_ERRSYNTAX;
|
||||
} else if chunk_is_text && !modeb.contains(&b't') {
|
||||
lua_pushfstring(
|
||||
L,
|
||||
cstr!("attempt to load a text chunk (mode is '%s')"),
|
||||
mode,
|
||||
);
|
||||
return LUA_ERRSYNTAX;
|
||||
}
|
||||
}
|
||||
|
||||
if chunk_is_text {
|
||||
let data = luau_compile_(data, size, ptr::null_mut(), &mut size);
|
||||
let ok = luau_load(L, name, data, size, 0) == 0;
|
||||
free(data as *mut c_void);
|
||||
if !ok {
|
||||
return LUA_ERRSYNTAX;
|
||||
}
|
||||
} else if luau_load(L, name, data, size, 0) != 0 {
|
||||
return LUA_ERRSYNTAX;
|
||||
}
|
||||
LUA_OK
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_loadbuffer(
|
||||
L: *mut lua_State,
|
||||
data: *const c_char,
|
||||
size: usize,
|
||||
name: *const c_char,
|
||||
) -> c_int {
|
||||
luaL_loadbufferx(L, data, size, name, ptr::null())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer {
|
||||
let mut isnum = 0;
|
||||
luaL_checkstack(L, 1, cstr!("not enough stack slots"));
|
||||
lua_len(L, idx);
|
||||
let res = lua_tointegerx(L, -1, &mut isnum);
|
||||
lua_pop(L, 1);
|
||||
if isnum == 0 {
|
||||
luaL_error(L, cstr!("object length is not an integer"));
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
pub unsafe fn luaL_traceback(
|
||||
L: *mut lua_State,
|
||||
L1: *mut lua_State,
|
||||
msg: *const c_char,
|
||||
mut level: c_int,
|
||||
) {
|
||||
let mut ar: lua_Debug = mem::zeroed();
|
||||
let top = lua_gettop(L);
|
||||
let numlevels = lua_stackdepth(L);
|
||||
let mark = if numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2 {
|
||||
COMPAT53_LEVELS1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
if !msg.is_null() {
|
||||
lua_pushfstring(L, cstr!("%s\n"), msg);
|
||||
}
|
||||
lua_pushliteral(L, "stack traceback:");
|
||||
while lua_getinfo(L1, level, cstr!(""), &mut ar) != 0 {
|
||||
if level + 1 == mark {
|
||||
// too many levels?
|
||||
lua_pushliteral(L, "\n\t..."); // add a '...'
|
||||
level = numlevels - COMPAT53_LEVELS2; // and skip to last ones
|
||||
} else {
|
||||
lua_getinfo(L1, level, cstr!("sln"), &mut ar);
|
||||
lua_pushfstring(L, cstr!("\n\t%s:"), ar.short_src);
|
||||
if ar.currentline > 0 {
|
||||
lua_pushfstring(L, cstr!("%d:"), ar.currentline);
|
||||
}
|
||||
lua_pushliteral(L, " in ");
|
||||
compat53_pushfuncname(L, level, &mut ar);
|
||||
lua_concat(L, lua_gettop(L) - top);
|
||||
}
|
||||
level += 1;
|
||||
}
|
||||
lua_concat(L, lua_gettop(L) - top);
|
||||
}
|
||||
|
||||
pub unsafe fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char {
|
||||
if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
|
||||
let t = lua_type(L, idx);
|
||||
match t {
|
||||
LUA_TNIL => {
|
||||
lua_pushliteral(L, "nil");
|
||||
}
|
||||
LUA_TSTRING | LUA_TNUMBER => {
|
||||
lua_pushvalue(L, idx);
|
||||
}
|
||||
LUA_TBOOLEAN => {
|
||||
if lua_toboolean(L, idx) == 0 {
|
||||
lua_pushliteral(L, "false");
|
||||
} else {
|
||||
lua_pushliteral(L, "true");
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let tt = luaL_getmetafield(L, idx, cstr!("__name"));
|
||||
let name = if tt == LUA_TSTRING {
|
||||
lua_tostring(L, -1)
|
||||
} else {
|
||||
lua_typename(L, t)
|
||||
};
|
||||
lua_pushfstring(L, cstr!("%s: %p"), name, lua_topointer(L, idx));
|
||||
if tt != LUA_TNIL {
|
||||
lua_replace(L, -2);
|
||||
}
|
||||
}
|
||||
};
|
||||
} else if lua_isstring(L, -1) == 0 {
|
||||
luaL_error(L, cstr!("'__tostring' must return a string"));
|
||||
}
|
||||
lua_tolstring(L, -1, len)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) {
|
||||
luaL_checkstack(L, 1, cstr!("not enough stack slots"));
|
||||
luaL_getmetatable(L, tname);
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
|
||||
pub unsafe fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int {
|
||||
let abs_i = lua_absindex(L, idx);
|
||||
luaL_checkstack(L, 3, cstr!("not enough stack slots"));
|
||||
lua_pushstring_(L, fname);
|
||||
if lua_gettable(L, abs_i) == LUA_TTABLE {
|
||||
return 1;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
lua_newtable(L);
|
||||
lua_pushstring_(L, fname);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, abs_i);
|
||||
0
|
||||
}
|
||||
|
||||
pub unsafe fn luaL_requiref(
|
||||
L: *mut lua_State,
|
||||
modname: *const c_char,
|
||||
openf: lua_CFunction,
|
||||
glb: c_int,
|
||||
) {
|
||||
luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
|
||||
luaL_getsubtable(L, LUA_REGISTRYINDEX, cstr!("_LOADED"));
|
||||
if lua_getfield(L, -1, modname) == LUA_TNIL {
|
||||
lua_pop(L, 1);
|
||||
lua_pushcfunction(L, openf);
|
||||
lua_pushstring(L, modname);
|
||||
lua_call(L, 1, 1);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -3, modname);
|
||||
}
|
||||
if glb != 0 {
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setglobal(L, modname);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_setglobal(L, modname);
|
||||
}
|
||||
lua_replace(L, -2);
|
||||
}
|
156
src/ffi/luau/lauxlib.rs
Normal file
156
src/ffi/luau/lauxlib.rs
Normal file
|
@ -0,0 +1,156 @@
|
|||
//! Contains definitions from `lualib.h`.
|
||||
|
||||
use std::os::raw::{c_char, c_float, c_int, c_void};
|
||||
use std::ptr;
|
||||
|
||||
use super::lua::{
|
||||
self, lua_CFunction, lua_Integer, lua_Number, lua_State, lua_Unsigned, LUA_REGISTRYINDEX,
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct luaL_Reg {
|
||||
pub name: *const c_char,
|
||||
pub func: lua_CFunction,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn luaL_register(L: *mut lua_State, libname: *const c_char, l: *const luaL_Reg);
|
||||
#[link_name = "luaL_getmetafield"]
|
||||
pub fn luaL_getmetafield_(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;
|
||||
#[link_name = "luaL_typeerrorL"]
|
||||
pub fn luaL_typeerror(L: *mut lua_State, narg: c_int, tname: *const c_char) -> !;
|
||||
#[link_name = "luaL_argerrorL"]
|
||||
pub fn luaL_argerror(L: *mut lua_State, narg: c_int, extramsg: *const c_char) -> !;
|
||||
pub fn luaL_checklstring(L: *mut lua_State, narg: c_int, l: *mut usize) -> *const c_char;
|
||||
pub fn luaL_optlstring(
|
||||
L: *mut lua_State,
|
||||
narg: c_int,
|
||||
def: *const c_char,
|
||||
l: *mut usize,
|
||||
) -> *const c_char;
|
||||
pub fn luaL_checknumber(L: *mut lua_State, narg: c_int) -> lua_Number;
|
||||
pub fn luaL_optnumber(L: *mut lua_State, narg: c_int, def: lua_Number) -> lua_Number;
|
||||
|
||||
pub fn luaL_checkboolean(L: *mut lua_State, narg: c_int) -> c_int;
|
||||
pub fn luaL_optboolean(L: *mut lua_State, narg: c_int, def: c_int) -> c_int;
|
||||
|
||||
pub fn luaL_checkinteger(L: *mut lua_State, narg: c_int) -> lua_Integer;
|
||||
pub fn luaL_optinteger(L: *mut lua_State, narg: c_int, def: lua_Integer) -> lua_Integer;
|
||||
pub fn luaL_checkunsigned(L: *mut lua_State, narg: c_int) -> lua_Unsigned;
|
||||
pub fn luaL_optunsigned(L: *mut lua_State, narg: c_int, def: lua_Unsigned) -> lua_Unsigned;
|
||||
|
||||
pub fn luaL_checkvector(L: *mut lua_State, narg: c_int) -> *const c_float;
|
||||
pub fn luaL_optvector(L: *mut lua_State, narg: c_int, def: *const c_float) -> *const c_float;
|
||||
|
||||
#[link_name = "luaL_checkstack"]
|
||||
pub fn luaL_checkstack_(L: *mut lua_State, sz: c_int, msg: *const c_char);
|
||||
pub fn luaL_checktype(L: *mut lua_State, narg: c_int, t: c_int);
|
||||
pub fn luaL_checkany(L: *mut lua_State, narg: c_int);
|
||||
|
||||
#[link_name = "luaL_newmetatable"]
|
||||
pub fn luaL_newmetatable_(L: *mut lua_State, tname: *const c_char) -> c_int;
|
||||
pub fn luaL_checkudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;
|
||||
|
||||
pub fn luaL_where(L: *mut lua_State, lvl: c_int);
|
||||
|
||||
#[link_name = "luaL_errorL"]
|
||||
pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> !;
|
||||
|
||||
pub fn luaL_checkoption(
|
||||
L: *mut lua_State,
|
||||
narg: c_int,
|
||||
def: *const c_char,
|
||||
lst: *const *const c_char,
|
||||
) -> c_int;
|
||||
|
||||
#[link_name = "luaL_tolstring"]
|
||||
pub fn luaL_tolstring_(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char;
|
||||
|
||||
pub fn luaL_newstate() -> *mut lua_State;
|
||||
|
||||
// TODO: luaL_findtable
|
||||
|
||||
pub fn luaL_typename(L: *mut lua_State, idx: c_int) -> *const c_char;
|
||||
|
||||
// sandbox libraries and globals
|
||||
#[link_name = "luaL_sandbox"]
|
||||
pub fn luaL_sandbox_(L: *mut lua_State);
|
||||
pub fn luaL_sandboxthread(L: *mut lua_State);
|
||||
}
|
||||
|
||||
//
|
||||
// Some useful macros (implemented as Rust functions)
|
||||
//
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_argcheck(L: *mut lua_State, cond: c_int, arg: c_int, extramsg: *const c_char) {
|
||||
if cond == 0 {
|
||||
luaL_argerror(L, arg, extramsg);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_argexpected(L: *mut lua_State, cond: c_int, arg: c_int, tname: *const c_char) {
|
||||
if cond == 0 {
|
||||
luaL_typeerror(L, arg, tname);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_checkstring(L: *mut lua_State, n: c_int) -> *const c_char {
|
||||
luaL_checklstring(L, n, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_optstring(L: *mut lua_State, n: c_int, d: *const c_char) -> *const c_char {
|
||||
luaL_optlstring(L, n, d, ptr::null_mut())
|
||||
}
|
||||
|
||||
// TODO: luaL_opt
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) -> c_int {
|
||||
lua::lua_getfield(L, LUA_REGISTRYINDEX, n)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_ref(L: *mut lua_State, t: c_int) -> c_int {
|
||||
assert_eq!(t, LUA_REGISTRYINDEX);
|
||||
let r = lua::lua_ref(L, -1);
|
||||
lua::lua_pop(L, 1);
|
||||
r
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn luaL_unref(L: *mut lua_State, t: c_int, r#ref: c_int) {
|
||||
assert_eq!(t, LUA_REGISTRYINDEX);
|
||||
lua::lua_unref(L, r#ref)
|
||||
}
|
||||
|
||||
pub unsafe fn luaL_sandbox(L: *mut lua_State, enabled: c_int) {
|
||||
use super::lua::*;
|
||||
|
||||
// set all libraries to read-only
|
||||
lua_pushnil(L);
|
||||
while lua_next(L, LUA_GLOBALSINDEX) != 0 {
|
||||
if lua_istable(L, -1) != 0 {
|
||||
lua_setreadonly(L, -1, enabled);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
// set all builtin metatables to read-only
|
||||
lua_pushliteral(L, "");
|
||||
lua_getmetatable(L, -1);
|
||||
lua_setreadonly(L, -1, enabled);
|
||||
lua_pop(L, 2);
|
||||
|
||||
// set globals to readonly and activate safeenv since the env is immutable
|
||||
lua_setreadonly(L, LUA_GLOBALSINDEX, enabled);
|
||||
lua_setsafeenv(L, LUA_GLOBALSINDEX, enabled);
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: Generic Buffer Manipulation
|
||||
//
|
507
src/ffi/luau/lua.rs
Normal file
507
src/ffi/luau/lua.rs
Normal file
|
@ -0,0 +1,507 @@
|
|||
//! Contains definitions from `lua.h`.
|
||||
|
||||
use std::marker::{PhantomData, PhantomPinned};
|
||||
use std::os::raw::{c_char, c_double, c_float, c_int, c_uint, c_void};
|
||||
use std::ptr;
|
||||
|
||||
// Option for multiple returns in 'lua_pcall' and 'lua_call'
|
||||
pub const LUA_MULTRET: c_int = -1;
|
||||
|
||||
//
|
||||
// Pseudo-indices
|
||||
//
|
||||
pub const LUA_REGISTRYINDEX: c_int = -10000;
|
||||
pub const LUA_ENVIRONINDEX: c_int = -10001;
|
||||
pub const LUA_GLOBALSINDEX: c_int = -10002;
|
||||
|
||||
pub const fn lua_upvalueindex(i: c_int) -> c_int {
|
||||
LUA_GLOBALSINDEX - i
|
||||
}
|
||||
|
||||
//
|
||||
// Thread status
|
||||
//
|
||||
pub const LUA_OK: c_int = 0;
|
||||
pub const LUA_YIELD: c_int = 1;
|
||||
pub const LUA_ERRRUN: c_int = 2;
|
||||
pub const LUA_ERRSYNTAX: c_int = 3;
|
||||
pub const LUA_ERRMEM: c_int = 4;
|
||||
pub const LUA_ERRERR: c_int = 5;
|
||||
|
||||
/// A raw Lua state associated with a thread.
|
||||
#[repr(C)]
|
||||
pub struct lua_State {
|
||||
_data: [u8; 0],
|
||||
_marker: PhantomData<(*mut u8, PhantomPinned)>,
|
||||
}
|
||||
|
||||
//
|
||||
// Basic types
|
||||
//
|
||||
pub const LUA_TNONE: c_int = -1;
|
||||
|
||||
pub const LUA_TNIL: c_int = 0;
|
||||
pub const LUA_TBOOLEAN: c_int = 1;
|
||||
|
||||
pub const LUA_TLIGHTUSERDATA: c_int = 2;
|
||||
pub const LUA_TNUMBER: c_int = 3;
|
||||
pub const LUA_TVECTOR: c_int = 4;
|
||||
|
||||
pub const LUA_TSTRING: c_int = 5;
|
||||
pub const LUA_TTABLE: c_int = 6;
|
||||
pub const LUA_TFUNCTION: c_int = 7;
|
||||
pub const LUA_TUSERDATA: c_int = 8;
|
||||
pub const LUA_TTHREAD: c_int = 9;
|
||||
|
||||
/// Guaranteed number of Lua stack slots available to a C function.
|
||||
pub const LUA_MINSTACK: c_int = 20;
|
||||
|
||||
/// A Lua number, usually equivalent to `f64`.
|
||||
pub type lua_Number = c_double;
|
||||
|
||||
/// A Lua integer, equivalent to `i32`.
|
||||
pub type lua_Integer = c_int;
|
||||
|
||||
/// A Lua unsigned integer, equivalent to `u32`.
|
||||
pub type lua_Unsigned = c_uint;
|
||||
|
||||
/// Type for native C functions that can be passed to Lua.
|
||||
pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int;
|
||||
pub type lua_Continuation = unsafe extern "C" fn(L: *mut lua_State, status: c_int) -> c_int;
|
||||
|
||||
/// Type for userdata destructor functions.
|
||||
pub type lua_Udestructor = unsafe extern "C" fn(*mut c_void);
|
||||
|
||||
/// Type for memory-allocation functions.
|
||||
pub type lua_Alloc = unsafe extern "C" fn(
|
||||
ud: *mut c_void,
|
||||
ptr: *mut c_void,
|
||||
osize: usize,
|
||||
nsize: usize,
|
||||
) -> *mut c_void;
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// State manipulation
|
||||
//
|
||||
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_newthread(L: *mut lua_State) -> *mut lua_State;
|
||||
pub fn lua_mainthread(L: *mut lua_State) -> *mut lua_State;
|
||||
pub fn lua_resetthread(L: *mut lua_State);
|
||||
pub fn lua_isthreadreset(L: *mut lua_State) -> c_int;
|
||||
|
||||
//
|
||||
// Basic stack manipulation
|
||||
//
|
||||
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_settop(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_pushvalue(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_remove(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_insert(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_replace(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_checkstack(L: *mut lua_State, sz: c_int) -> c_int;
|
||||
pub fn lua_rawcheckstack(L: *mut lua_State, sz: c_int);
|
||||
|
||||
pub fn lua_xmove(from: *mut lua_State, to: *mut lua_State, n: c_int);
|
||||
pub fn lua_xpush(from: *mut lua_State, to: *mut lua_State, idx: c_int);
|
||||
|
||||
//
|
||||
// Access functions (stack -> C)
|
||||
//
|
||||
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_iscfunction(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_isLfunction(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_typename(L: *mut lua_State, tp: c_int) -> *const c_char;
|
||||
|
||||
pub fn lua_equal(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;
|
||||
pub fn lua_lessthan(L: *mut lua_State, idx1: c_int, idx2: c_int) -> c_int;
|
||||
|
||||
pub fn lua_tonumberx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Number;
|
||||
#[link_name = "lua_tointegerx"]
|
||||
pub fn lua_tointegerx_(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Integer;
|
||||
pub fn lua_tounsignedx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Unsigned;
|
||||
pub fn lua_tovector(L: *mut lua_State, idx: c_int) -> *const c_float;
|
||||
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_tostringatom(L: *mut lua_State, idx: c_int, atom: *mut c_int) -> *const c_char;
|
||||
pub fn lua_namecallatom(L: *mut lua_State, atom: *mut c_int) -> *const c_char;
|
||||
pub fn lua_objlen(L: *mut lua_State, idx: c_int) -> usize;
|
||||
pub fn lua_tocfunction(L: *mut lua_State, idx: c_int) -> Option<lua_CFunction>;
|
||||
pub fn lua_tolightuserdata(L: *mut lua_State, idx: c_int) -> *mut c_void;
|
||||
pub fn lua_touserdata(L: *mut lua_State, idx: c_int) -> *mut c_void;
|
||||
pub fn lua_touserdatatagged(L: *mut lua_State, idx: c_int, tag: c_int) -> *mut c_void;
|
||||
pub fn lua_userdatatag(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_tothread(L: *mut lua_State, idx: c_int) -> *mut lua_State;
|
||||
pub fn lua_topointer(L: *mut lua_State, idx: c_int) -> *const c_void;
|
||||
|
||||
//
|
||||
// Push functions (C -> stack)
|
||||
//
|
||||
pub fn lua_pushnil(L: *mut lua_State);
|
||||
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_pushunsigned(L: *mut lua_State, n: lua_Unsigned);
|
||||
pub fn lua_pushvector(L: *mut lua_State, x: c_float, y: c_float, z: c_float);
|
||||
#[link_name = "lua_pushlstring"]
|
||||
pub fn lua_pushlstring_(L: *mut lua_State, s: *const c_char, l: usize);
|
||||
#[link_name = "lua_pushstring"]
|
||||
pub fn lua_pushstring_(L: *mut lua_State, s: *const c_char);
|
||||
// lua_pushvfstring
|
||||
#[link_name = "lua_pushfstringL"]
|
||||
pub fn lua_pushfstring(L: *mut lua_State, fmt: *const c_char, ...) -> *const c_char;
|
||||
pub fn lua_pushcclosurek(
|
||||
L: *mut lua_State,
|
||||
f: lua_CFunction,
|
||||
debugname: *const c_char,
|
||||
nup: c_int,
|
||||
cont: Option<lua_Continuation>,
|
||||
);
|
||||
pub fn lua_pushboolean(L: *mut lua_State, b: c_int);
|
||||
pub fn lua_pushthread(L: *mut lua_State) -> c_int;
|
||||
|
||||
pub fn lua_pushlightuserdata(L: *mut lua_State, p: *mut c_void);
|
||||
pub fn lua_newuserdatatagged(L: *mut lua_State, sz: usize, tag: c_int) -> *mut c_void;
|
||||
pub fn lua_newuserdatadtor(L: *mut lua_State, sz: usize, dtor: lua_Udestructor) -> *mut c_void;
|
||||
|
||||
//
|
||||
// Get functions (Lua -> stack)
|
||||
//
|
||||
pub fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int;
|
||||
pub fn lua_rawgetfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int;
|
||||
pub fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
#[link_name = "lua_rawgeti"]
|
||||
pub fn lua_rawgeti_(L: *mut lua_State, idx: c_int, n: c_int) -> c_int;
|
||||
pub fn lua_createtable(L: *mut lua_State, narr: c_int, nrec: c_int);
|
||||
|
||||
pub fn lua_setreadonly(L: *mut lua_State, idx: c_int, enabled: c_int);
|
||||
pub fn lua_getreadonly(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_setsafeenv(L: *mut lua_State, idx: c_int, enabled: c_int);
|
||||
|
||||
pub fn lua_getmetatable(L: *mut lua_State, objindex: c_int) -> c_int;
|
||||
pub fn lua_getfenv(L: *mut lua_State, idx: c_int);
|
||||
|
||||
//
|
||||
// Set functions (stack -> Lua)
|
||||
//
|
||||
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_rawset(L: *mut lua_State, idx: c_int);
|
||||
#[link_name = "lua_rawseti"]
|
||||
pub fn lua_rawseti_(L: *mut lua_State, idx: c_int, n: c_int);
|
||||
pub fn lua_setmetatable(L: *mut lua_State, objindex: c_int) -> c_int;
|
||||
pub fn lua_setfenv(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
|
||||
//
|
||||
// `load' and `call' functions (load and run Luau bytecode)
|
||||
//
|
||||
pub fn luau_load(
|
||||
L: *mut lua_State,
|
||||
chunkname: *const c_char,
|
||||
data: *const c_char,
|
||||
size: usize,
|
||||
env: c_int,
|
||||
) -> c_int;
|
||||
pub fn lua_call(L: *mut lua_State, nargs: c_int, nresults: c_int);
|
||||
pub fn lua_pcall(L: *mut lua_State, nargs: c_int, nresults: c_int, errfunc: c_int) -> c_int;
|
||||
|
||||
//
|
||||
// Coroutine functions
|
||||
//
|
||||
pub fn lua_yield(L: *mut lua_State, nresults: c_int) -> c_int;
|
||||
pub fn lua_break(L: *mut lua_State) -> c_int;
|
||||
#[link_name = "lua_resume"]
|
||||
pub fn lua_resume_(L: *mut lua_State, from: *mut lua_State, narg: c_int) -> c_int;
|
||||
pub fn lua_resumeerror(L: *mut lua_State, from: *mut lua_State) -> c_int;
|
||||
pub fn lua_status(L: *mut lua_State) -> c_int;
|
||||
pub fn lua_isyieldable(L: *mut lua_State) -> c_int;
|
||||
pub fn lua_getthreaddata(L: *mut lua_State) -> *mut c_void;
|
||||
pub fn lua_setthreaddata(L: *mut lua_State, data: *mut c_void);
|
||||
}
|
||||
|
||||
//
|
||||
// Garbage-collection function and options
|
||||
//
|
||||
pub const LUA_GCSTOP: c_int = 0;
|
||||
pub const LUA_GCRESTART: c_int = 1;
|
||||
pub const LUA_GCCOLLECT: c_int = 2;
|
||||
pub const LUA_GCCOUNT: c_int = 3;
|
||||
pub const LUA_GCCOUNTB: c_int = 4;
|
||||
pub const LUA_GCISRUNNING: c_int = 5;
|
||||
pub const LUA_GCSTEP: c_int = 6;
|
||||
pub const LUA_GCSETGOAL: c_int = 7;
|
||||
pub const LUA_GCSETSTEPMUL: c_int = 8;
|
||||
pub const LUA_GCSETSTEPSIZE: c_int = 9;
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int;
|
||||
}
|
||||
|
||||
//
|
||||
// Memory statistics
|
||||
//
|
||||
extern "C" {
|
||||
pub fn lua_setmemcat(L: *mut lua_State, category: c_int);
|
||||
pub fn lua_totalbytes(L: *mut lua_State, category: c_int) -> usize;
|
||||
}
|
||||
|
||||
//
|
||||
// Miscellaneous functions
|
||||
//
|
||||
extern "C" {
|
||||
pub fn lua_error(L: *mut lua_State) -> !;
|
||||
pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_rawiter(L: *mut lua_State, idx: c_int, iter: c_int) -> c_int;
|
||||
pub fn lua_concat(L: *mut lua_State, n: c_int);
|
||||
// TODO: lua_encodepointer
|
||||
pub fn lua_clock() -> c_double;
|
||||
pub fn lua_setuserdatatag(L: *mut lua_State, idx: c_int, tag: c_int);
|
||||
pub fn lua_setuserdatadtor(
|
||||
L: *mut lua_State,
|
||||
tag: c_int,
|
||||
dtor: Option<unsafe extern "C" fn(*mut lua_State, *mut c_void)>,
|
||||
);
|
||||
pub fn lua_clonefunction(L: *mut lua_State, idx: c_int);
|
||||
pub fn lua_cleartable(L: *mut lua_State, idx: c_int);
|
||||
}
|
||||
|
||||
//
|
||||
// Reference system, can be used to pin objects
|
||||
//
|
||||
pub const LUA_NOREF: c_int = -1;
|
||||
pub const LUA_REFNIL: c_int = 0;
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_ref(L: *mut lua_State, idx: c_int) -> c_int;
|
||||
pub fn lua_unref(L: *mut lua_State, r#ref: c_int);
|
||||
}
|
||||
|
||||
//
|
||||
// Some useful macros (implemented as Rust functions)
|
||||
//
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number {
|
||||
lua_tonumberx(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tointeger_(L: *mut lua_State, i: c_int) -> lua_Integer {
|
||||
lua_tointegerx_(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tounsigned(L: *mut lua_State, i: c_int) -> lua_Unsigned {
|
||||
lua_tounsignedx(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pop(L: *mut lua_State, n: c_int) {
|
||||
lua_settop(L, -n - 1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_newtable(L: *mut lua_State) {
|
||||
lua_createtable(L, 0, 0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_newuserdata(L: *mut lua_State, sz: usize) -> *mut c_void {
|
||||
lua_newuserdatatagged(L, sz, 0)
|
||||
}
|
||||
|
||||
// TODO: lua_strlen
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isfunction(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TFUNCTION) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_istable(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TTABLE) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_islightuserdata(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TLIGHTUSERDATA) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TNIL) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isboolean(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TBOOLEAN) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isvector(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TVECTOR) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isthread(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TTHREAD) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnone(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) == LUA_TNONE) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_isnoneornil(L: *mut lua_State, n: c_int) -> c_int {
|
||||
(lua_type(L, n) <= LUA_TNIL) as c_int
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &'static str) {
|
||||
use std::ffi::CString;
|
||||
let c_str = CString::new(s).unwrap();
|
||||
lua_pushlstring_(L, c_str.as_ptr(), c_str.as_bytes().len())
|
||||
}
|
||||
|
||||
pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) {
|
||||
lua_pushcclosurek(L, f, ptr::null(), 0, None)
|
||||
}
|
||||
|
||||
pub unsafe fn lua_pushcfunctiond(L: *mut lua_State, f: lua_CFunction, debugname: *const c_char) {
|
||||
lua_pushcclosurek(L, f, debugname, 0, None)
|
||||
}
|
||||
|
||||
pub unsafe fn lua_pushcclosure(L: *mut lua_State, f: lua_CFunction, nup: c_int) {
|
||||
lua_pushcclosurek(L, f, ptr::null(), nup, None)
|
||||
}
|
||||
|
||||
pub unsafe fn lua_pushcclosured(
|
||||
L: *mut lua_State,
|
||||
f: lua_CFunction,
|
||||
debugname: *const c_char,
|
||||
nup: c_int,
|
||||
) {
|
||||
lua_pushcclosurek(L, f, debugname, nup, None)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_setglobal(L: *mut lua_State, var: *const c_char) {
|
||||
lua_setfield(L, LUA_GLOBALSINDEX, var)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int {
|
||||
lua_getfield(L, LUA_GLOBALSINDEX, var)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char {
|
||||
lua_tolstring(L, i, ptr::null_mut())
|
||||
}
|
||||
|
||||
//
|
||||
// Debug API
|
||||
//
|
||||
|
||||
// Maximum size for the description of the source of a function in debug information.
|
||||
const LUA_IDSIZE: usize = 256;
|
||||
|
||||
/// Type for functions to be called on debug events.
|
||||
pub type lua_Hook = unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug);
|
||||
|
||||
pub type lua_Coverage = unsafe extern "C" fn(
|
||||
context: *mut c_void,
|
||||
function: *const c_char,
|
||||
linedefined: c_int,
|
||||
depth: c_int,
|
||||
hits: *const c_int,
|
||||
size: usize,
|
||||
);
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_stackdepth(L: *mut lua_State) -> c_int;
|
||||
pub fn lua_getinfo(
|
||||
L: *mut lua_State,
|
||||
level: c_int,
|
||||
what: *const c_char,
|
||||
ar: *mut lua_Debug,
|
||||
) -> c_int;
|
||||
pub fn lua_getargument(L: *mut lua_State, level: c_int, n: c_int) -> c_int;
|
||||
pub fn lua_getlocal(L: *mut lua_State, level: c_int, n: c_int) -> *const c_char;
|
||||
pub fn lua_setlocal(L: *mut lua_State, level: 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_singlestep(L: *mut lua_State, enabled: c_int);
|
||||
pub fn lua_breakpoint(
|
||||
L: *mut lua_State,
|
||||
funcindex: c_int,
|
||||
line: c_int,
|
||||
enabled: c_int,
|
||||
) -> c_int;
|
||||
|
||||
pub fn lua_getcoverage(
|
||||
L: *mut lua_State,
|
||||
funcindex: c_int,
|
||||
context: *mut c_void,
|
||||
callback: lua_Coverage,
|
||||
);
|
||||
|
||||
pub fn lua_debugtrace(L: *mut lua_State) -> *const c_char;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct lua_Debug {
|
||||
pub name: *const c_char,
|
||||
pub what: *const c_char,
|
||||
pub source: *const c_char,
|
||||
pub short_src: *const c_char,
|
||||
pub linedefined: c_int,
|
||||
pub currentline: c_int,
|
||||
pub nupvals: u8,
|
||||
pub nparams: u8,
|
||||
pub isvararg: c_char,
|
||||
pub userdata: *mut c_void,
|
||||
pub ssbuf: [c_char; LUA_IDSIZE],
|
||||
}
|
||||
|
||||
//
|
||||
// Callbacks that can be used to reconfigure behavior of the VM dynamically.
|
||||
// These are shared between all coroutines.
|
||||
//
|
||||
|
||||
#[repr(C)]
|
||||
pub struct lua_Callbacks {
|
||||
/// arbitrary userdata pointer that is never overwritten by Luau
|
||||
pub userdata: *mut c_void,
|
||||
|
||||
/// gets called at safepoints (loop back edges, call/ret, gc) if set
|
||||
pub interrupt: Option<unsafe extern "C" fn(L: *mut lua_State, gc: c_int)>,
|
||||
/// gets called when an unprotected error is raised (if longjmp is used)
|
||||
pub panic: Option<unsafe extern "C" fn(L: *mut lua_State, errcode: c_int)>,
|
||||
|
||||
/// gets called when L is created (LP == parent) or destroyed (LP == NULL)
|
||||
pub userthread: Option<unsafe extern "C" fn(LP: *mut lua_State, L: *mut lua_State)>,
|
||||
/// gets called when a string is created; returned atom can be retrieved via tostringatom
|
||||
pub useratom: Option<unsafe extern "C" fn(s: *const c_char, l: usize) -> i16>,
|
||||
|
||||
/// gets called when BREAK instruction is encountered
|
||||
pub debugbreak: Option<unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug)>,
|
||||
/// gets called after each instruction in single step mode
|
||||
pub debugstep: Option<unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug)>,
|
||||
/// gets called when thread execution is interrupted by break in another thread
|
||||
pub debuginterrupt: Option<unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug)>,
|
||||
/// gets called when protected call results in an error
|
||||
pub debugprotectederror: Option<unsafe extern "C" fn(L: *mut lua_State)>,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn lua_callbacks(L: *mut lua_State) -> *mut lua_Callbacks;
|
||||
}
|
39
src/ffi/luau/luacode.rs
Normal file
39
src/ffi/luau/luacode.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
//! Contains definitions from `luacode.h`.
|
||||
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::slice;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct lua_CompileOptions {
|
||||
pub optimizationLevel: c_int,
|
||||
pub debugLevel: c_int,
|
||||
pub coverageLevel: c_int,
|
||||
pub vectorLib: *const c_char,
|
||||
pub vectorCtor: *const c_char,
|
||||
pub mutableGlobals: *mut *const c_char,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "luau_compile"]
|
||||
pub fn luau_compile_(
|
||||
source: *const c_char,
|
||||
size: usize,
|
||||
options: *mut lua_CompileOptions,
|
||||
outsize: *mut usize,
|
||||
) -> *mut c_char;
|
||||
|
||||
fn free(p: *mut c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn luau_compile(source: &[u8], mut options: lua_CompileOptions) -> Vec<u8> {
|
||||
let mut outsize = 0;
|
||||
let data_ptr = luau_compile_(
|
||||
source.as_ptr() as *const c_char,
|
||||
source.len(),
|
||||
&mut options,
|
||||
&mut outsize,
|
||||
);
|
||||
let data = slice::from_raw_parts(data_ptr as *mut u8, outsize).to_vec();
|
||||
free(data_ptr as *mut c_void);
|
||||
data
|
||||
}
|
29
src/ffi/luau/lualib.rs
Normal file
29
src/ffi/luau/lualib.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
//! Contains definitions from `lualib.h`.
|
||||
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use super::lua::lua_State;
|
||||
|
||||
pub const LUA_COLIBNAME: &str = "coroutine";
|
||||
pub const LUA_TABLIBNAME: &str = "table";
|
||||
pub const LUA_OSLIBNAME: &str = "os";
|
||||
pub const LUA_STRLIBNAME: &str = "string";
|
||||
pub const LUA_BITLIBNAME: &str = "bit32";
|
||||
pub const LUA_UTF8LIBNAME: &str = "utf8";
|
||||
pub const LUA_MATHLIBNAME: &str = "math";
|
||||
pub const LUA_DBLIBNAME: &str = "debug";
|
||||
|
||||
extern "C" {
|
||||
pub fn luaopen_base(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_os(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_string(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_bit32(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_utf8(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_math(L: *mut lua_State) -> c_int;
|
||||
pub fn luaopen_debug(L: *mut lua_State) -> c_int;
|
||||
|
||||
// open all builtin libraries
|
||||
pub fn luaL_openlibs(L: *mut lua_State);
|
||||
}
|
13
src/ffi/luau/mod.rs
Normal file
13
src/ffi/luau/mod.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
//! Low level bindings to Luau.
|
||||
|
||||
pub use compat::*;
|
||||
pub use lauxlib::*;
|
||||
pub use lua::*;
|
||||
pub use luacode::*;
|
||||
pub use lualib::*;
|
||||
|
||||
pub mod compat;
|
||||
pub mod lauxlib;
|
||||
pub mod lua;
|
||||
pub mod luacode;
|
||||
pub mod lualib;
|
315
src/ffi/mod.rs
315
src/ffi/mod.rs
|
@ -1,265 +1,42 @@
|
|||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2019-2021 A. Orlenko
|
||||
// Copyright (c) 2014 J.C. Moyer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
//! Low level bindings to Lua.
|
||||
//! Low level bindings to Lua 5.4/5.3/5.2/5.1 including LuaJIT.
|
||||
|
||||
#![allow(non_camel_case_types, non_snake_case, dead_code)]
|
||||
|
||||
use std::os::raw::c_int;
|
||||
|
||||
// This is more or less in the order it appears in the Lua manual, with the
|
||||
// exception of constants, which appear scattered throughout the manual text.
|
||||
|
||||
// C API types
|
||||
pub use self::lua::{
|
||||
lua_Alloc, lua_CFunction, lua_Debug, lua_Hook, lua_Integer, lua_Number, lua_Reader, lua_State,
|
||||
lua_Unsigned, lua_Writer,
|
||||
};
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
pub use self::lua::lua_WarnFunction;
|
||||
pub use lua54::*;
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub use self::lua::{lua_KContext, lua_KFunction};
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub use self::lua::{lua_getfenv, lua_setfenv};
|
||||
|
||||
// C API functions
|
||||
pub use self::lua::{
|
||||
lua_absindex,
|
||||
lua_arith,
|
||||
lua_atpanic,
|
||||
lua_call,
|
||||
lua_checkstack,
|
||||
lua_close,
|
||||
lua_compare,
|
||||
lua_concat,
|
||||
lua_copy,
|
||||
lua_createtable,
|
||||
lua_dump,
|
||||
lua_error,
|
||||
lua_gc,
|
||||
lua_getallocf,
|
||||
lua_getextraspace,
|
||||
lua_getfield,
|
||||
lua_getglobal,
|
||||
lua_gethook,
|
||||
lua_gethookcount,
|
||||
lua_gethookmask,
|
||||
lua_geti,
|
||||
lua_getinfo,
|
||||
lua_getlocal,
|
||||
lua_getmetatable,
|
||||
lua_getstack,
|
||||
lua_gettable,
|
||||
lua_gettop,
|
||||
lua_getupvalue,
|
||||
lua_getuservalue,
|
||||
lua_insert,
|
||||
lua_isboolean,
|
||||
lua_iscfunction,
|
||||
lua_isfunction,
|
||||
lua_isinteger,
|
||||
lua_islightuserdata,
|
||||
lua_isnil,
|
||||
lua_isnone,
|
||||
lua_isnoneornil,
|
||||
lua_isnumber,
|
||||
lua_isstring,
|
||||
lua_istable,
|
||||
lua_isthread,
|
||||
lua_isuserdata,
|
||||
lua_len,
|
||||
lua_load,
|
||||
lua_newstate,
|
||||
lua_newtable,
|
||||
lua_newthread,
|
||||
lua_newuserdata,
|
||||
lua_next,
|
||||
lua_pcall,
|
||||
lua_pop,
|
||||
lua_pushboolean,
|
||||
lua_pushcclosure,
|
||||
lua_pushcfunction,
|
||||
lua_pushfstring,
|
||||
lua_pushglobaltable,
|
||||
lua_pushinteger,
|
||||
lua_pushlightuserdata,
|
||||
lua_pushliteral,
|
||||
lua_pushlstring,
|
||||
lua_pushnil,
|
||||
lua_pushnumber,
|
||||
lua_pushstring,
|
||||
lua_pushthread,
|
||||
lua_pushvalue,
|
||||
// omitted: lua_pushvfstring
|
||||
lua_rawequal,
|
||||
lua_rawget,
|
||||
lua_rawgeti,
|
||||
lua_rawgetp,
|
||||
lua_rawlen,
|
||||
lua_rawset,
|
||||
lua_rawseti,
|
||||
lua_rawsetp,
|
||||
lua_register,
|
||||
lua_remove,
|
||||
lua_replace,
|
||||
lua_resume,
|
||||
lua_rotate,
|
||||
lua_setallocf,
|
||||
lua_setfield,
|
||||
lua_setglobal,
|
||||
lua_sethook,
|
||||
lua_seti,
|
||||
lua_setlocal,
|
||||
lua_setmetatable,
|
||||
lua_settable,
|
||||
lua_settop,
|
||||
lua_setupvalue,
|
||||
lua_setuservalue,
|
||||
lua_status,
|
||||
lua_stringtonumber,
|
||||
lua_toboolean,
|
||||
lua_tocfunction,
|
||||
lua_tointeger,
|
||||
lua_tointegerx,
|
||||
lua_tolstring,
|
||||
lua_tonumber,
|
||||
lua_tonumberx,
|
||||
lua_topointer,
|
||||
lua_tostring,
|
||||
lua_tothread,
|
||||
lua_touserdata,
|
||||
lua_type,
|
||||
lua_typename,
|
||||
lua_upvalueindex,
|
||||
lua_xmove,
|
||||
lua_yield,
|
||||
};
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
pub use self::lua::{
|
||||
lua_getiuservalue, lua_newuserdatauv, lua_setcstacklimit, lua_setiuservalue, lua_setwarnf,
|
||||
lua_toclose, lua_warning,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub use self::lua::{lua_isyieldable, lua_version};
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub use self::lua::{lua_callk, lua_pcallk, lua_upvalueid, lua_upvaluejoin, lua_yieldk};
|
||||
|
||||
#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored")))]
|
||||
pub use self::lua::lua_resetthread;
|
||||
|
||||
// auxiliary library types
|
||||
pub use self::lauxlib::luaL_Reg;
|
||||
|
||||
// auxiliary library functions
|
||||
pub use self::lauxlib::{
|
||||
luaL_argcheck, luaL_argerror, luaL_callmeta, luaL_checkany, luaL_checkint, luaL_checkinteger,
|
||||
luaL_checklong, luaL_checklstring, luaL_checknumber, luaL_checkoption, luaL_checkstack,
|
||||
luaL_checkstring, luaL_checktype, luaL_checkudata, luaL_checkversion, luaL_dofile,
|
||||
luaL_dostring, luaL_error, luaL_getmetafield, luaL_getmetatable, luaL_getsubtable, luaL_gsub,
|
||||
luaL_len, luaL_loadbuffer, luaL_loadbufferx, luaL_loadfile, luaL_loadstring, luaL_newlib,
|
||||
luaL_newlibtable, luaL_newmetatable, luaL_newstate, luaL_optint, luaL_optinteger, luaL_optlong,
|
||||
luaL_optlstring, luaL_optnumber, luaL_optstring, luaL_ref, luaL_requiref, luaL_setfuncs,
|
||||
luaL_setmetatable, luaL_testudata, luaL_tolstring, luaL_traceback, luaL_typename, luaL_unref,
|
||||
luaL_where,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub use self::lauxlib::{luaL_execresult, luaL_fileresult, luaL_loadfilex};
|
||||
|
||||
// lualib.h functions
|
||||
pub use self::lualib::{
|
||||
luaL_openlibs, luaopen_base, luaopen_debug, luaopen_io, luaopen_math, luaopen_os,
|
||||
luaopen_package, luaopen_string, luaopen_table,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub use self::lualib::{luaopen_coroutine, luaopen_utf8};
|
||||
#[cfg(feature = "lua53")]
|
||||
pub use lua53::*;
|
||||
|
||||
#[cfg(feature = "lua52")]
|
||||
pub use self::lualib::{luaopen_bit32, luaopen_coroutine};
|
||||
|
||||
#[cfg(feature = "luajit")]
|
||||
pub use self::lualib::{luaopen_bit, luaopen_ffi, luaopen_jit};
|
||||
|
||||
// constants from lua.h
|
||||
pub use self::lua::{
|
||||
LUA_ERRERR, LUA_ERRMEM, LUA_ERRRUN, LUA_ERRSYNTAX, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCCOUNTB,
|
||||
LUA_GCRESTART, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, LUA_GCSTEP, LUA_GCSTOP, LUA_HOOKCALL,
|
||||
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_OPLE, LUA_OPLT, LUA_OPMOD, LUA_OPMUL, LUA_OPPOW, LUA_OPSUB, LUA_OPUNM, LUA_REGISTRYINDEX,
|
||||
LUA_SIGNATURE, LUA_TBOOLEAN, LUA_TFUNCTION, LUA_TLIGHTUSERDATA, LUA_TNIL, LUA_TNONE,
|
||||
LUA_TNUMBER, LUA_TRACEBACK_STACK, LUA_TSTRING, LUA_TTABLE, LUA_TTHREAD, LUA_TUSERDATA,
|
||||
LUA_YIELD,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub use self::lua::{
|
||||
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"))]
|
||||
pub use self::lua::LUA_ERRGCMM;
|
||||
pub use lua52::*;
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub use self::lua::{LUA_ENVIRONINDEX, LUA_GLOBALSINDEX};
|
||||
pub use lua51::*;
|
||||
|
||||
#[cfg(feature = "luajit")]
|
||||
pub use self::lua::LUA_TCDATA;
|
||||
#[cfg(feature = "luau")]
|
||||
pub use luau::*;
|
||||
|
||||
// constants from lauxlib.h
|
||||
pub use self::lauxlib::{LUA_ERRFILE, LUA_NOREF, LUA_REFNIL};
|
||||
|
||||
// constants from lualib.h
|
||||
pub use self::lualib::{
|
||||
LUA_COLIBNAME, LUA_DBLIBNAME, LUA_IOLIBNAME, LUA_LOADLIBNAME, LUA_MATHLIBNAME, LUA_OSLIBNAME,
|
||||
LUA_STRLIBNAME, LUA_TABLIBNAME,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
pub use self::lualib::LUA_UTF8LIBNAME;
|
||||
|
||||
#[cfg(any(feature = "lua52", feature = "luajit"))]
|
||||
pub use self::lualib::LUA_BITLIBNAME;
|
||||
|
||||
#[cfg(feature = "luajit")]
|
||||
pub use self::lualib::{LUA_FFILIBNAME, LUA_JITLIBNAME};
|
||||
|
||||
// Not actually defined in lua.h / luaconf.h
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub const LUA_MAX_UPVALUES: c_int = 255;
|
||||
|
||||
#[cfg(any(feature = "lua51", all(feature = "luajit", not(feature = "vendored"))))]
|
||||
pub const LUA_MAX_UPVALUES: c_int = 60;
|
||||
|
||||
#[cfg(all(feature = "luajit", feature = "vendored"))]
|
||||
pub const LUA_MAX_UPVALUES: c_int = 120;
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
pub const LUA_MAX_UPVALUES: c_int = 200;
|
||||
|
||||
// I believe `luaL_traceback` < 5.4 requires this much free stack to not error.
|
||||
// 5.4 uses `luaL_Buffer`
|
||||
pub const LUA_TRACEBACK_STACK: c_int = 11;
|
||||
|
||||
// The minimum alignment guaranteed by the architecture. This value is used to
|
||||
// add fast paths for low alignment values.
|
||||
// Copied from https://github.com/rust-lang/rust/blob/master/library/std/src/sys/common/alloc.rs
|
||||
#[cfg(all(any(
|
||||
target_arch = "x86",
|
||||
|
@ -271,7 +48,8 @@ pub const LUA_MAX_UPVALUES: c_int = 255;
|
|||
target_arch = "asmjs",
|
||||
target_arch = "wasm32",
|
||||
target_arch = "hexagon",
|
||||
target_arch = "riscv32"
|
||||
all(target_arch = "riscv32", not(target_os = "espidf")),
|
||||
all(target_arch = "xtensa", not(target_os = "espidf")),
|
||||
)))]
|
||||
pub const SYS_MIN_ALIGN: usize = 8;
|
||||
#[cfg(all(any(
|
||||
|
@ -280,12 +58,20 @@ pub const SYS_MIN_ALIGN: usize = 8;
|
|||
target_arch = "mips64",
|
||||
target_arch = "s390x",
|
||||
target_arch = "sparc64",
|
||||
target_arch = "riscv64"
|
||||
target_arch = "riscv64",
|
||||
target_arch = "wasm64",
|
||||
)))]
|
||||
pub const SYS_MIN_ALIGN: usize = 16;
|
||||
// The allocator on the esp-idf platform guarentees 4 byte alignment.
|
||||
#[cfg(all(any(
|
||||
all(target_arch = "riscv32", target_os = "espidf"),
|
||||
all(target_arch = "xtensa", target_os = "espidf"),
|
||||
)))]
|
||||
pub const SYS_MIN_ALIGN: usize = 4;
|
||||
|
||||
// Hack to avoid stripping a few unused Lua symbols that could be imported
|
||||
// by C modules in unsafe mode
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub(crate) fn keep_lua_symbols() {
|
||||
let mut symbols: Vec<*const extern "C" fn()> = Vec::new();
|
||||
symbols.push(lua_atpanic as _);
|
||||
|
@ -293,26 +79,25 @@ pub(crate) fn keep_lua_symbols() {
|
|||
symbols.push(lua_tocfunction as _);
|
||||
symbols.push(luaL_loadstring as _);
|
||||
symbols.push(luaL_openlibs as _);
|
||||
if cfg!(any(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52"
|
||||
))) {
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
{
|
||||
symbols.push(lua_getglobal as _);
|
||||
symbols.push(lua_setglobal as _);
|
||||
symbols.push(luaL_setfuncs as _);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_imports, dead_code, non_camel_case_types)]
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
mod glue {
|
||||
include!(concat!(env!("OUT_DIR"), "/glue.rs"));
|
||||
}
|
||||
#[cfg(feature = "lua54")]
|
||||
pub mod lua54;
|
||||
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
mod compat53;
|
||||
#[cfg(feature = "lua53")]
|
||||
pub mod lua53;
|
||||
|
||||
mod lauxlib;
|
||||
mod lua;
|
||||
mod luaconf;
|
||||
mod lualib;
|
||||
#[cfg(feature = "lua52")]
|
||||
pub mod lua52;
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub mod lua51;
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
pub mod luau;
|
||||
|
|
179
src/function.rs
179
src/function.rs
|
@ -1,3 +1,4 @@
|
|||
use std::mem;
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
|
@ -5,7 +6,9 @@ use std::slice;
|
|||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::types::LuaRef;
|
||||
use crate::util::{assert_stack, check_stack, error_traceback, pop_error, StackGuard};
|
||||
use crate::util::{
|
||||
assert_stack, check_stack, error_traceback, pop_error, ptr_to_cstr_bytes, StackGuard,
|
||||
};
|
||||
use crate::value::{FromLuaMulti, ToLuaMulti};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
|
@ -15,6 +18,29 @@ use {futures_core::future::LocalBoxFuture, futures_util::future};
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct Function<'lua>(pub(crate) LuaRef<'lua>);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FunctionInfo {
|
||||
pub name: Option<Vec<u8>>,
|
||||
pub name_what: Option<Vec<u8>>,
|
||||
pub what: Option<Vec<u8>>,
|
||||
pub source: Option<Vec<u8>>,
|
||||
pub short_src: Option<Vec<u8>>,
|
||||
pub line_defined: i32,
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub last_line_defined: i32,
|
||||
}
|
||||
|
||||
/// Luau function coverage snapshot.
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct CoverageInfo {
|
||||
pub function: Option<std::string::String>,
|
||||
pub line_defined: i32,
|
||||
pub depth: i32,
|
||||
pub hits: Vec<i32>,
|
||||
}
|
||||
|
||||
impl<'lua> Function<'lua> {
|
||||
/// Calls the function, passing `args` as function arguments.
|
||||
///
|
||||
|
@ -88,7 +114,7 @@ impl<'lua> Function<'lua> {
|
|||
R::from_lua_multi(results, lua)
|
||||
}
|
||||
|
||||
/// Returns a Feature that, when polled, calls `self`, passing `args` as function arguments,
|
||||
/// Returns a future that, when polled, calls `self`, passing `args` as function arguments,
|
||||
/// and drives the execution.
|
||||
///
|
||||
/// Internally it wraps the function to an [`AsyncThread`].
|
||||
|
@ -164,24 +190,19 @@ impl<'lua> Function<'lua> {
|
|||
/// # }
|
||||
/// ```
|
||||
pub fn bind<A: ToLuaMulti<'lua>>(&self, args: A) -> Result<Function<'lua>> {
|
||||
unsafe extern "C" fn bind_call_impl(state: *mut ffi::lua_State) -> c_int {
|
||||
unsafe extern "C" fn args_wrapper_impl(state: *mut ffi::lua_State) -> c_int {
|
||||
let nargs = ffi::lua_gettop(state);
|
||||
let nbinds = ffi::lua_tointeger(state, ffi::lua_upvalueindex(2)) as c_int;
|
||||
ffi::luaL_checkstack(state, nbinds + 2, ptr::null());
|
||||
|
||||
ffi::lua_settop(state, nargs + nbinds + 1);
|
||||
ffi::lua_rotate(state, -(nargs + nbinds + 1), nbinds + 1);
|
||||
|
||||
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(1));
|
||||
ffi::lua_replace(state, 1);
|
||||
let nbinds = ffi::lua_tointeger(state, ffi::lua_upvalueindex(1)) as c_int;
|
||||
ffi::luaL_checkstack(state, nbinds, ptr::null());
|
||||
|
||||
for i in 0..nbinds {
|
||||
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(i + 3));
|
||||
ffi::lua_replace(state, i + 2);
|
||||
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(i + 2));
|
||||
}
|
||||
if nargs > 0 {
|
||||
ffi::lua_rotate(state, 1, nbinds);
|
||||
}
|
||||
|
||||
ffi::lua_call(state, nargs + nbinds, ffi::LUA_MULTRET);
|
||||
ffi::lua_gettop(state)
|
||||
nargs + nbinds
|
||||
}
|
||||
|
||||
let lua = self.0.lua;
|
||||
|
@ -189,24 +210,77 @@ impl<'lua> Function<'lua> {
|
|||
let args = args.to_lua_multi(lua)?;
|
||||
let nargs = args.len() as c_int;
|
||||
|
||||
if nargs + 2 > ffi::LUA_MAX_UPVALUES {
|
||||
if nargs == 0 {
|
||||
return Ok(self.clone());
|
||||
}
|
||||
|
||||
if nargs + 1 > ffi::LUA_MAX_UPVALUES {
|
||||
return Err(Error::BindError);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let args_wrapper = unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, nargs + 5)?;
|
||||
check_stack(lua.state, nargs + 3)?;
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
ffi::lua_pushinteger(lua.state, nargs as ffi::lua_Integer);
|
||||
for arg in args {
|
||||
lua.push_value(arg)?;
|
||||
}
|
||||
protect_lua!(lua.state, nargs + 2, 1, fn(state) {
|
||||
ffi::lua_pushcclosure(state, bind_call_impl, ffi::lua_gettop(state));
|
||||
protect_lua!(lua.state, nargs + 1, 1, fn(state) {
|
||||
ffi::lua_pushcclosure(state, args_wrapper_impl, ffi::lua_gettop(state));
|
||||
})?;
|
||||
|
||||
Ok(Function(lua.pop_ref()))
|
||||
Function(lua.pop_ref())
|
||||
};
|
||||
|
||||
lua.load(
|
||||
r#"
|
||||
local func, args_wrapper = ...
|
||||
return function(...)
|
||||
return func(args_wrapper(...))
|
||||
end
|
||||
"#,
|
||||
)
|
||||
.try_cache()
|
||||
.set_name("_mlua_bind")?
|
||||
.call((self.clone(), args_wrapper))
|
||||
}
|
||||
|
||||
/// Returns information about the function.
|
||||
///
|
||||
/// Corresponds to the `>Sn` what mask for [`lua_getinfo`] when applied to the function.
|
||||
///
|
||||
/// [`lua_getinfo`]: https://www.lua.org/manual/5.4/manual.html#lua_getinfo
|
||||
pub fn info(&self) -> FunctionInfo {
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
assert_stack(lua.state, 1);
|
||||
|
||||
let mut ar: ffi::lua_Debug = mem::zeroed();
|
||||
lua.push_ref(&self.0);
|
||||
#[cfg(not(feature = "luau"))]
|
||||
let res = ffi::lua_getinfo(lua.state, cstr!(">Sn"), &mut ar);
|
||||
#[cfg(feature = "luau")]
|
||||
let res = ffi::lua_getinfo(lua.state, -1, cstr!("sn"), &mut ar);
|
||||
mlua_assert!(res != 0, "lua_getinfo failed with `>Sn`");
|
||||
|
||||
FunctionInfo {
|
||||
name: ptr_to_cstr_bytes(ar.name).map(|s| s.to_vec()),
|
||||
#[cfg(not(feature = "luau"))]
|
||||
name_what: ptr_to_cstr_bytes(ar.namewhat).map(|s| s.to_vec()),
|
||||
#[cfg(feature = "luau")]
|
||||
name_what: None,
|
||||
what: ptr_to_cstr_bytes(ar.what).map(|s| s.to_vec()),
|
||||
source: ptr_to_cstr_bytes(ar.source).map(|s| s.to_vec()),
|
||||
#[cfg(not(feature = "luau"))]
|
||||
short_src: ptr_to_cstr_bytes(ar.short_src.as_ptr()).map(|s| s.to_vec()),
|
||||
#[cfg(feature = "luau")]
|
||||
short_src: ptr_to_cstr_bytes(ar.short_src).map(|s| s.to_vec()),
|
||||
line_defined: ar.linedefined,
|
||||
#[cfg(not(feature = "luau"))]
|
||||
last_line_defined: ar.lastlinedefined,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,6 +288,12 @@ impl<'lua> Function<'lua> {
|
|||
///
|
||||
/// If `strip` is true, the binary representation may not include all debug information
|
||||
/// about the function, to save space.
|
||||
///
|
||||
/// For Luau a [Compiler] can be used to compile Lua chunks to bytecode.
|
||||
///
|
||||
/// [Compiler]: crate::chunk::Compiler
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
||||
pub fn dump(&self, strip: bool) -> Vec<u8> {
|
||||
unsafe extern "C" fn writer(
|
||||
_state: *mut ffi::lua_State,
|
||||
|
@ -235,13 +315,64 @@ impl<'lua> Function<'lua> {
|
|||
|
||||
lua.push_ref(&self.0);
|
||||
let data_ptr = &mut data as *mut Vec<u8> as *mut c_void;
|
||||
let strip = if strip { 1 } else { 0 };
|
||||
ffi::lua_dump(lua.state, writer, data_ptr, strip);
|
||||
ffi::lua_dump(lua.state, writer, data_ptr, strip as i32);
|
||||
ffi::lua_pop(lua.state, 1);
|
||||
}
|
||||
|
||||
data
|
||||
}
|
||||
|
||||
/// Retrieves recorded coverage information about this Lua function including inner calls.
|
||||
///
|
||||
/// This function takes a callback as an argument and calls it providing [`CoverageInfo`] snapshot
|
||||
/// per each executed inner function.
|
||||
///
|
||||
/// Recording of coverage information is controlled by [`Compiler::set_coverage_level`] option.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
///
|
||||
/// [`Compiler::set_coverage_level`]: crate::chunk::Compiler::set_coverage_level
|
||||
#[cfg(any(feature = "luau", docsrs))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn coverage<F>(&self, mut func: F)
|
||||
where
|
||||
F: FnMut(CoverageInfo),
|
||||
{
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::c_char;
|
||||
|
||||
unsafe extern "C" fn callback<F: FnMut(CoverageInfo)>(
|
||||
data: *mut c_void,
|
||||
function: *const c_char,
|
||||
line_defined: c_int,
|
||||
depth: c_int,
|
||||
hits: *const c_int,
|
||||
size: usize,
|
||||
) {
|
||||
let function = if !function.is_null() {
|
||||
Some(CStr::from_ptr(function).to_string_lossy().to_string())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let rust_callback = &mut *(data as *mut F);
|
||||
rust_callback(CoverageInfo {
|
||||
function,
|
||||
line_defined,
|
||||
depth,
|
||||
hits: slice::from_raw_parts(hits, size).to_vec(),
|
||||
});
|
||||
}
|
||||
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
assert_stack(lua.state, 1);
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
let func_ptr = &mut func as *mut F as *mut c_void;
|
||||
ffi::lua_getcoverage(lua.state, -1, func_ptr, callback::<F>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> PartialEq for Function<'lua> {
|
||||
|
|
113
src/hook.rs
113
src/hook.rs
|
@ -1,10 +1,11 @@
|
|||
use std::cell::UnsafeCell;
|
||||
use std::ffi::CStr;
|
||||
#[cfg(not(feature = "luau"))]
|
||||
use std::ops::{BitOr, BitOrAssign};
|
||||
use std::os::raw::{c_char, c_int};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use crate::ffi::{self, lua_Debug};
|
||||
use crate::lua::Lua;
|
||||
use crate::util::ptr_to_cstr_bytes;
|
||||
|
||||
/// Contains information about currently executing Lua code.
|
||||
///
|
||||
|
@ -18,9 +19,12 @@ use crate::lua::Lua;
|
|||
pub struct Debug<'lua> {
|
||||
lua: &'lua Lua,
|
||||
ar: ActivationRecord,
|
||||
#[cfg(feature = "luau")]
|
||||
level: c_int,
|
||||
}
|
||||
|
||||
impl<'lua> Debug<'lua> {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub(crate) fn new(lua: &'lua Lua, ar: *mut lua_Debug) -> Self {
|
||||
Debug {
|
||||
lua,
|
||||
|
@ -28,10 +32,12 @@ impl<'lua> Debug<'lua> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_owned(lua: &'lua Lua, ar: lua_Debug) -> Self {
|
||||
pub(crate) fn new_owned(lua: &'lua Lua, _level: c_int, ar: lua_Debug) -> Self {
|
||||
Debug {
|
||||
lua,
|
||||
ar: ActivationRecord::Owned(UnsafeCell::new(ar)),
|
||||
#[cfg(feature = "luau")]
|
||||
level: _level,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,6 +47,8 @@ impl<'lua> Debug<'lua> {
|
|||
/// from a function that did a tail call.
|
||||
///
|
||||
/// [Lua 5.1]: https://www.lua.org/manual/5.1/manual.html#pdf-LUA_HOOKTAILRET
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
||||
pub fn event(&self) -> DebugEvent {
|
||||
unsafe {
|
||||
match (*self.ar.get()).event {
|
||||
|
@ -57,13 +65,23 @@ impl<'lua> Debug<'lua> {
|
|||
/// Corresponds to the `n` what mask.
|
||||
pub fn names(&self) -> DebugNames<'lua> {
|
||||
unsafe {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, cstr!("n"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `n`"
|
||||
);
|
||||
#[cfg(feature = "luau")]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, self.level, cstr!("n"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `n`"
|
||||
);
|
||||
|
||||
DebugNames {
|
||||
name: ptr_to_str((*self.ar.get()).name),
|
||||
name_what: ptr_to_str((*self.ar.get()).namewhat),
|
||||
name: ptr_to_cstr_bytes((*self.ar.get()).name),
|
||||
#[cfg(not(feature = "luau"))]
|
||||
name_what: ptr_to_cstr_bytes((*self.ar.get()).namewhat),
|
||||
#[cfg(feature = "luau")]
|
||||
name_what: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,16 +89,27 @@ impl<'lua> Debug<'lua> {
|
|||
/// Corresponds to the `S` what mask.
|
||||
pub fn source(&self) -> DebugSource<'lua> {
|
||||
unsafe {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, cstr!("S"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `S`"
|
||||
);
|
||||
#[cfg(feature = "luau")]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, self.level, cstr!("s"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `s`"
|
||||
);
|
||||
|
||||
DebugSource {
|
||||
source: ptr_to_str((*self.ar.get()).source),
|
||||
short_src: ptr_to_str((*self.ar.get()).short_src.as_ptr()),
|
||||
line_defined: (*self.ar.get()).linedefined as i32,
|
||||
last_line_defined: (*self.ar.get()).lastlinedefined as i32,
|
||||
what: ptr_to_str((*self.ar.get()).what),
|
||||
source: ptr_to_cstr_bytes((*self.ar.get()).source),
|
||||
#[cfg(not(feature = "luau"))]
|
||||
short_src: ptr_to_cstr_bytes((*self.ar.get()).short_src.as_ptr()),
|
||||
#[cfg(feature = "luau")]
|
||||
short_src: ptr_to_cstr_bytes((*self.ar.get()).short_src),
|
||||
line_defined: (*self.ar.get()).linedefined,
|
||||
#[cfg(not(feature = "luau"))]
|
||||
last_line_defined: (*self.ar.get()).lastlinedefined,
|
||||
what: ptr_to_cstr_bytes((*self.ar.get()).what),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,16 +117,25 @@ impl<'lua> Debug<'lua> {
|
|||
/// Corresponds to the `l` what mask. Returns the current line.
|
||||
pub fn curr_line(&self) -> i32 {
|
||||
unsafe {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, cstr!("l"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `l`"
|
||||
);
|
||||
(*self.ar.get()).currentline as i32
|
||||
#[cfg(feature = "luau")]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, self.level, cstr!("l"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `l`"
|
||||
);
|
||||
|
||||
(*self.ar.get()).currentline
|
||||
}
|
||||
}
|
||||
|
||||
/// Corresponds to the `t` what mask. Returns true if the hook is in a function tail call, false
|
||||
/// otherwise.
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
||||
pub fn is_tail_call(&self) -> bool {
|
||||
unsafe {
|
||||
mlua_assert!(
|
||||
|
@ -111,22 +149,38 @@ impl<'lua> Debug<'lua> {
|
|||
/// Corresponds to the `u` what mask.
|
||||
pub fn stack(&self) -> DebugStack {
|
||||
unsafe {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, cstr!("u"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `u`"
|
||||
);
|
||||
DebugStack {
|
||||
#[cfg(feature = "luau")]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.lua.state, self.level, cstr!("a"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `a`"
|
||||
);
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
let stack = DebugStack {
|
||||
num_ups: (*self.ar.get()).nups as i32,
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
num_params: (*self.ar.get()).nparams as i32,
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
is_vararg: (*self.ar.get()).isvararg != 0,
|
||||
}
|
||||
};
|
||||
#[cfg(feature = "luau")]
|
||||
let stack = DebugStack {
|
||||
num_ups: (*self.ar.get()).nupvals as i32,
|
||||
num_params: (*self.ar.get()).nparams as i32,
|
||||
is_vararg: (*self.ar.get()).isvararg != 0,
|
||||
};
|
||||
stack
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ActivationRecord {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
Borrowed(*mut lua_Debug),
|
||||
Owned(UnsafeCell<lua_Debug>),
|
||||
}
|
||||
|
@ -135,6 +189,7 @@ impl ActivationRecord {
|
|||
#[inline]
|
||||
fn get(&self) -> *mut lua_Debug {
|
||||
match self {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
ActivationRecord::Borrowed(x) => *x,
|
||||
ActivationRecord::Owned(x) => x.get(),
|
||||
}
|
||||
|
@ -163,6 +218,7 @@ pub struct DebugSource<'a> {
|
|||
pub source: Option<&'a [u8]>,
|
||||
pub short_src: Option<&'a [u8]>,
|
||||
pub line_defined: i32,
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub last_line_defined: i32,
|
||||
pub what: Option<&'a [u8]>,
|
||||
}
|
||||
|
@ -170,15 +226,27 @@ pub struct DebugSource<'a> {
|
|||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct DebugStack {
|
||||
pub num_ups: i32,
|
||||
/// Requires `feature = "lua54/lua53/lua52"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
/// Requires `feature = "lua54/lua53/lua52/luau"`
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luau"
|
||||
))]
|
||||
pub num_params: i32,
|
||||
/// Requires `feature = "lua54/lua53/lua52"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
/// Requires `feature = "lua54/lua53/lua52/luau"`
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luau"
|
||||
))]
|
||||
pub is_vararg: bool,
|
||||
}
|
||||
|
||||
/// Determines when a hook function will be called by Lua.
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct HookTriggers {
|
||||
/// Before a function call.
|
||||
|
@ -196,6 +264,7 @@ pub struct HookTriggers {
|
|||
pub every_nth_instruction: Option<u32>,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
impl HookTriggers {
|
||||
/// Returns a new instance of `HookTriggers` with [`on_calls`] trigger set.
|
||||
///
|
||||
|
@ -262,6 +331,7 @@ impl HookTriggers {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
impl BitOr for HookTriggers {
|
||||
type Output = Self;
|
||||
|
||||
|
@ -276,16 +346,9 @@ impl BitOr for HookTriggers {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
impl BitOrAssign for HookTriggers {
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
*self = *self | rhs;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn ptr_to_str<'a>(input: *const c_char) -> Option<&'a [u8]> {
|
||||
if input.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(CStr::from_ptr(input).to_bytes())
|
||||
}
|
||||
}
|
||||
|
|
20
src/lib.rs
20
src/lib.rs
|
@ -72,7 +72,7 @@
|
|||
//! [`serde::Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html
|
||||
|
||||
// mlua types in rustdoc of other crates get linked to here.
|
||||
#![doc(html_root_url = "https://docs.rs/mlua/0.7.4")]
|
||||
#![doc(html_root_url = "https://docs.rs/mlua/0.8.6")]
|
||||
// Deny warnings inside doc tests / examples. When this isn't present, rustdoc doesn't show *any*
|
||||
// warnings at all.
|
||||
#![doc(test(attr(deny(warnings))))]
|
||||
|
@ -81,12 +81,15 @@
|
|||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
mod chunk;
|
||||
mod conversion;
|
||||
mod error;
|
||||
mod ffi;
|
||||
mod function;
|
||||
mod hook;
|
||||
mod lua;
|
||||
#[cfg(feature = "luau")]
|
||||
mod luau;
|
||||
mod multi;
|
||||
mod scope;
|
||||
mod stdlib;
|
||||
|
@ -95,6 +98,7 @@ mod table;
|
|||
mod thread;
|
||||
mod types;
|
||||
mod userdata;
|
||||
mod userdata_impl;
|
||||
mod util;
|
||||
mod value;
|
||||
|
||||
|
@ -102,10 +106,11 @@ pub mod prelude;
|
|||
|
||||
pub use crate::{ffi::lua_CFunction, ffi::lua_State};
|
||||
|
||||
pub use crate::chunk::{AsChunk, Chunk, ChunkMode};
|
||||
pub use crate::error::{Error, ExternalError, ExternalResult, Result};
|
||||
pub use crate::function::Function;
|
||||
pub use crate::hook::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack, HookTriggers};
|
||||
pub use crate::lua::{AsChunk, Chunk, ChunkMode, GCMode, Lua, LuaOptions};
|
||||
pub use crate::function::{Function, FunctionInfo};
|
||||
pub use crate::hook::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack};
|
||||
pub use crate::lua::{GCMode, Lua, LuaOptions};
|
||||
pub use crate::multi::Variadic;
|
||||
pub use crate::scope::Scope;
|
||||
pub use crate::stdlib::StdLib;
|
||||
|
@ -118,6 +123,13 @@ pub use crate::userdata::{
|
|||
};
|
||||
pub use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value};
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub use crate::hook::HookTriggers;
|
||||
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub use crate::{chunk::Compiler, function::CoverageInfo, types::VmState};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub use crate::thread::AsyncThread;
|
||||
|
||||
|
|
2010
src/lua.rs
2010
src/lua.rs
File diff suppressed because it is too large
Load diff
124
src/luau.rs
Normal file
124
src/luau.rs
Normal file
|
@ -0,0 +1,124 @@
|
|||
use std::ffi::CStr;
|
||||
use std::os::raw::{c_float, c_int};
|
||||
|
||||
use crate::chunk::ChunkMode;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::lua::Lua;
|
||||
use crate::table::Table;
|
||||
use crate::util::{check_stack, StackGuard};
|
||||
use crate::value::Value;
|
||||
|
||||
// Since Luau has some missing standard function, we re-implement them here
|
||||
|
||||
impl Lua {
|
||||
pub(crate) unsafe fn prepare_luau_state(&self) -> Result<()> {
|
||||
let globals = self.globals();
|
||||
|
||||
globals.raw_set(
|
||||
"collectgarbage",
|
||||
self.create_c_function(lua_collectgarbage)?,
|
||||
)?;
|
||||
globals.raw_set("require", self.create_function(lua_require)?)?;
|
||||
globals.raw_set("vector", self.create_c_function(lua_vector)?)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn lua_collectgarbage(state: *mut ffi::lua_State) -> c_int {
|
||||
let option = ffi::luaL_optstring(state, 1, cstr!("collect"));
|
||||
let option = CStr::from_ptr(option);
|
||||
let arg = ffi::luaL_optinteger(state, 2, 0);
|
||||
match option.to_str() {
|
||||
Ok("collect") => {
|
||||
ffi::lua_gc(state, ffi::LUA_GCCOLLECT, 0);
|
||||
0
|
||||
}
|
||||
Ok("stop") => {
|
||||
ffi::lua_gc(state, ffi::LUA_GCSTOP, 0);
|
||||
0
|
||||
}
|
||||
Ok("restart") => {
|
||||
ffi::lua_gc(state, ffi::LUA_GCRESTART, 0);
|
||||
0
|
||||
}
|
||||
Ok("count") => {
|
||||
let kbytes = ffi::lua_gc(state, ffi::LUA_GCCOUNT, 0) as ffi::lua_Number;
|
||||
let kbytes_rem = ffi::lua_gc(state, ffi::LUA_GCCOUNTB, 0) as ffi::lua_Number;
|
||||
ffi::lua_pushnumber(state, kbytes + kbytes_rem / 1024.0);
|
||||
1
|
||||
}
|
||||
Ok("step") => {
|
||||
let res = ffi::lua_gc(state, ffi::LUA_GCSTEP, arg);
|
||||
ffi::lua_pushboolean(state, res);
|
||||
1
|
||||
}
|
||||
Ok("isrunning") => {
|
||||
let res = ffi::lua_gc(state, ffi::LUA_GCISRUNNING, 0);
|
||||
ffi::lua_pushboolean(state, res);
|
||||
1
|
||||
}
|
||||
_ => ffi::luaL_error(state, cstr!("collectgarbage called with invalid option")),
|
||||
}
|
||||
}
|
||||
|
||||
fn lua_require(lua: &Lua, name: Option<std::string::String>) -> Result<Value> {
|
||||
let name = name.ok_or_else(|| Error::RuntimeError("invalid module name".into()))?;
|
||||
|
||||
// Find module in the cache
|
||||
let loaded = unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 2)?;
|
||||
protect_lua!(lua.state, 0, 1, fn(state) {
|
||||
ffi::luaL_getsubtable(state, ffi::LUA_REGISTRYINDEX, cstr!("_LOADED"));
|
||||
})?;
|
||||
Table(lua.pop_ref())
|
||||
};
|
||||
if let Some(v) = loaded.raw_get(name.clone())? {
|
||||
return Ok(v);
|
||||
}
|
||||
|
||||
// Load file from filesystem
|
||||
let mut search_path = std::env::var("LUAU_PATH").unwrap_or_default();
|
||||
if search_path.is_empty() {
|
||||
search_path = "?.luau;?.lua".into();
|
||||
}
|
||||
|
||||
let (mut source, mut source_name) = (None, String::new());
|
||||
for path in search_path.split(';') {
|
||||
let file_path = path.replacen('?', &name, 1);
|
||||
if let Ok(buf) = std::fs::read(&file_path) {
|
||||
source = Some(buf);
|
||||
source_name = file_path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
let source = source.ok_or_else(|| Error::RuntimeError(format!("cannot find '{}'", name)))?;
|
||||
|
||||
let value = lua
|
||||
.load(&source)
|
||||
.set_name(&format!("={}", source_name))?
|
||||
.set_mode(ChunkMode::Text)
|
||||
.call::<_, Value>(())?;
|
||||
|
||||
// Save in the cache
|
||||
loaded.raw_set(
|
||||
name,
|
||||
match value.clone() {
|
||||
Value::Nil => Value::Boolean(true),
|
||||
v => v,
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
// Luau vector datatype constructor
|
||||
unsafe extern "C" fn lua_vector(state: *mut ffi::lua_State) -> c_int {
|
||||
let x = ffi::luaL_checknumber(state, 1) as c_float;
|
||||
let y = ffi::luaL_checknumber(state, 2) as c_float;
|
||||
let z = ffi::luaL_checknumber(state, 3) as c_float;
|
||||
ffi::lua_pushvector(state, x, y, z);
|
||||
1
|
||||
}
|
13
src/multi.rs
13
src/multi.rs
|
@ -11,6 +11,7 @@ use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti};
|
|||
/// Result is convertible to `MultiValue` following the common Lua idiom of returning the result
|
||||
/// on success, or in the case of an error, returning `nil` and an error message.
|
||||
impl<'lua, T: ToLua<'lua>, E: ToLua<'lua>> ToLuaMulti<'lua> for StdResult<T, E> {
|
||||
#[inline]
|
||||
fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
|
||||
let mut result = MultiValue::new_or_cached(lua);
|
||||
match self {
|
||||
|
@ -25,6 +26,7 @@ impl<'lua, T: ToLua<'lua>, E: ToLua<'lua>> ToLuaMulti<'lua> for StdResult<T, E>
|
|||
}
|
||||
|
||||
impl<'lua, T: ToLua<'lua>> ToLuaMulti<'lua> for T {
|
||||
#[inline]
|
||||
fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
|
||||
let mut v = MultiValue::new_or_cached(lua);
|
||||
v.push_front(self.to_lua(lua)?);
|
||||
|
@ -33,6 +35,7 @@ impl<'lua, T: ToLua<'lua>> ToLuaMulti<'lua> for T {
|
|||
}
|
||||
|
||||
impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for T {
|
||||
#[inline]
|
||||
fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
let res = T::from_lua(values.pop_front().unwrap_or(Nil), lua);
|
||||
lua.cache_multivalue(values);
|
||||
|
@ -41,12 +44,14 @@ impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for T {
|
|||
}
|
||||
|
||||
impl<'lua> ToLuaMulti<'lua> for MultiValue<'lua> {
|
||||
#[inline]
|
||||
fn to_lua_multi(self, _: &'lua Lua) -> Result<MultiValue<'lua>> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLuaMulti<'lua> for MultiValue<'lua> {
|
||||
#[inline]
|
||||
fn from_lua_multi(values: MultiValue<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||
Ok(values)
|
||||
}
|
||||
|
@ -83,7 +88,7 @@ pub struct Variadic<T>(Vec<T>);
|
|||
|
||||
impl<T> Variadic<T> {
|
||||
/// Creates an empty `Variadic` wrapper containing no values.
|
||||
pub fn new() -> Variadic<T> {
|
||||
pub const fn new() -> Variadic<T> {
|
||||
Variadic(Vec::new())
|
||||
}
|
||||
}
|
||||
|
@ -124,6 +129,7 @@ impl<T> DerefMut for Variadic<T> {
|
|||
}
|
||||
|
||||
impl<'lua, T: ToLua<'lua>> ToLuaMulti<'lua> for Variadic<T> {
|
||||
#[inline]
|
||||
fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
|
||||
let mut values = MultiValue::new_or_cached(lua);
|
||||
values.refill(self.0.into_iter().map(|e| e.to_lua(lua)))?;
|
||||
|
@ -132,6 +138,7 @@ impl<'lua, T: ToLua<'lua>> ToLuaMulti<'lua> for Variadic<T> {
|
|||
}
|
||||
|
||||
impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for Variadic<T> {
|
||||
#[inline]
|
||||
fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
let res = values
|
||||
.drain_all()
|
||||
|
@ -146,12 +153,14 @@ impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for Variadic<T> {
|
|||
macro_rules! impl_tuple {
|
||||
() => (
|
||||
impl<'lua> ToLuaMulti<'lua> for () {
|
||||
#[inline]
|
||||
fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
|
||||
Ok(MultiValue::new_or_cached(lua))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLuaMulti<'lua> for () {
|
||||
#[inline]
|
||||
fn from_lua_multi(values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
lua.cache_multivalue(values);
|
||||
Ok(())
|
||||
|
@ -166,6 +175,7 @@ macro_rules! impl_tuple {
|
|||
{
|
||||
#[allow(unused_mut)]
|
||||
#[allow(non_snake_case)]
|
||||
#[inline]
|
||||
fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
|
||||
let ($($name,)* $last,) = self;
|
||||
|
||||
|
@ -181,6 +191,7 @@ macro_rules! impl_tuple {
|
|||
{
|
||||
#[allow(unused_mut)]
|
||||
#[allow(non_snake_case)]
|
||||
#[inline]
|
||||
fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
$(let $name = values.pop_front().unwrap_or(Nil);)*
|
||||
let $last = FromLuaMulti::from_lua_multi(values, lua)?;
|
||||
|
|
|
@ -4,17 +4,25 @@
|
|||
pub use crate::{
|
||||
AnyUserData as LuaAnyUserData, Chunk as LuaChunk, Error as LuaError,
|
||||
ExternalError as LuaExternalError, ExternalResult as LuaExternalResult, FromLua, FromLuaMulti,
|
||||
Function as LuaFunction, GCMode as LuaGCMode, Integer as LuaInteger,
|
||||
LightUserData as LuaLightUserData, Lua, LuaOptions, MetaMethod as LuaMetaMethod,
|
||||
MultiValue as LuaMultiValue, Nil as LuaNil, Number as LuaNumber, RegistryKey as LuaRegistryKey,
|
||||
Result as LuaResult, StdLib as LuaStdLib, String as LuaString, Table as LuaTable,
|
||||
TableExt as LuaTableExt, TablePairs as LuaTablePairs, TableSequence as LuaTableSequence,
|
||||
Thread as LuaThread, ThreadStatus as LuaThreadStatus, ToLua, ToLuaMulti,
|
||||
UserData as LuaUserData, UserDataFields as LuaUserDataFields,
|
||||
Function as LuaFunction, FunctionInfo as LuaFunctionInfo, GCMode as LuaGCMode,
|
||||
Integer as LuaInteger, LightUserData as LuaLightUserData, Lua, LuaOptions,
|
||||
MetaMethod as LuaMetaMethod, MultiValue as LuaMultiValue, Nil as LuaNil, Number as LuaNumber,
|
||||
RegistryKey as LuaRegistryKey, Result as LuaResult, StdLib as LuaStdLib, String as LuaString,
|
||||
Table as LuaTable, TableExt as LuaTableExt, TablePairs as LuaTablePairs,
|
||||
TableSequence as LuaTableSequence, Thread as LuaThread, ThreadStatus as LuaThreadStatus, ToLua,
|
||||
ToLuaMulti, UserData as LuaUserData, UserDataFields as LuaUserDataFields,
|
||||
UserDataMetatable as LuaUserDataMetatable, UserDataMethods as LuaUserDataMethods,
|
||||
Value as LuaValue,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::HookTriggers as LuaHookTriggers;
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::{CoverageInfo as LuaCoverageInfo, VmState as LuaVmState};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::AsyncThread as LuaAsyncThread;
|
||||
|
|
54
src/scope.rs
54
src/scope.rs
|
@ -3,7 +3,6 @@ use std::cell::{Cell, RefCell};
|
|||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
|
@ -104,7 +103,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||
{
|
||||
let func = RefCell::new(func);
|
||||
self.create_function(move |lua, args| {
|
||||
(&mut *func
|
||||
(*func
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| Error::RecursiveMutCallback)?)(lua, args)
|
||||
})
|
||||
|
@ -206,7 +205,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||
ffi::lua_pushnil(state);
|
||||
ffi::lua_setiuservalue(state, -2, i as c_int);
|
||||
}
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
#[cfg(any(feature = "lua53", feature = "lua52", feature = "luau"))]
|
||||
{
|
||||
ffi::lua_pushnil(state);
|
||||
ffi::lua_setuservalue(state, -2);
|
||||
|
@ -264,7 +263,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||
fn wrap_method<'scope, 'lua, 'callback: 'scope, T: 'scope>(
|
||||
scope: &Scope<'lua, 'scope>,
|
||||
data: Rc<RefCell<T>>,
|
||||
data_ptr: *const c_void,
|
||||
ud_ptr: *const c_void,
|
||||
method: NonStaticMethod<'callback, T>,
|
||||
) -> Result<Function<'lua>> {
|
||||
// On methods that actually receive the userdata, we fake a type check on the passed in
|
||||
|
@ -280,7 +279,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 2)?;
|
||||
lua.push_userdata_ref(&ud.0)?;
|
||||
if get_userdata(lua.state, -1) as *const _ == data_ptr {
|
||||
if get_userdata(lua.state, -1) as *const _ == ud_ptr {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
@ -307,7 +306,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||
let mut data = data
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| Error::UserDataBorrowMutError)?;
|
||||
(&mut *method)(lua, &mut *data, args)
|
||||
(*method)(lua, &mut *data, args)
|
||||
});
|
||||
unsafe { scope.create_callback(f) }
|
||||
}
|
||||
|
@ -315,7 +314,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||
NonStaticMethod::FunctionMut(function) => {
|
||||
let function = RefCell::new(function);
|
||||
let f = Box::new(move |lua, args| {
|
||||
(&mut *function
|
||||
(*function
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| Error::RecursiveMutCallback)?)(
|
||||
lua, args
|
||||
|
@ -336,8 +335,9 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 13)?;
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[allow(clippy::let_and_return)]
|
||||
let data_ptr = protect_lua!(lua.state, 0, 1, |state| {
|
||||
let ud_ptr = protect_lua!(lua.state, 0, 1, |state| {
|
||||
let ud =
|
||||
ffi::lua_newuserdata(state, mem::size_of::<UserDataCell<Rc<RefCell<T>>>>());
|
||||
|
||||
|
@ -350,13 +350,23 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||
|
||||
ud
|
||||
})?;
|
||||
#[cfg(feature = "luau")]
|
||||
let ud_ptr = {
|
||||
crate::util::push_userdata::<UserDataCell<Rc<RefCell<T>>>>(
|
||||
lua.state,
|
||||
UserDataCell::new(data.clone()),
|
||||
true,
|
||||
)?;
|
||||
ffi::lua_touserdata(lua.state, -1)
|
||||
};
|
||||
|
||||
// Prepare metatable, add meta methods first and then meta fields
|
||||
let meta_methods_nrec = ud_methods.meta_methods.len() + ud_fields.meta_fields.len() + 1;
|
||||
push_table(lua.state, 0, meta_methods_nrec as c_int)?;
|
||||
push_table(lua.state, 0, meta_methods_nrec as c_int, true)?;
|
||||
|
||||
for (k, m) in ud_methods.meta_methods {
|
||||
let data = data.clone();
|
||||
lua.push_value(Value::Function(wrap_method(self, data, data_ptr, m)?))?;
|
||||
lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;
|
||||
rawset_field(lua.state, -2, k.validate()?.name())?;
|
||||
}
|
||||
for (k, f) in ud_fields.meta_fields {
|
||||
|
@ -368,10 +378,10 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||
let mut field_getters_index = None;
|
||||
let field_getters_nrec = ud_fields.field_getters.len();
|
||||
if field_getters_nrec > 0 {
|
||||
push_table(lua.state, 0, field_getters_nrec as c_int)?;
|
||||
push_table(lua.state, 0, field_getters_nrec as c_int, true)?;
|
||||
for (k, m) in ud_fields.field_getters {
|
||||
let data = data.clone();
|
||||
lua.push_value(Value::Function(wrap_method(self, data, data_ptr, m)?))?;
|
||||
lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;
|
||||
rawset_field(lua.state, -2, &k)?;
|
||||
}
|
||||
field_getters_index = Some(ffi::lua_absindex(lua.state, -1));
|
||||
|
@ -380,10 +390,10 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||
let mut field_setters_index = None;
|
||||
let field_setters_nrec = ud_fields.field_setters.len();
|
||||
if field_setters_nrec > 0 {
|
||||
push_table(lua.state, 0, field_setters_nrec as c_int)?;
|
||||
push_table(lua.state, 0, field_setters_nrec as c_int, true)?;
|
||||
for (k, m) in ud_fields.field_setters {
|
||||
let data = data.clone();
|
||||
lua.push_value(Value::Function(wrap_method(self, data, data_ptr, m)?))?;
|
||||
lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;
|
||||
rawset_field(lua.state, -2, &k)?;
|
||||
}
|
||||
field_setters_index = Some(ffi::lua_absindex(lua.state, -1));
|
||||
|
@ -393,10 +403,10 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||
let methods_nrec = ud_methods.methods.len();
|
||||
if methods_nrec > 0 {
|
||||
// Create table used for methods lookup
|
||||
push_table(lua.state, 0, methods_nrec as c_int)?;
|
||||
push_table(lua.state, 0, methods_nrec as c_int, true)?;
|
||||
for (k, m) in ud_methods.methods {
|
||||
let data = data.clone();
|
||||
lua.push_value(Value::Function(wrap_method(self, data, data_ptr, m)?))?;
|
||||
lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;
|
||||
rawset_field(lua.state, -2, &k)?;
|
||||
}
|
||||
methods_index = Some(ffi::lua_absindex(lua.state, -1));
|
||||
|
@ -417,7 +427,8 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||
|
||||
let mt_ptr = ffi::lua_topointer(lua.state, -1);
|
||||
// Write userdata just before attaching metatable with `__gc` metamethod
|
||||
ptr::write(data_ptr as _, UserDataCell::new(data));
|
||||
#[cfg(not(feature = "luau"))]
|
||||
std::ptr::write(ud_ptr as _, UserDataCell::new(data));
|
||||
ffi::lua_setmetatable(lua.state, -2);
|
||||
let ud = AnyUserData(lua.pop_ref());
|
||||
lua.register_userdata_metatable(mt_ptr, None);
|
||||
|
@ -446,7 +457,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||
ffi::lua_pushnil(state);
|
||||
ffi::lua_setiuservalue(state, -2, i as c_int);
|
||||
}
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
#[cfg(any(feature = "lua53", feature = "lua52", feature = "luau"))]
|
||||
{
|
||||
ffi::lua_pushnil(state);
|
||||
ffi::lua_setuservalue(state, -2);
|
||||
|
@ -532,7 +543,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
|||
// 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"))]
|
||||
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
|
||||
ffi::lua_getfenv(state, -1);
|
||||
|
||||
// Second, get the `get_poll()` closure using the corresponding key
|
||||
|
@ -586,6 +597,7 @@ impl<'lua, 'scope> Drop for Scope<'lua, 'scope> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
enum NonStaticMethod<'lua, T> {
|
||||
Method(Box<dyn Fn(&'lua Lua, &T, MultiValue<'lua>) -> Result<MultiValue<'lua>>>),
|
||||
MethodMut(Box<dyn FnMut(&'lua Lua, &mut T, MultiValue<'lua>) -> Result<MultiValue<'lua>>>),
|
||||
|
@ -727,7 +739,7 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
|
|||
));
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "async", not(feature = "lua51")))]
|
||||
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
|
||||
fn add_async_meta_method<S, A, R, M, MR>(&mut self, _meta: S, _method: M)
|
||||
where
|
||||
T: Clone,
|
||||
|
@ -772,7 +784,7 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
|
|||
));
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "async", not(feature = "lua51")))]
|
||||
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
|
||||
fn add_async_meta_function<S, A, R, F, FR>(&mut self, _meta: S, _function: F)
|
||||
where
|
||||
S: Into<MetaMethod>,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::cell::RefCell;
|
||||
use std::convert::TryInto;
|
||||
use std::os::raw::c_void;
|
||||
use std::rc::Rc;
|
||||
use std::string::String as StdString;
|
||||
|
@ -7,7 +8,6 @@ use rustc_hash::FxHashSet;
|
|||
use serde::de::{self, IntoDeserializer};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::table::{Table, TablePairs, TableSequence};
|
||||
use crate::value::Value;
|
||||
|
||||
|
@ -71,7 +71,7 @@ impl Options {
|
|||
///
|
||||
/// [`deny_recursive_tables`]: #structfield.deny_recursive_tables
|
||||
#[must_use]
|
||||
pub fn deny_recursive_tables(mut self, enabled: bool) -> Self {
|
||||
pub const fn deny_recursive_tables(mut self, enabled: bool) -> Self {
|
||||
self.deny_recursive_tables = enabled;
|
||||
self
|
||||
}
|
||||
|
@ -117,9 +117,13 @@ impl<'lua, 'de> serde::Deserializer<'de> for Deserializer<'lua> {
|
|||
Value::Nil => visitor.visit_unit(),
|
||||
Value::Boolean(b) => visitor.visit_bool(b),
|
||||
#[allow(clippy::useless_conversion)]
|
||||
Value::Integer(i) => visitor.visit_i64(i.into()),
|
||||
Value::Integer(i) => {
|
||||
visitor.visit_i64(i.try_into().expect("cannot convert lua_Integer to i64"))
|
||||
}
|
||||
#[allow(clippy::useless_conversion)]
|
||||
Value::Number(n) => visitor.visit_f64(n.into()),
|
||||
#[cfg(feature = "luau")]
|
||||
Value::Vector(_, _, _) => self.deserialize_seq(visitor),
|
||||
Value::String(s) => match s.to_str() {
|
||||
Ok(s) => visitor.visit_str(s),
|
||||
Err(_) => visitor.visit_bytes(s.as_bytes()),
|
||||
|
@ -211,6 +215,16 @@ impl<'lua, 'de> serde::Deserializer<'de> for Deserializer<'lua> {
|
|||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self.value {
|
||||
#[cfg(feature = "luau")]
|
||||
Value::Vector(x, y, z) => {
|
||||
let mut deserializer = VecDeserializer {
|
||||
vec: [x, y, z],
|
||||
next: 0,
|
||||
options: self.options,
|
||||
visited: self.visited,
|
||||
};
|
||||
visitor.visit_seq(&mut deserializer)
|
||||
}
|
||||
Value::Table(t) => {
|
||||
let _guard = RecursionGuard::new(&t, &self.visited);
|
||||
|
||||
|
@ -305,10 +319,17 @@ impl<'lua, 'de> serde::Deserializer<'de> for Deserializer<'lua> {
|
|||
self.deserialize_map(visitor)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_newtype_struct(self)
|
||||
}
|
||||
|
||||
serde::forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes
|
||||
byte_buf unit unit_struct newtype_struct
|
||||
identifier ignored_any
|
||||
byte_buf unit unit_struct identifier ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,6 +370,39 @@ impl<'lua, 'de> de::SeqAccess<'de> for SeqDeserializer<'lua> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
struct VecDeserializer {
|
||||
vec: [f32; 3],
|
||||
next: usize,
|
||||
options: Options,
|
||||
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
impl<'de> de::SeqAccess<'de> for VecDeserializer {
|
||||
type Error = Error;
|
||||
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
|
||||
where
|
||||
T: de::DeserializeSeed<'de>,
|
||||
{
|
||||
match self.vec.get(self.next) {
|
||||
Some(&n) => {
|
||||
self.next += 1;
|
||||
let visited = Rc::clone(&self.visited);
|
||||
let deserializer =
|
||||
Deserializer::from_parts(Value::Number(n as _), self.options, visited);
|
||||
seed.deserialize(deserializer).map(Some)
|
||||
}
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> Option<usize> {
|
||||
Some(3)
|
||||
}
|
||||
}
|
||||
|
||||
struct MapDeserializer<'lua> {
|
||||
pairs: TablePairs<'lua, Value<'lua>, Value<'lua>>,
|
||||
value: Option<Value<'lua>>,
|
||||
|
@ -508,9 +562,7 @@ impl RecursionGuard {
|
|||
#[inline]
|
||||
fn new(table: &Table, visited: &Rc<RefCell<FxHashSet<*const c_void>>>) -> Self {
|
||||
let visited = Rc::clone(visited);
|
||||
let lua = table.0.lua;
|
||||
let ptr =
|
||||
unsafe { lua.ref_thread_exec(|refthr| ffi::lua_topointer(refthr, table.0.index)) };
|
||||
let ptr = table.to_pointer();
|
||||
visited.borrow_mut().insert(ptr);
|
||||
RecursionGuard { ptr, visited }
|
||||
}
|
||||
|
@ -530,9 +582,7 @@ fn check_value_if_skip(
|
|||
) -> Result<bool> {
|
||||
match value {
|
||||
Value::Table(table) => {
|
||||
let lua = table.0.lua;
|
||||
let ptr =
|
||||
unsafe { lua.ref_thread_exec(|refthr| ffi::lua_topointer(refthr, table.0.index)) };
|
||||
let ptr = table.to_pointer();
|
||||
if visited.borrow().contains(&ptr) {
|
||||
if options.deny_recursive_tables {
|
||||
return Err(de::Error::custom("recursive table detected"));
|
||||
|
|
|
@ -10,10 +10,11 @@ use crate::ffi;
|
|||
use crate::lua::Lua;
|
||||
use crate::table::Table;
|
||||
use crate::types::LightUserData;
|
||||
use crate::util::{assert_stack, check_stack, StackGuard};
|
||||
use crate::util::check_stack;
|
||||
use crate::value::Value;
|
||||
|
||||
/// Trait for serializing/deserializing Lua values using Serde.
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
|
||||
pub trait LuaSerdeExt<'lua> {
|
||||
/// A special value (lightuserdata) to encode/decode optional (none) values.
|
||||
///
|
||||
|
@ -157,6 +158,7 @@ pub trait LuaSerdeExt<'lua> {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
fn from_value<T: Deserialize<'lua>>(&'lua self, value: Value<'lua>) -> Result<T>;
|
||||
|
||||
/// Deserializes a [`Value`] into any serde deserializable object with options.
|
||||
|
@ -188,6 +190,7 @@ pub trait LuaSerdeExt<'lua> {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
fn from_value_with<T: Deserialize<'lua>>(
|
||||
&'lua self,
|
||||
value: Value<'lua>,
|
||||
|
@ -202,12 +205,8 @@ impl<'lua> LuaSerdeExt<'lua> for Lua {
|
|||
|
||||
fn array_metatable(&'lua self) -> Table<'lua> {
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(self.state);
|
||||
assert_stack(self.state, 1);
|
||||
|
||||
push_array_metatable(self.state);
|
||||
|
||||
Table(self.pop_ref())
|
||||
push_array_metatable(self.ref_thread());
|
||||
Table(self.pop_ref_thread())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,7 +255,7 @@ pub(crate) unsafe fn init_metatables(state: *mut ffi::lua_State) -> Result<()> {
|
|||
}
|
||||
|
||||
pub(crate) unsafe fn push_array_metatable(state: *mut ffi::lua_State) {
|
||||
let array_metatable_key = &ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void;
|
||||
let array_metatable_key = &ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *const c_void;
|
||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, array_metatable_key);
|
||||
}
|
||||
|
||||
|
|
|
@ -327,10 +327,17 @@ impl<'lua> ser::SerializeSeq for SerializeVec<'lua> {
|
|||
|
||||
lua.push_ref(&self.table.0);
|
||||
lua.push_value(value)?;
|
||||
protect_lua!(lua.state, 2, 0, fn(state) {
|
||||
let len = ffi::lua_rawlen(state, -2) as Integer;
|
||||
ffi::lua_rawseti(state, -2, len + 1);
|
||||
})
|
||||
if lua.unlikely_memory_error() {
|
||||
let len = ffi::lua_rawlen(lua.state, -2) as Integer;
|
||||
ffi::lua_rawseti(lua.state, -2, len + 1);
|
||||
ffi::lua_pop(lua.state, 1);
|
||||
Ok(())
|
||||
} else {
|
||||
protect_lua!(lua.state, 2, 0, fn(state) {
|
||||
let len = ffi::lua_rawlen(state, -2) as Integer;
|
||||
ffi::lua_rawseti(state, -2, len + 1);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,19 @@ pub struct StdLib(u32);
|
|||
impl StdLib {
|
||||
/// [`coroutine`](https://www.lua.org/manual/5.4/manual.html#6.2) library
|
||||
///
|
||||
/// Requires `feature = "lua54/lua53/lua52"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
/// Requires `feature = "lua54/lua53/lua52/luau"`
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luau"
|
||||
))]
|
||||
pub const COROUTINE: StdLib = StdLib(1);
|
||||
/// [`table`](https://www.lua.org/manual/5.4/manual.html#6.6) library
|
||||
pub const TABLE: StdLib = StdLib(1 << 1);
|
||||
/// [`io`](https://www.lua.org/manual/5.4/manual.html#6.8) library
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
||||
pub const IO: StdLib = StdLib(1 << 2);
|
||||
/// [`os`](https://www.lua.org/manual/5.4/manual.html#6.9) library
|
||||
pub const OS: StdLib = StdLib(1 << 3);
|
||||
|
@ -21,28 +28,32 @@ impl StdLib {
|
|||
pub const STRING: StdLib = StdLib(1 << 4);
|
||||
/// [`utf8`](https://www.lua.org/manual/5.4/manual.html#6.5) library
|
||||
///
|
||||
/// Requires `feature = "lua54/lua53"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
/// Requires `feature = "lua54/lua53/luau"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))]
|
||||
pub const UTF8: StdLib = StdLib(1 << 5);
|
||||
/// [`bit`](https://www.lua.org/manual/5.2/manual.html#6.7) library
|
||||
///
|
||||
/// Requires `feature = "lua52/luajit"`
|
||||
#[cfg(any(feature = "lua52", feature = "luajit", doc))]
|
||||
/// Requires `feature = "lua52/luajit/luau"`
|
||||
#[cfg(any(feature = "lua52", feature = "luajit", feature = "luau", doc))]
|
||||
pub const BIT: StdLib = StdLib(1 << 6);
|
||||
/// [`math`](https://www.lua.org/manual/5.4/manual.html#6.7) library
|
||||
pub const MATH: StdLib = StdLib(1 << 7);
|
||||
/// [`package`](https://www.lua.org/manual/5.4/manual.html#6.3) library
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
||||
pub const PACKAGE: StdLib = StdLib(1 << 8);
|
||||
/// [`jit`](http://luajit.org/ext_jit.html) library
|
||||
///
|
||||
/// Requires `feature = "luajit"`
|
||||
#[cfg(any(feature = "luajit", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luajit")))]
|
||||
pub const JIT: StdLib = StdLib(1 << 9);
|
||||
|
||||
/// (**unsafe**) [`ffi`](http://luajit.org/ext_ffi.html) library
|
||||
///
|
||||
/// Requires `feature = "luajit"`
|
||||
#[cfg(any(feature = "luajit", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luajit")))]
|
||||
pub const FFI: StdLib = StdLib(1 << 30);
|
||||
/// (**unsafe**) [`debug`](https://www.lua.org/manual/5.4/manual.html#6.10) library
|
||||
pub const DEBUG: StdLib = StdLib(1 << 31);
|
||||
|
@ -52,7 +63,10 @@ impl StdLib {
|
|||
/// (**unsafe**) All standard libraries
|
||||
pub const ALL: StdLib = StdLib(u32::MAX);
|
||||
/// The safe subset of the standard libraries
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub const ALL_SAFE: StdLib = StdLib((1 << 30) - 1);
|
||||
#[cfg(feature = "luau")]
|
||||
pub const ALL_SAFE: StdLib = StdLib(u32::MAX);
|
||||
|
||||
pub fn contains(self, lib: Self) -> bool {
|
||||
(self & lib).0 != 0
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use std::borrow::Cow;
|
||||
use std::borrow::{Borrow, Cow};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::os::raw::c_void;
|
||||
use std::string::String as StdString;
|
||||
use std::{slice, str};
|
||||
|
||||
|
@ -11,7 +13,6 @@ use {
|
|||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::types::LuaRef;
|
||||
use crate::util::{assert_stack, StackGuard};
|
||||
|
||||
/// Handle to an internal Lua string.
|
||||
///
|
||||
|
@ -38,6 +39,7 @@ impl<'lua> String<'lua> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn to_str(&self) -> Result<&str> {
|
||||
str::from_utf8(self.as_bytes()).map_err(|e| Error::FromLuaConversionError {
|
||||
from: "string",
|
||||
|
@ -64,6 +66,7 @@ impl<'lua> String<'lua> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn to_string_lossy(&self) -> Cow<'_, str> {
|
||||
StdString::from_utf8_lossy(self.as_bytes())
|
||||
}
|
||||
|
@ -85,6 +88,7 @@ impl<'lua> String<'lua> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
let nulled = self.as_bytes_with_nul();
|
||||
&nulled[..nulled.len() - 1]
|
||||
|
@ -92,25 +96,32 @@ impl<'lua> String<'lua> {
|
|||
|
||||
/// Get the bytes that make up this string, including the trailing nul byte.
|
||||
pub fn as_bytes_with_nul(&self) -> &[u8] {
|
||||
let lua = self.0.lua;
|
||||
let ref_thread = self.0.lua.ref_thread();
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
assert_stack(lua.state, 1);
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
mlua_debug_assert!(
|
||||
ffi::lua_type(lua.state, -1) == ffi::LUA_TSTRING,
|
||||
ffi::lua_type(ref_thread, self.0.index) == ffi::LUA_TSTRING,
|
||||
"string ref is not string type"
|
||||
);
|
||||
|
||||
let mut size = 0;
|
||||
// This will not trigger a 'm' error, because the reference is guaranteed to be of
|
||||
// string type
|
||||
let data = ffi::lua_tolstring(lua.state, -1, &mut size);
|
||||
let data = ffi::lua_tolstring(ref_thread, self.0.index, &mut size);
|
||||
|
||||
slice::from_raw_parts(data as *const u8, size + 1)
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the string to a generic C pointer.
|
||||
///
|
||||
/// There is no way to convert the pointer back to its original value.
|
||||
///
|
||||
/// Typically this function is used only for hashing and debug information.
|
||||
#[inline]
|
||||
pub fn to_pointer(&self) -> *const c_void {
|
||||
let ref_thread = self.0.lua.ref_thread();
|
||||
unsafe { ffi::lua_topointer(ref_thread, self.0.index) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsRef<[u8]> for String<'lua> {
|
||||
|
@ -119,6 +130,12 @@ impl<'lua> AsRef<[u8]> for String<'lua> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'lua> Borrow<[u8]> for String<'lua> {
|
||||
fn borrow(&self) -> &[u8] {
|
||||
self.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
// Lua strings are basically &[u8] slices, so implement PartialEq for anything resembling that.
|
||||
//
|
||||
// This makes our `String` comparable with `Vec<u8>`, `[u8]`, `&str`, `String` and `mlua::String`
|
||||
|
@ -136,6 +153,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'lua> Eq for String<'lua> {}
|
||||
|
||||
impl<'lua> Hash for String<'lua> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.as_bytes().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
impl<'lua> Serialize for String<'lua> {
|
||||
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
|
||||
|
|
207
src/table.rs
207
src/table.rs
|
@ -1,10 +1,11 @@
|
|||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_void;
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
use {
|
||||
rustc_hash::FxHashSet,
|
||||
serde::ser::{self, Serialize, SerializeMap, SerializeSeq, Serializer},
|
||||
std::{cell::RefCell, os::raw::c_void, result::Result as StdResult},
|
||||
std::{cell::RefCell, result::Result as StdResult},
|
||||
};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
|
@ -57,6 +58,11 @@ impl<'lua> Table<'lua> {
|
|||
///
|
||||
/// [`raw_set`]: #method.raw_set
|
||||
pub fn set<K: ToLua<'lua>, V: ToLua<'lua>>(&self, key: K, value: V) -> Result<()> {
|
||||
// Fast track
|
||||
if !self.has_metatable() {
|
||||
return self.raw_set(key, value);
|
||||
}
|
||||
|
||||
let lua = self.0.lua;
|
||||
let key = key.to_lua(lua)?;
|
||||
let value = value.to_lua(lua)?;
|
||||
|
@ -97,6 +103,11 @@ impl<'lua> Table<'lua> {
|
|||
///
|
||||
/// [`raw_get`]: #method.raw_get
|
||||
pub fn get<K: ToLua<'lua>, V: FromLua<'lua>>(&self, key: K) -> Result<V> {
|
||||
// Fast track
|
||||
if !self.has_metatable() {
|
||||
return self.raw_get(key);
|
||||
}
|
||||
|
||||
let lua = self.0.lua;
|
||||
let key = key.to_lua(lua)?;
|
||||
|
||||
|
@ -115,18 +126,54 @@ impl<'lua> Table<'lua> {
|
|||
|
||||
/// Checks whether the table contains a non-nil value for `key`.
|
||||
pub fn contains_key<K: ToLua<'lua>>(&self, key: K) -> Result<bool> {
|
||||
let lua = self.0.lua;
|
||||
let key = key.to_lua(lua)?;
|
||||
Ok(self.get::<_, Value>(key)? != Value::Nil)
|
||||
}
|
||||
|
||||
/// Appends a value to the back of the table.
|
||||
pub fn push<V: ToLua<'lua>>(&self, value: V) -> Result<()> {
|
||||
// Fast track
|
||||
if !self.has_metatable() {
|
||||
return self.raw_push(value);
|
||||
}
|
||||
|
||||
let lua = self.0.lua;
|
||||
let value = value.to_lua(lua)?;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 4)?;
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
lua.push_value(key)?;
|
||||
protect_lua!(lua.state, 2, 1, fn(state) ffi::lua_gettable(state, -2))?;
|
||||
Ok(ffi::lua_isnil(lua.state, -1) == 0)
|
||||
lua.push_value(value)?;
|
||||
protect_lua!(lua.state, 2, 0, fn(state) {
|
||||
let len = ffi::luaL_len(state, -2) as Integer;
|
||||
ffi::lua_seti(state, -2, len + 1);
|
||||
})?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes the last element from the table and returns it.
|
||||
pub fn pop<V: FromLua<'lua>>(&self) -> Result<V> {
|
||||
// Fast track
|
||||
if !self.has_metatable() {
|
||||
return self.raw_pop();
|
||||
}
|
||||
|
||||
let lua = self.0.lua;
|
||||
let value = unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 4)?;
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
protect_lua!(lua.state, 1, 1, fn(state) {
|
||||
let len = ffi::luaL_len(state, -1) as Integer;
|
||||
ffi::lua_geti(state, -1, len);
|
||||
ffi::lua_pushnil(state);
|
||||
ffi::lua_seti(state, -3, len);
|
||||
})?;
|
||||
lua.pop_value()
|
||||
};
|
||||
V::from_lua(value, lua)
|
||||
}
|
||||
|
||||
/// Compares two tables for equality.
|
||||
|
@ -187,6 +234,9 @@ impl<'lua> Table<'lua> {
|
|||
|
||||
/// Sets a key-value pair without invoking metamethods.
|
||||
pub fn raw_set<K: ToLua<'lua>, V: ToLua<'lua>>(&self, key: K, value: V) -> Result<()> {
|
||||
#[cfg(feature = "luau")]
|
||||
self.check_readonly_write()?;
|
||||
|
||||
let lua = self.0.lua;
|
||||
let key = key.to_lua(lua)?;
|
||||
let value = value.to_lua(lua)?;
|
||||
|
@ -198,7 +248,14 @@ impl<'lua> Table<'lua> {
|
|||
lua.push_ref(&self.0);
|
||||
lua.push_value(key)?;
|
||||
lua.push_value(value)?;
|
||||
protect_lua!(lua.state, 3, 0, fn(state) ffi::lua_rawset(state, -3))
|
||||
|
||||
if lua.unlikely_memory_error() {
|
||||
ffi::lua_rawset(lua.state, -3);
|
||||
ffi::lua_pop(lua.state, 1);
|
||||
Ok(())
|
||||
} else {
|
||||
protect_lua!(lua.state, 3, 0, fn(state) ffi::lua_rawset(state, -3))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,6 +304,56 @@ impl<'lua> Table<'lua> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Appends a value to the back of the table without invoking metamethods.
|
||||
pub fn raw_push<V: ToLua<'lua>>(&self, value: V) -> Result<()> {
|
||||
#[cfg(feature = "luau")]
|
||||
self.check_readonly_write()?;
|
||||
|
||||
let lua = self.0.lua;
|
||||
let value = value.to_lua(lua)?;
|
||||
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 4)?;
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
lua.push_value(value)?;
|
||||
|
||||
unsafe fn callback(state: *mut ffi::lua_State) {
|
||||
let len = ffi::lua_rawlen(state, -2) as Integer;
|
||||
ffi::lua_rawseti(state, -2, len + 1);
|
||||
}
|
||||
|
||||
if lua.unlikely_memory_error() {
|
||||
callback(lua.state);
|
||||
} else {
|
||||
protect_lua!(lua.state, 2, 0, fn(state) callback(state))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes the last element from the table and returns it, without invoking metamethods.
|
||||
pub fn raw_pop<V: FromLua<'lua>>(&self) -> Result<V> {
|
||||
#[cfg(feature = "luau")]
|
||||
self.check_readonly_write()?;
|
||||
|
||||
let lua = self.0.lua;
|
||||
let value = unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 3)?;
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
let len = ffi::lua_rawlen(lua.state, -1) as Integer;
|
||||
ffi::lua_rawgeti(lua.state, -1, len);
|
||||
// Set slot to nil (it must be safe to do)
|
||||
ffi::lua_pushnil(lua.state);
|
||||
ffi::lua_rawseti(lua.state, -3, len);
|
||||
lua.pop_value()
|
||||
};
|
||||
V::from_lua(value, lua)
|
||||
}
|
||||
|
||||
/// Removes a key from the table.
|
||||
///
|
||||
/// If `key` is an integer, mlua shifts down the elements from `table[key+1]`,
|
||||
|
@ -288,6 +395,11 @@ impl<'lua> Table<'lua> {
|
|||
///
|
||||
/// [`raw_len`]: #method.raw_len
|
||||
pub fn len(&self) -> Result<Integer> {
|
||||
// Fast track
|
||||
if !self.has_metatable() {
|
||||
return Ok(self.raw_len());
|
||||
}
|
||||
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
|
@ -300,14 +412,8 @@ impl<'lua> Table<'lua> {
|
|||
|
||||
/// Returns the result of the Lua `#` operator, without invoking the `__len` metamethod.
|
||||
pub fn raw_len(&self) -> Integer {
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
assert_stack(lua.state, 1);
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
ffi::lua_rawlen(lua.state, -1) as Integer
|
||||
}
|
||||
let ref_thread = self.0.lua.ref_thread();
|
||||
unsafe { ffi::lua_rawlen(ref_thread, self.0.index) as Integer }
|
||||
}
|
||||
|
||||
/// Returns a reference to the metatable of this table, or `None` if no metatable is set.
|
||||
|
@ -333,6 +439,12 @@ impl<'lua> Table<'lua> {
|
|||
/// If `metatable` is `None`, the metatable is removed (if no metatable is set, this does
|
||||
/// nothing).
|
||||
pub fn set_metatable(&self, metatable: Option<Table<'lua>>) {
|
||||
// Workaround to throw readonly error without returning Result
|
||||
#[cfg(feature = "luau")]
|
||||
if self.is_readonly() {
|
||||
panic!("attempt to modify a readonly table");
|
||||
}
|
||||
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
|
@ -348,6 +460,58 @@ impl<'lua> Table<'lua> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns true if the table has metatable attached.
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub fn has_metatable(&self) -> bool {
|
||||
let ref_thread = self.0.lua.ref_thread();
|
||||
unsafe {
|
||||
if ffi::lua_getmetatable(ref_thread, self.0.index) != 0 {
|
||||
ffi::lua_pop(ref_thread, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Sets `readonly` attribute on the table.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn set_readonly(&self, enabled: bool) {
|
||||
let ref_thread = self.0.lua.ref_thread();
|
||||
unsafe {
|
||||
ffi::lua_setreadonly(ref_thread, self.0.index, enabled as _);
|
||||
if !enabled {
|
||||
// Reset "safeenv" flag
|
||||
ffi::lua_setsafeenv(ref_thread, self.0.index, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `readonly` attribute of the table.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub fn is_readonly(&self) -> bool {
|
||||
let ref_thread = self.0.lua.ref_thread();
|
||||
unsafe { ffi::lua_getreadonly(ref_thread, self.0.index) != 0 }
|
||||
}
|
||||
|
||||
/// Converts the table to a generic C pointer.
|
||||
///
|
||||
/// Different tables will give different pointers.
|
||||
/// There is no way to convert the pointer back to its original value.
|
||||
///
|
||||
/// Typically this function is used only for hashing and debug information.
|
||||
#[inline]
|
||||
pub fn to_pointer(&self) -> *const c_void {
|
||||
let ref_thread = self.0.lua.ref_thread();
|
||||
unsafe { ffi::lua_topointer(ref_thread, self.0.index) }
|
||||
}
|
||||
|
||||
/// Consume this table and return an iterator over the pairs of the table.
|
||||
///
|
||||
/// This works like the Lua `pairs` function, but does not invoke the `__pairs` metamethod.
|
||||
|
@ -485,6 +649,16 @@ impl<'lua> Table<'lua> {
|
|||
ffi::lua_rawequal(lua.state, -1, -2) != 0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
#[inline(always)]
|
||||
pub(crate) fn check_readonly_write(&self) -> Result<()> {
|
||||
if self.is_readonly() {
|
||||
let err = "attempt to modify a readonly table".to_string();
|
||||
return Err(Error::RuntimeError(err));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> PartialEq for Table<'lua> {
|
||||
|
@ -665,8 +839,7 @@ impl<'lua> Serialize for Table<'lua> {
|
|||
static VISITED: RefCell<FxHashSet<*const c_void>> = RefCell::new(FxHashSet::default());
|
||||
}
|
||||
|
||||
let lua = self.0.lua;
|
||||
let ptr = unsafe { lua.ref_thread_exec(|refthr| ffi::lua_topointer(refthr, self.0.index)) };
|
||||
let ptr = self.to_pointer();
|
||||
let res = VISITED.with(|visited| {
|
||||
{
|
||||
let mut visited = visited.borrow_mut();
|
||||
|
|
119
src/thread.rs
119
src/thread.rs
|
@ -4,10 +4,14 @@ use std::os::raw::c_int;
|
|||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::types::LuaRef;
|
||||
use crate::util::{check_stack, error_traceback, pop_error, StackGuard};
|
||||
use crate::util::{check_stack, error_traceback_thread, pop_error, StackGuard};
|
||||
use crate::value::{FromLuaMulti, ToLuaMulti};
|
||||
|
||||
#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored")))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
all(feature = "luajit", feature = "vendored"),
|
||||
feature = "luau",
|
||||
))]
|
||||
use crate::function::Function;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
|
@ -20,7 +24,6 @@ use {
|
|||
std::{
|
||||
cell::RefCell,
|
||||
marker::PhantomData,
|
||||
os::raw::c_void,
|
||||
pin::Pin,
|
||||
task::{Context, Poll, Waker},
|
||||
},
|
||||
|
@ -115,8 +118,7 @@ impl<'lua> Thread<'lua> {
|
|||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, cmp::max(nargs + 1, 3))?;
|
||||
|
||||
let thread_state =
|
||||
lua.ref_thread_exec(|ref_thread| ffi::lua_tothread(ref_thread, self.0.index));
|
||||
let thread_state = ffi::lua_tothread(lua.ref_thread(), self.0.index);
|
||||
|
||||
let status = ffi::lua_status(thread_state);
|
||||
if status != ffi::LUA_YIELD && ffi::lua_gettop(thread_state) == 0 {
|
||||
|
@ -133,8 +135,12 @@ impl<'lua> Thread<'lua> {
|
|||
|
||||
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 {
|
||||
protect_lua!(lua.state, 0, 0, |_| error_traceback(thread_state))?;
|
||||
return Err(pop_error(thread_state, ret));
|
||||
check_stack(lua.state, 3)?;
|
||||
protect_lua!(lua.state, 0, 1, |state| error_traceback_thread(
|
||||
state,
|
||||
thread_state
|
||||
))?;
|
||||
return Err(pop_error(lua.state, ret));
|
||||
}
|
||||
|
||||
let mut results = args; // Reuse MultiValue container
|
||||
|
@ -153,8 +159,7 @@ impl<'lua> Thread<'lua> {
|
|||
pub fn status(&self) -> ThreadStatus {
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let thread_state =
|
||||
lua.ref_thread_exec(|ref_thread| ffi::lua_tothread(ref_thread, self.0.index));
|
||||
let thread_state = ffi::lua_tothread(lua.ref_thread(), self.0.index);
|
||||
|
||||
let status = ffi::lua_status(thread_state);
|
||||
if status != ffi::LUA_OK && status != ffi::LUA_YIELD {
|
||||
|
@ -173,16 +178,20 @@ impl<'lua> Thread<'lua> {
|
|||
/// Returns a error in case of either the original error that stopped the thread or errors
|
||||
/// in closing methods.
|
||||
///
|
||||
/// In [LuaJIT]: resets to the initial state of a newly created Lua thread.
|
||||
/// In [LuaJIT] and Luau: resets to the initial state of a newly created Lua thread.
|
||||
/// Lua threads in arbitrary states (like yielded or errored) can be reset properly.
|
||||
///
|
||||
/// Sets a Lua function for the thread afterwards.
|
||||
///
|
||||
/// Requires `feature = "lua54"` OR `feature = "luajit,vendored"`
|
||||
/// Requires `feature = "lua54"` OR `feature = "luajit,vendored"` OR `feature = "luau"`
|
||||
///
|
||||
/// [Lua 5.4]: https://www.lua.org/manual/5.4/manual.html#lua_resetthread
|
||||
/// [LuaJIT]: https://github.com/openresty/luajit2#lua_resetthread
|
||||
#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored")))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
all(feature = "luajit", feature = "vendored"),
|
||||
feature = "luau",
|
||||
))]
|
||||
pub fn reset(&self, func: Function<'lua>) -> Result<()> {
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
|
@ -192,14 +201,27 @@ impl<'lua> Thread<'lua> {
|
|||
lua.push_ref(&self.0);
|
||||
let thread_state = ffi::lua_tothread(lua.state, -1);
|
||||
|
||||
let ret = ffi::lua_resetthread(lua.state, thread_state);
|
||||
if ret != ffi::LUA_OK {
|
||||
return Err(pop_error(thread_state, ret));
|
||||
#[cfg(feature = "lua54")]
|
||||
let status = ffi::lua_resetthread(thread_state);
|
||||
#[cfg(feature = "lua54")]
|
||||
if status != ffi::LUA_OK {
|
||||
return Err(pop_error(thread_state, status));
|
||||
}
|
||||
#[cfg(all(feature = "luajit", feature = "vendored"))]
|
||||
ffi::lua_resetthread(lua.state, thread_state);
|
||||
#[cfg(feature = "luau")]
|
||||
ffi::lua_resetthread(thread_state);
|
||||
|
||||
lua.push_ref(&func.0);
|
||||
ffi::lua_xmove(lua.state, thread_state, 1);
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
{
|
||||
// Inherit `LUA_GLOBALSINDEX` from the caller
|
||||
ffi::lua_xpush(lua.state, thread_state, ffi::LUA_GLOBALSINDEX);
|
||||
ffi::lua_replace(thread_state, ffi::LUA_GLOBALSINDEX);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -264,6 +286,53 @@ impl<'lua> Thread<'lua> {
|
|||
recycle: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Enables sandbox mode on this thread.
|
||||
///
|
||||
/// Under the hood replaces the global environment table with a new table,
|
||||
/// that performs writes locally and proxies reads to caller's global environment.
|
||||
///
|
||||
/// This mode ideally should be used together with the global sandbox mode [`Lua::sandbox()`].
|
||||
///
|
||||
/// Please note that Luau links environment table with chunk when loading it into Lua state.
|
||||
/// Therefore you need to load chunks into a thread to link with the thread environment.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use mlua::{Lua, Result};
|
||||
/// # fn main() -> Result<()> {
|
||||
/// let lua = Lua::new();
|
||||
/// let thread = lua.create_thread(lua.create_function(|lua2, ()| {
|
||||
/// lua2.load("var = 123").exec()?;
|
||||
/// assert_eq!(lua2.globals().get::<_, u32>("var")?, 123);
|
||||
/// Ok(())
|
||||
/// })?)?;
|
||||
/// thread.sandbox()?;
|
||||
/// thread.resume(())?;
|
||||
///
|
||||
/// // The global environment should be unchanged
|
||||
/// assert_eq!(lua.globals().get::<_, Option<u32>>("var")?, None);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
#[cfg(any(feature = "luau", docsrs))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
#[doc(hidden)]
|
||||
pub fn sandbox(&self) -> Result<()> {
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let thread = ffi::lua_tothread(lua.ref_thread(), self.0.index);
|
||||
check_stack(thread, 1)?;
|
||||
check_stack(lua.state, 3)?;
|
||||
// Inherit `LUA_GLOBALSINDEX` from the caller
|
||||
ffi::lua_xpush(lua.state, thread, ffi::LUA_GLOBALSINDEX);
|
||||
ffi::lua_replace(thread, ffi::LUA_GLOBALSINDEX);
|
||||
protect_lua!(lua.state, 0, 0, |_| ffi::luaL_sandboxthread(thread))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> PartialEq for Thread<'lua> {
|
||||
|
@ -281,11 +350,25 @@ impl<'lua, R> AsyncThread<'lua, R> {
|
|||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored")))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
all(feature = "luajit", feature = "vendored"),
|
||||
feature = "luau",
|
||||
))]
|
||||
impl<'lua, R> Drop for AsyncThread<'lua, R> {
|
||||
fn drop(&mut self) {
|
||||
if self.recycle {
|
||||
self.thread.0.lua.recycle_thread(&mut self.thread);
|
||||
unsafe {
|
||||
let lua = self.thread.0.lua;
|
||||
// For Lua 5.4 this also closes all pending to-be-closed variables
|
||||
if !lua.recycle_thread(&mut self.thread) {
|
||||
#[cfg(feature = "lua54")]
|
||||
if self.thread.status() == ThreadStatus::Error {
|
||||
let thread_state = ffi::lua_tothread(lua.ref_thread(), self.thread.0.index);
|
||||
ffi::lua_resetthread(thread_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -362,7 +445,7 @@ where
|
|||
fn is_poll_pending(val: &MultiValue) -> bool {
|
||||
match val.iter().enumerate().last() {
|
||||
Some((0, Value::LightUserData(ud))) => {
|
||||
ud.0 == &ASYNC_POLL_PENDING as *const u8 as *mut c_void
|
||||
std::ptr::eq(ud.0 as *const u8, &ASYNC_POLL_PENDING as *const u8)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
|
|
81
src/types.rs
81
src/types.rs
|
@ -1,5 +1,7 @@
|
|||
use std::cell::UnsafeCell;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{fmt, mem, ptr};
|
||||
|
||||
|
@ -11,8 +13,9 @@ use futures_core::future::LocalBoxFuture;
|
|||
|
||||
use crate::error::Result;
|
||||
use crate::ffi;
|
||||
#[cfg(not(feature = "luau"))]
|
||||
use crate::hook::Debug;
|
||||
use crate::lua::Lua;
|
||||
use crate::lua::{ExtraData, Lua};
|
||||
use crate::util::{assert_stack, StackGuard};
|
||||
use crate::value::MultiValue;
|
||||
|
||||
|
@ -28,32 +31,42 @@ pub struct LightUserData(pub *mut c_void);
|
|||
pub(crate) type Callback<'lua, 'a> =
|
||||
Box<dyn Fn(&'lua Lua, MultiValue<'lua>) -> Result<MultiValue<'lua>> + 'a>;
|
||||
|
||||
pub(crate) struct CallbackUpvalue<'lua> {
|
||||
pub(crate) lua: Lua,
|
||||
pub(crate) func: Callback<'lua, 'static>,
|
||||
pub(crate) struct Upvalue<T> {
|
||||
pub(crate) data: T,
|
||||
pub(crate) extra: Arc<UnsafeCell<ExtraData>>,
|
||||
}
|
||||
|
||||
pub(crate) type CallbackUpvalue = Upvalue<Callback<'static, 'static>>;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub(crate) type AsyncCallback<'lua, 'a> =
|
||||
Box<dyn Fn(&'lua Lua, MultiValue<'lua>) -> LocalBoxFuture<'lua, Result<MultiValue<'lua>>> + 'a>;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub(crate) struct AsyncCallbackUpvalue<'lua> {
|
||||
pub(crate) lua: Lua,
|
||||
pub(crate) func: AsyncCallback<'lua, 'static>,
|
||||
}
|
||||
pub(crate) type AsyncCallbackUpvalue = Upvalue<AsyncCallback<'static, 'static>>;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub(crate) struct AsyncPollUpvalue<'lua> {
|
||||
pub(crate) lua: Lua,
|
||||
pub(crate) fut: LocalBoxFuture<'lua, Result<MultiValue<'lua>>>,
|
||||
pub(crate) type AsyncPollUpvalue = Upvalue<LocalBoxFuture<'static, Result<MultiValue<'static>>>>;
|
||||
|
||||
/// Type to set next Luau VM action after executing interrupt function.
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
pub enum VmState {
|
||||
Continue,
|
||||
Yield,
|
||||
}
|
||||
|
||||
#[cfg(feature = "send")]
|
||||
pub(crate) type HookCallback = Arc<Mutex<dyn FnMut(&Lua, Debug) -> Result<()> + Send>>;
|
||||
#[cfg(all(feature = "send", not(feature = "luau")))]
|
||||
pub(crate) type HookCallback = Arc<dyn Fn(&Lua, Debug) -> Result<()> + Send>;
|
||||
|
||||
#[cfg(not(feature = "send"))]
|
||||
pub(crate) type HookCallback = Arc<Mutex<dyn FnMut(&Lua, Debug) -> Result<()>>>;
|
||||
#[cfg(all(not(feature = "send"), not(feature = "luau")))]
|
||||
pub(crate) type HookCallback = Arc<dyn Fn(&Lua, Debug) -> Result<()>>;
|
||||
|
||||
#[cfg(all(feature = "luau", feature = "send"))]
|
||||
pub(crate) type InterruptCallback = Arc<dyn Fn() -> Result<VmState> + Send>;
|
||||
|
||||
#[cfg(all(feature = "luau", not(feature = "send")))]
|
||||
pub(crate) type InterruptCallback = Arc<dyn Fn() -> Result<VmState>>;
|
||||
|
||||
#[cfg(all(feature = "send", feature = "lua54"))]
|
||||
pub(crate) type WarnCallback = Box<dyn Fn(&Lua, &CStr, bool) -> Result<()> + Send>;
|
||||
|
@ -71,7 +84,7 @@ pub trait MaybeSend {}
|
|||
#[cfg(not(feature = "send"))]
|
||||
impl<T> MaybeSend for T {}
|
||||
|
||||
pub(crate) struct DestructedUserdataMT;
|
||||
pub(crate) struct DestructedUserdata;
|
||||
|
||||
/// An auto generated key into the Lua registry.
|
||||
///
|
||||
|
@ -92,6 +105,7 @@ pub(crate) struct DestructedUserdataMT;
|
|||
/// [`AnyUserData::get_user_value`]: crate::AnyUserData::get_user_value
|
||||
pub struct RegistryKey {
|
||||
pub(crate) registry_id: c_int,
|
||||
pub(crate) is_nil: AtomicBool,
|
||||
pub(crate) unref_list: Arc<Mutex<Option<Vec<c_int>>>>,
|
||||
}
|
||||
|
||||
|
@ -117,15 +131,27 @@ impl Eq for RegistryKey {}
|
|||
|
||||
impl Drop for RegistryKey {
|
||||
fn drop(&mut self) {
|
||||
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);
|
||||
// We don't need to collect nil slot
|
||||
if self.registry_id > ffi::LUA_REFNIL {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RegistryKey {
|
||||
// Destroys the RegistryKey without adding to the drop list
|
||||
// Creates a new instance of `RegistryKey`
|
||||
pub(crate) const fn new(id: c_int, unref_list: Arc<Mutex<Option<Vec<c_int>>>>) -> Self {
|
||||
RegistryKey {
|
||||
registry_id: id,
|
||||
is_nil: AtomicBool::new(id == ffi::LUA_REFNIL),
|
||||
unref_list,
|
||||
}
|
||||
}
|
||||
|
||||
// Destroys the `RegistryKey` without adding to the unref list
|
||||
pub(crate) fn take(self) -> c_int {
|
||||
let registry_id = self.registry_id;
|
||||
unsafe {
|
||||
|
@ -134,6 +160,21 @@ impl RegistryKey {
|
|||
}
|
||||
registry_id
|
||||
}
|
||||
|
||||
// Returns true if this `RegistryKey` holds a nil value
|
||||
#[inline(always)]
|
||||
pub(crate) fn is_nil(&self) -> bool {
|
||||
self.is_nil.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
// Marks value of this `RegistryKey` as `Nil`
|
||||
#[inline(always)]
|
||||
pub(crate) fn set_nil(&self, enabled: bool) {
|
||||
// We cannot replace previous value with nil in as this will break
|
||||
// Lua mechanism to find free keys.
|
||||
// Instead, we set a special flag to mark value as nil.
|
||||
self.is_nil.store(enabled, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct LuaRef<'lua> {
|
||||
|
|
|
@ -118,7 +118,17 @@ pub enum MetaMethod {
|
|||
///
|
||||
/// [`ipairs`]: https://www.lua.org/manual/5.2/manual.html#pdf-ipairs
|
||||
#[cfg(any(feature = "lua52", feature = "luajit52", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua52", feature = "luajit52"))))]
|
||||
IPairs,
|
||||
/// The `__iter` metamethod.
|
||||
///
|
||||
/// Executed before the iteration begins, and should return an iterator function like `next`
|
||||
/// (or a custom one).
|
||||
///
|
||||
/// Requires `feature = "lua"`
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
Iter,
|
||||
/// The `__close` metamethod.
|
||||
///
|
||||
/// Executed when a variable, that marked as to-be-closed, goes out of scope.
|
||||
|
@ -203,6 +213,8 @@ impl MetaMethod {
|
|||
MetaMethod::Pairs => "__pairs",
|
||||
#[cfg(any(feature = "lua52", feature = "luajit52"))]
|
||||
MetaMethod::IPairs => "__ipairs",
|
||||
#[cfg(feature = "luau")]
|
||||
MetaMethod::Iter => "__iter",
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
MetaMethod::Close => "__close",
|
||||
|
@ -270,6 +282,8 @@ impl From<StdString> for MetaMethod {
|
|||
"__pairs" => MetaMethod::Pairs,
|
||||
#[cfg(any(feature = "lua52", feature = "luajit52"))]
|
||||
"__ipairs" => MetaMethod::IPairs,
|
||||
#[cfg(feature = "luau")]
|
||||
"__iter" => MetaMethod::Iter,
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
"__close" => MetaMethod::Close,
|
||||
|
@ -419,7 +433,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`add_meta_method`]: #method.add_meta_method
|
||||
#[cfg(all(feature = "async", not(feature = "lua51")))]
|
||||
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
fn add_async_meta_method<S, A, R, M, MR>(&mut self, name: S, method: M)
|
||||
where
|
||||
|
@ -461,7 +475,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
|||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`add_meta_function`]: #method.add_meta_function
|
||||
#[cfg(all(feature = "async", not(feature = "lua51")))]
|
||||
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
fn add_async_meta_function<S, A, R, F, FR>(&mut self, name: S, function: F)
|
||||
where
|
||||
|
@ -839,7 +853,7 @@ impl<'lua> AnyUserData<'lua> {
|
|||
ffi::lua_pushnil(lua.state);
|
||||
ffi::lua_setiuservalue(lua.state, -2, i as c_int);
|
||||
}
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
#[cfg(any(feature = "lua53", feature = "lua52", feature = "luau"))]
|
||||
{
|
||||
ffi::lua_pushnil(lua.state);
|
||||
ffi::lua_setuservalue(lua.state, -2);
|
||||
|
@ -914,16 +928,16 @@ impl<'lua> AnyUserData<'lua> {
|
|||
|
||||
// Multiple (extra) user values are emulated by storing them in a table
|
||||
protect_lua!(lua.state, 2, 0, |state| {
|
||||
if getuservalue_table(lua.state, -2) != ffi::LUA_TTABLE {
|
||||
if getuservalue_table(state, -2) != ffi::LUA_TTABLE {
|
||||
// Create a new table to use as uservalue
|
||||
ffi::lua_pop(lua.state, 1);
|
||||
ffi::lua_pop(state, 1);
|
||||
ffi::lua_newtable(state);
|
||||
ffi::lua_pushvalue(state, -1);
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
ffi::lua_setiuservalue(lua.state, -4, USER_VALUE_MAXSLOT as c_int);
|
||||
ffi::lua_setiuservalue(state, -4, USER_VALUE_MAXSLOT as c_int);
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
ffi::lua_setuservalue(lua.state, -4);
|
||||
ffi::lua_setuservalue(state, -4);
|
||||
}
|
||||
ffi::lua_pushvalue(state, -2);
|
||||
#[cfg(feature = "lua54")]
|
||||
|
@ -967,8 +981,8 @@ impl<'lua> AnyUserData<'lua> {
|
|||
|
||||
// Multiple (extra) user values are emulated by storing them in a table
|
||||
protect_lua!(lua.state, 1, 1, |state| {
|
||||
if getuservalue_table(lua.state, -1) != ffi::LUA_TTABLE {
|
||||
ffi::lua_pushnil(lua.state);
|
||||
if getuservalue_table(state, -1) != ffi::LUA_TTABLE {
|
||||
ffi::lua_pushnil(state);
|
||||
return;
|
||||
}
|
||||
#[cfg(feature = "lua54")]
|
||||
|
@ -1002,16 +1016,16 @@ impl<'lua> AnyUserData<'lua> {
|
|||
// Multiple (extra) user values are emulated by storing them in a table
|
||||
let name = name.as_ref();
|
||||
protect_lua!(lua.state, 2, 0, |state| {
|
||||
if getuservalue_table(lua.state, -2) != ffi::LUA_TTABLE {
|
||||
if getuservalue_table(state, -2) != ffi::LUA_TTABLE {
|
||||
// Create a new table to use as uservalue
|
||||
ffi::lua_pop(lua.state, 1);
|
||||
ffi::lua_pop(state, 1);
|
||||
ffi::lua_newtable(state);
|
||||
ffi::lua_pushvalue(state, -1);
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
ffi::lua_setiuservalue(lua.state, -4, USER_VALUE_MAXSLOT as c_int);
|
||||
ffi::lua_setiuservalue(state, -4, USER_VALUE_MAXSLOT as c_int);
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
ffi::lua_setuservalue(lua.state, -4);
|
||||
ffi::lua_setuservalue(state, -4);
|
||||
}
|
||||
ffi::lua_pushlstring(state, name.as_ptr() as *const c_char, name.len());
|
||||
ffi::lua_pushvalue(state, -3);
|
||||
|
@ -1040,8 +1054,8 @@ impl<'lua> AnyUserData<'lua> {
|
|||
// Multiple (extra) user values are emulated by storing them in a table
|
||||
let name = name.as_ref();
|
||||
protect_lua!(lua.state, 1, 1, |state| {
|
||||
if getuservalue_table(lua.state, -1) != ffi::LUA_TTABLE {
|
||||
ffi::lua_pushnil(lua.state);
|
||||
if getuservalue_table(state, -1) != ffi::LUA_TTABLE {
|
||||
ffi::lua_pushnil(state);
|
||||
return;
|
||||
}
|
||||
ffi::lua_pushlstring(state, name.as_ptr() as *const c_char, name.len());
|
||||
|
|
629
src/userdata_impl.rs
Normal file
629
src/userdata_impl.rs
Normal file
|
@ -0,0 +1,629 @@
|
|||
use std::any::TypeId;
|
||||
use std::cell::{Ref, RefCell, RefMut};
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::lua::Lua;
|
||||
use crate::types::{Callback, MaybeSend};
|
||||
use crate::userdata::{
|
||||
AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
|
||||
};
|
||||
use crate::util::{check_stack, get_userdata, StackGuard};
|
||||
use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti, Value};
|
||||
|
||||
#[cfg(not(feature = "send"))]
|
||||
use std::rc::Rc;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
use {
|
||||
crate::types::AsyncCallback,
|
||||
futures_core::future::Future,
|
||||
futures_util::future::{self, TryFutureExt},
|
||||
};
|
||||
|
||||
pub(crate) struct StaticUserDataMethods<'lua, T: 'static + UserData> {
|
||||
pub(crate) methods: Vec<(Vec<u8>, Callback<'lua, 'static>)>,
|
||||
#[cfg(feature = "async")]
|
||||
pub(crate) async_methods: Vec<(Vec<u8>, AsyncCallback<'lua, 'static>)>,
|
||||
pub(crate) meta_methods: Vec<(MetaMethod, Callback<'lua, 'static>)>,
|
||||
#[cfg(feature = "async")]
|
||||
pub(crate) async_meta_methods: Vec<(MetaMethod, AsyncCallback<'lua, 'static>)>,
|
||||
_type: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'lua, T: 'static + UserData> Default for StaticUserDataMethods<'lua, T> {
|
||||
fn default() -> StaticUserDataMethods<'lua, T> {
|
||||
StaticUserDataMethods {
|
||||
methods: Vec::new(),
|
||||
#[cfg(feature = "async")]
|
||||
async_methods: Vec::new(),
|
||||
meta_methods: Vec::new(),
|
||||
#[cfg(feature = "async")]
|
||||
async_meta_methods: Vec::new(),
|
||||
_type: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMethods<'lua, T> {
|
||||
fn add_method<S, A, R, M>(&mut self, name: &S, method: M)
|
||||
where
|
||||
S: AsRef<[u8]> + ?Sized,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
|
||||
{
|
||||
self.methods
|
||||
.push((name.as_ref().to_vec(), Self::box_method(method)));
|
||||
}
|
||||
|
||||
fn add_method_mut<S, A, R, M>(&mut self, name: &S, method: M)
|
||||
where
|
||||
S: AsRef<[u8]> + ?Sized,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
||||
{
|
||||
self.methods
|
||||
.push((name.as_ref().to_vec(), Self::box_method_mut(method)));
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
fn add_async_method<S, A, R, M, MR>(&mut self, name: &S, method: M)
|
||||
where
|
||||
T: Clone,
|
||||
S: AsRef<[u8]> + ?Sized,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
|
||||
MR: 'lua + Future<Output = Result<R>>,
|
||||
{
|
||||
self.async_methods
|
||||
.push((name.as_ref().to_vec(), Self::box_async_method(method)));
|
||||
}
|
||||
|
||||
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((name.as_ref().to_vec(), Self::box_function(function)));
|
||||
}
|
||||
|
||||
fn add_function_mut<S, A, R, F>(&mut self, name: &S, function: F)
|
||||
where
|
||||
S: AsRef<[u8]> + ?Sized,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
self.methods
|
||||
.push((name.as_ref().to_vec(), Self::box_function_mut(function)));
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
fn add_async_function<S, A, R, F, FR>(&mut self, name: &S, function: F)
|
||||
where
|
||||
S: AsRef<[u8]> + ?Sized,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
|
||||
FR: 'lua + Future<Output = Result<R>>,
|
||||
{
|
||||
self.async_methods
|
||||
.push((name.as_ref().to_vec(), Self::box_async_function(function)));
|
||||
}
|
||||
|
||||
fn add_meta_method<S, A, R, M>(&mut self, meta: S, method: M)
|
||||
where
|
||||
S: Into<MetaMethod>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
|
||||
{
|
||||
self.meta_methods
|
||||
.push((meta.into(), Self::box_method(method)));
|
||||
}
|
||||
|
||||
fn add_meta_method_mut<S, A, R, M>(&mut self, meta: S, method: M)
|
||||
where
|
||||
S: Into<MetaMethod>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
||||
{
|
||||
self.meta_methods
|
||||
.push((meta.into(), Self::box_method_mut(method)));
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
|
||||
fn add_async_meta_method<S, A, R, M, MR>(&mut self, meta: S, method: M)
|
||||
where
|
||||
T: Clone,
|
||||
S: Into<MetaMethod>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
|
||||
MR: 'lua + Future<Output = Result<R>>,
|
||||
{
|
||||
self.async_meta_methods
|
||||
.push((meta.into(), Self::box_async_method(method)));
|
||||
}
|
||||
|
||||
fn add_meta_function<S, A, R, F>(&mut self, meta: S, function: F)
|
||||
where
|
||||
S: Into<MetaMethod>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
self.meta_methods
|
||||
.push((meta.into(), Self::box_function(function)));
|
||||
}
|
||||
|
||||
fn add_meta_function_mut<S, A, R, F>(&mut self, meta: S, function: F)
|
||||
where
|
||||
S: Into<MetaMethod>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
self.meta_methods
|
||||
.push((meta.into(), Self::box_function_mut(function)));
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
|
||||
fn add_async_meta_function<S, A, R, F, FR>(&mut self, meta: S, function: F)
|
||||
where
|
||||
S: Into<MetaMethod>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
|
||||
FR: 'lua + Future<Output = Result<R>>,
|
||||
{
|
||||
self.async_meta_methods
|
||||
.push((meta.into(), Self::box_async_function(function)));
|
||||
}
|
||||
|
||||
// Below are internal methods used in generated code
|
||||
|
||||
fn add_callback(&mut self, name: Vec<u8>, callback: Callback<'lua, 'static>) {
|
||||
self.methods.push((name, callback));
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
fn add_async_callback(&mut self, name: Vec<u8>, callback: AsyncCallback<'lua, 'static>) {
|
||||
self.async_methods.push((name, callback));
|
||||
}
|
||||
|
||||
fn add_meta_callback(&mut self, meta: MetaMethod, callback: Callback<'lua, 'static>) {
|
||||
self.meta_methods.push((meta, callback));
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
fn add_async_meta_callback(
|
||||
&mut self,
|
||||
meta: MetaMethod,
|
||||
callback: AsyncCallback<'lua, 'static>,
|
||||
) {
|
||||
self.async_meta_methods.push((meta, callback))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
|
||||
fn box_method<A, R, M>(method: M) -> Callback<'lua, 'static>
|
||||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>,
|
||||
{
|
||||
Box::new(move |lua, mut args| {
|
||||
if let Some(front) = args.pop_front() {
|
||||
let userdata = AnyUserData::from_lua(front, lua)?;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 2)?;
|
||||
|
||||
let type_id = lua.push_userdata_ref(&userdata.0)?;
|
||||
match type_id {
|
||||
Some(id) if id == TypeId::of::<T>() => {
|
||||
let ud = get_userdata_ref::<T>(lua.state)?;
|
||||
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
#[cfg(not(feature = "send"))]
|
||||
Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
|
||||
let ud = get_userdata_ref::<Rc<RefCell<T>>>(lua.state)?;
|
||||
let ud = ud.try_borrow().map_err(|_| Error::UserDataBorrowError)?;
|
||||
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
|
||||
let ud = get_userdata_ref::<Arc<Mutex<T>>>(lua.state)?;
|
||||
let ud = ud.try_lock().map_err(|_| Error::UserDataBorrowError)?;
|
||||
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
#[cfg(feature = "parking_lot")]
|
||||
Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
|
||||
let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(lua.state)?;
|
||||
let ud = ud.try_lock().ok_or(Error::UserDataBorrowError)?;
|
||||
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
|
||||
let ud = get_userdata_ref::<Arc<RwLock<T>>>(lua.state)?;
|
||||
let ud = ud.try_read().map_err(|_| Error::UserDataBorrowError)?;
|
||||
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
#[cfg(feature = "parking_lot")]
|
||||
Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
|
||||
let ud = get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(lua.state)?;
|
||||
let ud = ud.try_read().ok_or(Error::UserDataBorrowError)?;
|
||||
method(lua, &ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
_ => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(Error::FromLuaConversionError {
|
||||
from: "missing argument",
|
||||
to: "userdata",
|
||||
message: None,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn box_method_mut<A, R, M>(method: M) -> Callback<'lua, 'static>
|
||||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>,
|
||||
{
|
||||
let method = RefCell::new(method);
|
||||
Box::new(move |lua, mut args| {
|
||||
if let Some(front) = args.pop_front() {
|
||||
let userdata = AnyUserData::from_lua(front, lua)?;
|
||||
let mut method = method
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| Error::RecursiveMutCallback)?;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 2)?;
|
||||
|
||||
let type_id = lua.push_userdata_ref(&userdata.0)?;
|
||||
match type_id {
|
||||
Some(id) if id == TypeId::of::<T>() => {
|
||||
let mut ud = get_userdata_mut::<T>(lua.state)?;
|
||||
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
#[cfg(not(feature = "send"))]
|
||||
Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
|
||||
let ud = get_userdata_mut::<Rc<RefCell<T>>>(lua.state)?;
|
||||
let mut ud = ud
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| Error::UserDataBorrowMutError)?;
|
||||
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
|
||||
let ud = get_userdata_mut::<Arc<Mutex<T>>>(lua.state)?;
|
||||
let mut ud =
|
||||
ud.try_lock().map_err(|_| Error::UserDataBorrowMutError)?;
|
||||
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
#[cfg(feature = "parking_lot")]
|
||||
Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
|
||||
let ud = get_userdata_mut::<Arc<parking_lot::Mutex<T>>>(lua.state)?;
|
||||
let mut ud = ud.try_lock().ok_or(Error::UserDataBorrowMutError)?;
|
||||
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
|
||||
let ud = get_userdata_mut::<Arc<RwLock<T>>>(lua.state)?;
|
||||
let mut ud =
|
||||
ud.try_write().map_err(|_| Error::UserDataBorrowMutError)?;
|
||||
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
#[cfg(feature = "parking_lot")]
|
||||
Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
|
||||
let ud = get_userdata_mut::<Arc<parking_lot::RwLock<T>>>(lua.state)?;
|
||||
let mut ud = ud.try_write().ok_or(Error::UserDataBorrowMutError)?;
|
||||
method(lua, &mut ud, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
}
|
||||
_ => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(Error::FromLuaConversionError {
|
||||
from: "missing argument",
|
||||
to: "userdata",
|
||||
message: None,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
fn box_async_method<A, R, M, MR>(method: M) -> AsyncCallback<'lua, 'static>
|
||||
where
|
||||
T: Clone,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
|
||||
MR: 'lua + Future<Output = Result<R>>,
|
||||
{
|
||||
Box::new(move |lua, mut args| {
|
||||
let fut_res = || {
|
||||
if let Some(front) = args.pop_front() {
|
||||
let userdata = AnyUserData::from_lua(front, lua)?;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 2)?;
|
||||
|
||||
let type_id = lua.push_userdata_ref(&userdata.0)?;
|
||||
match type_id {
|
||||
Some(id) if id == TypeId::of::<T>() => {
|
||||
let ud = get_userdata_ref::<T>(lua.state)?;
|
||||
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
|
||||
}
|
||||
#[cfg(not(feature = "send"))]
|
||||
Some(id) if id == TypeId::of::<Rc<RefCell<T>>>() => {
|
||||
let ud = get_userdata_ref::<Rc<RefCell<T>>>(lua.state)?;
|
||||
let ud = ud.try_borrow().map_err(|_| Error::UserDataBorrowError)?;
|
||||
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
|
||||
}
|
||||
Some(id) if id == TypeId::of::<Arc<Mutex<T>>>() => {
|
||||
let ud = get_userdata_ref::<Arc<Mutex<T>>>(lua.state)?;
|
||||
let ud = ud.try_lock().map_err(|_| Error::UserDataBorrowError)?;
|
||||
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
|
||||
}
|
||||
#[cfg(feature = "parking_lot")]
|
||||
Some(id) if id == TypeId::of::<Arc<parking_lot::Mutex<T>>>() => {
|
||||
let ud = get_userdata_ref::<Arc<parking_lot::Mutex<T>>>(lua.state)?;
|
||||
let ud = ud.try_lock().ok_or(Error::UserDataBorrowError)?;
|
||||
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
|
||||
}
|
||||
Some(id) if id == TypeId::of::<Arc<RwLock<T>>>() => {
|
||||
let ud = get_userdata_ref::<Arc<RwLock<T>>>(lua.state)?;
|
||||
let ud = ud.try_read().map_err(|_| Error::UserDataBorrowError)?;
|
||||
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
|
||||
}
|
||||
#[cfg(feature = "parking_lot")]
|
||||
Some(id) if id == TypeId::of::<Arc<parking_lot::RwLock<T>>>() => {
|
||||
let ud =
|
||||
get_userdata_ref::<Arc<parking_lot::RwLock<T>>>(lua.state)?;
|
||||
let ud = ud.try_read().ok_or(Error::UserDataBorrowError)?;
|
||||
Ok(method(lua, ud.clone(), A::from_lua_multi(args, lua)?))
|
||||
}
|
||||
_ => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(Error::FromLuaConversionError {
|
||||
from: "missing argument",
|
||||
to: "userdata",
|
||||
message: None,
|
||||
})
|
||||
}
|
||||
};
|
||||
match fut_res() {
|
||||
Ok(fut) => Box::pin(fut.and_then(move |ret| future::ready(ret.to_lua_multi(lua)))),
|
||||
Err(e) => Box::pin(future::err(e)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn box_function<A, R, F>(function: F) -> Callback<'lua, 'static>
|
||||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
Box::new(move |lua, args| function(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua))
|
||||
}
|
||||
|
||||
fn box_function_mut<A, R, F>(function: F) -> Callback<'lua, 'static>
|
||||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
let function = RefCell::new(function);
|
||||
Box::new(move |lua, args| {
|
||||
let function = &mut *function
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| Error::RecursiveMutCallback)?;
|
||||
function(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
fn box_async_function<A, R, F, FR>(function: F) -> AsyncCallback<'lua, 'static>
|
||||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
|
||||
FR: 'lua + Future<Output = Result<R>>,
|
||||
{
|
||||
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(function(lua, args).and_then(move |ret| future::ready(ret.to_lua_multi(lua))))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct StaticUserDataFields<'lua, T: 'static + UserData> {
|
||||
pub(crate) field_getters: Vec<(Vec<u8>, Callback<'lua, 'static>)>,
|
||||
pub(crate) field_setters: Vec<(Vec<u8>, Callback<'lua, 'static>)>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(crate) meta_fields: Vec<(
|
||||
MetaMethod,
|
||||
Box<dyn Fn(&'lua Lua) -> Result<Value<'lua>> + 'static>,
|
||||
)>,
|
||||
_type: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'lua, T: 'static + UserData> Default for StaticUserDataFields<'lua, T> {
|
||||
fn default() -> StaticUserDataFields<'lua, T> {
|
||||
StaticUserDataFields {
|
||||
field_getters: Vec::new(),
|
||||
field_setters: Vec::new(),
|
||||
meta_fields: Vec::new(),
|
||||
_type: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: 'static + UserData> UserDataFields<'lua, T> for StaticUserDataFields<'lua, T> {
|
||||
fn add_field_method_get<S, R, M>(&mut self, name: &S, method: M)
|
||||
where
|
||||
S: AsRef<[u8]> + ?Sized,
|
||||
R: ToLua<'lua>,
|
||||
M: 'static + MaybeSend + Fn(&'lua Lua, &T) -> Result<R>,
|
||||
{
|
||||
self.field_getters.push((
|
||||
name.as_ref().to_vec(),
|
||||
StaticUserDataMethods::box_method(move |lua, data, ()| method(lua, data)),
|
||||
));
|
||||
}
|
||||
|
||||
fn add_field_method_set<S, A, M>(&mut self, name: &S, method: M)
|
||||
where
|
||||
S: AsRef<[u8]> + ?Sized,
|
||||
A: FromLua<'lua>,
|
||||
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<()>,
|
||||
{
|
||||
self.field_setters.push((
|
||||
name.as_ref().to_vec(),
|
||||
StaticUserDataMethods::box_method_mut(method),
|
||||
));
|
||||
}
|
||||
|
||||
fn add_field_function_get<S, R, F>(&mut self, name: &S, function: F)
|
||||
where
|
||||
S: AsRef<[u8]> + ?Sized,
|
||||
R: ToLua<'lua>,
|
||||
F: 'static + MaybeSend + Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R>,
|
||||
{
|
||||
self.field_getters.push((
|
||||
name.as_ref().to_vec(),
|
||||
StaticUserDataMethods::<T>::box_function(function),
|
||||
));
|
||||
}
|
||||
|
||||
fn add_field_function_set<S, A, F>(&mut self, name: &S, mut function: F)
|
||||
where
|
||||
S: AsRef<[u8]> + ?Sized,
|
||||
A: FromLua<'lua>,
|
||||
F: 'static + MaybeSend + FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()>,
|
||||
{
|
||||
self.field_setters.push((
|
||||
name.as_ref().to_vec(),
|
||||
StaticUserDataMethods::<T>::box_function_mut(move |lua, (data, val)| {
|
||||
function(lua, data, val)
|
||||
}),
|
||||
));
|
||||
}
|
||||
|
||||
fn add_meta_field_with<S, R, F>(&mut self, meta: S, f: F)
|
||||
where
|
||||
S: Into<MetaMethod>,
|
||||
R: ToLua<'lua>,
|
||||
F: 'static + MaybeSend + Fn(&'lua Lua) -> Result<R>,
|
||||
{
|
||||
let meta = meta.into();
|
||||
self.meta_fields.push((
|
||||
meta.clone(),
|
||||
Box::new(move |lua| {
|
||||
let value = f(lua)?.to_lua(lua)?;
|
||||
if meta == MetaMethod::Index || meta == MetaMethod::NewIndex {
|
||||
match value {
|
||||
Value::Nil | Value::Table(_) | Value::Function(_) => {}
|
||||
_ => {
|
||||
return Err(Error::MetaMethodTypeError {
|
||||
method: meta.to_string(),
|
||||
type_name: value.type_name(),
|
||||
message: Some("expected nil, table or function".to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(value)
|
||||
}),
|
||||
));
|
||||
}
|
||||
|
||||
// Below are internal methods
|
||||
|
||||
fn add_field_getter(&mut self, name: Vec<u8>, callback: Callback<'lua, 'static>) {
|
||||
self.field_getters.push((name, callback));
|
||||
}
|
||||
|
||||
fn add_field_setter(&mut self, name: Vec<u8>, callback: Callback<'lua, 'static>) {
|
||||
self.field_setters.push((name, callback));
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_userdata_ref<'a, T>(state: *mut ffi::lua_State) -> Result<Ref<'a, T>> {
|
||||
(*get_userdata::<UserDataCell<T>>(state, -1)).try_borrow()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_userdata_mut<'a, T>(state: *mut ffi::lua_State) -> Result<RefMut<'a, T>> {
|
||||
(*get_userdata::<UserDataCell<T>>(state, -1)).try_borrow_mut()
|
||||
}
|
||||
|
||||
macro_rules! lua_userdata_impl {
|
||||
($type:ty) => {
|
||||
impl<T: 'static + UserData> UserData for $type {
|
||||
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
let mut orig_fields = StaticUserDataFields::default();
|
||||
T::add_fields(&mut orig_fields);
|
||||
for (name, callback) in orig_fields.field_getters {
|
||||
fields.add_field_getter(name, callback);
|
||||
}
|
||||
for (name, callback) in orig_fields.field_setters {
|
||||
fields.add_field_setter(name, callback);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
let mut orig_methods = StaticUserDataMethods::default();
|
||||
T::add_methods(&mut orig_methods);
|
||||
for (name, callback) in orig_methods.methods {
|
||||
methods.add_callback(name, callback);
|
||||
}
|
||||
#[cfg(feature = "async")]
|
||||
for (name, callback) in orig_methods.async_methods {
|
||||
methods.add_async_callback(name, callback);
|
||||
}
|
||||
for (meta, callback) in orig_methods.meta_methods {
|
||||
methods.add_meta_callback(meta, callback);
|
||||
}
|
||||
#[cfg(feature = "async")]
|
||||
for (meta, callback) in orig_methods.async_meta_methods {
|
||||
methods.add_async_meta_callback(meta, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "send"))]
|
||||
lua_userdata_impl!(Rc<RefCell<T>>);
|
||||
lua_userdata_impl!(Arc<Mutex<T>>);
|
||||
lua_userdata_impl!(Arc<RwLock<T>>);
|
||||
#[cfg(feature = "parking_lot")]
|
||||
lua_userdata_impl!(Arc<parking_lot::Mutex<T>>);
|
||||
#[cfg(feature = "parking_lot")]
|
||||
lua_userdata_impl!(Arc<parking_lot::RwLock<T>>);
|
||||
|
||||
// A special proxy object for UserData
|
||||
pub(crate) struct UserDataProxy<T>(pub(crate) PhantomData<T>);
|
||||
|
||||
lua_userdata_impl!(UserDataProxy<T>);
|
451
src/util.rs
451
src/util.rs
|
@ -1,5 +1,7 @@
|
|||
use std::any::{Any, TypeId};
|
||||
use std::ffi::CStr;
|
||||
use std::fmt::Write;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
|
||||
use std::sync::Arc;
|
||||
|
@ -135,26 +137,21 @@ where
|
|||
F: Fn(*mut ffi::lua_State) -> R,
|
||||
R: Copy,
|
||||
{
|
||||
union URes<R: Copy> {
|
||||
uninit: (),
|
||||
init: R,
|
||||
}
|
||||
|
||||
struct Params<F, R: Copy> {
|
||||
function: F,
|
||||
result: URes<R>,
|
||||
result: MaybeUninit<R>,
|
||||
nresults: c_int,
|
||||
}
|
||||
|
||||
unsafe extern "C" fn do_call<F, R>(state: *mut ffi::lua_State) -> c_int
|
||||
where
|
||||
R: Copy,
|
||||
F: Fn(*mut ffi::lua_State) -> R,
|
||||
R: Copy,
|
||||
{
|
||||
let params = ffi::lua_touserdata(state, -1) as *mut Params<F, R>;
|
||||
ffi::lua_pop(state, 1);
|
||||
|
||||
(*params).result.init = ((*params).function)(state);
|
||||
(*params).result.write(((*params).function)(state));
|
||||
|
||||
if (*params).nresults == ffi::LUA_MULTRET {
|
||||
ffi::lua_gettop(state)
|
||||
|
@ -173,7 +170,7 @@ where
|
|||
|
||||
let mut params = Params {
|
||||
function: f,
|
||||
result: URes { uninit: () },
|
||||
result: MaybeUninit::uninit(),
|
||||
nresults,
|
||||
};
|
||||
|
||||
|
@ -184,7 +181,7 @@ where
|
|||
if ret == ffi::LUA_OK {
|
||||
// `LUA_OK` is only returned when the `do_call` function has completed successfully, so
|
||||
// `params.result` is definitely initialized.
|
||||
Ok(params.result.init)
|
||||
Ok(params.result.assume_init())
|
||||
} else {
|
||||
Err(pop_error(state, ret))
|
||||
}
|
||||
|
@ -202,7 +199,7 @@ pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error {
|
|||
"pop_error called with non-error return code"
|
||||
);
|
||||
|
||||
match get_gc_userdata::<WrappedFailure>(state, -1).as_mut() {
|
||||
match get_gc_userdata::<WrappedFailure>(state, -1, ptr::null()).as_mut() {
|
||||
Some(WrappedFailure::Error(err)) => {
|
||||
ffi::lua_pop(state, 1);
|
||||
err.clone()
|
||||
|
@ -245,22 +242,33 @@ pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error {
|
|||
}
|
||||
}
|
||||
|
||||
// Uses 3 stack spaces, does not call checkstack.
|
||||
#[inline]
|
||||
pub unsafe fn push_string<S: AsRef<[u8]> + ?Sized>(
|
||||
state: *mut ffi::lua_State,
|
||||
s: &S,
|
||||
) -> Result<()> {
|
||||
let s = s.as_ref();
|
||||
protect_lua!(state, 0, 1, |state| {
|
||||
// Uses 3 (or 1 if unprotected) stack spaces, does not call checkstack.
|
||||
#[inline(always)]
|
||||
pub unsafe fn push_string(state: *mut ffi::lua_State, s: &[u8], protect: bool) -> Result<()> {
|
||||
if protect {
|
||||
protect_lua!(state, 0, 1, |state| {
|
||||
ffi::lua_pushlstring(state, s.as_ptr() as *const c_char, s.len());
|
||||
})
|
||||
} else {
|
||||
ffi::lua_pushlstring(state, s.as_ptr() as *const c_char, s.len());
|
||||
})
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Uses 3 stack spaces, does not call checkstack.
|
||||
#[inline]
|
||||
pub unsafe fn push_table(state: *mut ffi::lua_State, narr: c_int, nrec: c_int) -> Result<()> {
|
||||
protect_lua!(state, 0, 1, |state| ffi::lua_createtable(state, narr, nrec))
|
||||
pub unsafe fn push_table(
|
||||
state: *mut ffi::lua_State,
|
||||
narr: c_int,
|
||||
nrec: c_int,
|
||||
protect: bool,
|
||||
) -> Result<()> {
|
||||
if protect {
|
||||
protect_lua!(state, 0, 1, |state| ffi::lua_createtable(state, narr, nrec))
|
||||
} else {
|
||||
ffi::lua_createtable(state, narr, nrec);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Uses 4 stack spaces, does not call checkstack.
|
||||
|
@ -278,22 +286,57 @@ where
|
|||
}
|
||||
|
||||
// Internally uses 3 stack spaces, does not call checkstack.
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[inline]
|
||||
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> {
|
||||
let ud = protect_lua!(state, 0, 1, |state| {
|
||||
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool) -> Result<()> {
|
||||
let ud = if protect {
|
||||
protect_lua!(state, 0, 1, |state| {
|
||||
ffi::lua_newuserdata(state, mem::size_of::<T>()) as *mut T
|
||||
})?
|
||||
} else {
|
||||
ffi::lua_newuserdata(state, mem::size_of::<T>()) as *mut T
|
||||
})?;
|
||||
};
|
||||
ptr::write(ud, t);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Internally uses 3 stack spaces, does not call checkstack.
|
||||
#[cfg(feature = "luau")]
|
||||
#[inline]
|
||||
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool) -> Result<()> {
|
||||
unsafe extern "C" fn destructor<T>(ud: *mut c_void) {
|
||||
ptr::drop_in_place(ud as *mut T);
|
||||
}
|
||||
|
||||
let size = mem::size_of::<T>();
|
||||
let ud = if protect {
|
||||
protect_lua!(state, 0, 1, |state| {
|
||||
ffi::lua_newuserdatadtor(state, size, destructor::<T>) as *mut T
|
||||
})?
|
||||
} else {
|
||||
ffi::lua_newuserdatadtor(state, size, destructor::<T>) as *mut T
|
||||
};
|
||||
ptr::write(ud, t);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Internally uses 3 stack spaces, does not call checkstack.
|
||||
#[cfg(feature = "lua54")]
|
||||
#[inline]
|
||||
pub unsafe fn push_userdata_uv<T>(state: *mut ffi::lua_State, t: T, nuvalue: c_int) -> Result<()> {
|
||||
let ud = protect_lua!(state, 0, 1, |state| {
|
||||
pub unsafe fn push_userdata_uv<T>(
|
||||
state: *mut ffi::lua_State,
|
||||
t: T,
|
||||
nuvalue: c_int,
|
||||
protect: bool,
|
||||
) -> Result<()> {
|
||||
let ud = if protect {
|
||||
protect_lua!(state, 0, 1, |state| {
|
||||
ffi::lua_newuserdatauv(state, mem::size_of::<T>(), nuvalue) as *mut T
|
||||
})?
|
||||
} else {
|
||||
ffi::lua_newuserdatauv(state, mem::size_of::<T>(), nuvalue) as *mut T
|
||||
})?;
|
||||
};
|
||||
ptr::write(ud, t);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -316,35 +359,169 @@ pub unsafe fn take_userdata<T>(state: *mut ffi::lua_State) -> T {
|
|||
// after the first call to __gc.
|
||||
get_destructed_userdata_metatable(state);
|
||||
ffi::lua_setmetatable(state, -2);
|
||||
let ud = get_userdata(state, -1);
|
||||
let ud = get_userdata::<T>(state, -1);
|
||||
|
||||
// Update userdata tag to disable destructor and mark as destructed
|
||||
#[cfg(feature = "luau")]
|
||||
ffi::lua_setuserdatatag(state, -1, 1);
|
||||
|
||||
ffi::lua_pop(state, 1);
|
||||
ptr::read(ud)
|
||||
}
|
||||
|
||||
// Pushes the userdata and attaches a metatable with __gc method.
|
||||
// Internally uses 3 stack spaces, does not call checkstack.
|
||||
pub unsafe fn push_gc_userdata<T: Any>(state: *mut ffi::lua_State, t: T) -> Result<()> {
|
||||
push_userdata(state, t)?;
|
||||
pub unsafe fn push_gc_userdata<T: Any>(
|
||||
state: *mut ffi::lua_State,
|
||||
t: T,
|
||||
protect: bool,
|
||||
) -> Result<()> {
|
||||
push_userdata(state, t, protect)?;
|
||||
get_gc_metatable::<T>(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 {
|
||||
pub unsafe fn get_gc_userdata<T: Any>(
|
||||
state: *mut ffi::lua_State,
|
||||
index: c_int,
|
||||
mt_ptr: *const c_void,
|
||||
) -> *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::<T>(state);
|
||||
let res = ffi::lua_rawequal(state, -1, -2);
|
||||
ffi::lua_pop(state, 2);
|
||||
if res == 0 {
|
||||
return ptr::null_mut();
|
||||
if !mt_ptr.is_null() {
|
||||
let ud_mt_ptr = ffi::lua_topointer(state, -1);
|
||||
ffi::lua_pop(state, 1);
|
||||
if !ptr::eq(ud_mt_ptr, mt_ptr) {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
} else {
|
||||
get_gc_metatable::<T>(state);
|
||||
let res = ffi::lua_rawequal(state, -1, -2);
|
||||
ffi::lua_pop(state, 2);
|
||||
if res == 0 {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
}
|
||||
ud
|
||||
}
|
||||
|
||||
unsafe extern "C" fn lua_error_impl(state: *mut ffi::lua_State) -> c_int {
|
||||
ffi::lua_error(state);
|
||||
}
|
||||
|
||||
unsafe extern "C" fn lua_isfunction_impl(state: *mut ffi::lua_State) -> c_int {
|
||||
let t = ffi::lua_type(state, -1);
|
||||
ffi::lua_pop(state, 1);
|
||||
ffi::lua_pushboolean(state, (t == ffi::LUA_TFUNCTION) as c_int);
|
||||
1
|
||||
}
|
||||
|
||||
unsafe fn init_userdata_metatable_index(state: *mut ffi::lua_State) -> Result<()> {
|
||||
let index_key = &USERDATA_METATABLE_INDEX as *const u8 as *const _;
|
||||
if ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, index_key) == ffi::LUA_TFUNCTION {
|
||||
return Ok(());
|
||||
}
|
||||
ffi::lua_pop(state, 1);
|
||||
|
||||
// Create and cache `__index` helper
|
||||
let code = cstr!(
|
||||
r#"
|
||||
local error, isfunction = ...
|
||||
return function (__index, field_getters, methods)
|
||||
return function (self, key)
|
||||
if field_getters ~= nil then
|
||||
local field_getter = field_getters[key]
|
||||
if field_getter ~= nil then
|
||||
return field_getter(self)
|
||||
end
|
||||
end
|
||||
|
||||
if methods ~= nil then
|
||||
local method = methods[key]
|
||||
if method ~= nil then
|
||||
return method
|
||||
end
|
||||
end
|
||||
|
||||
if isfunction(__index) then
|
||||
return __index(self, key)
|
||||
elseif __index == nil then
|
||||
error("attempt to get an unknown field '"..key.."'")
|
||||
else
|
||||
return __index[key]
|
||||
end
|
||||
end
|
||||
end
|
||||
"#
|
||||
);
|
||||
let code_len = CStr::from_ptr(code).to_bytes().len();
|
||||
protect_lua!(state, 0, 1, |state| {
|
||||
let ret = ffi::luaL_loadbuffer(state, code, code_len, cstr!("__mlua_index"));
|
||||
if ret != ffi::LUA_OK {
|
||||
ffi::lua_error(state);
|
||||
}
|
||||
ffi::lua_pushcfunction(state, lua_error_impl);
|
||||
ffi::lua_pushcfunction(state, lua_isfunction_impl);
|
||||
ffi::lua_call(state, 2, 1);
|
||||
|
||||
// Store in the registry
|
||||
ffi::lua_pushvalue(state, -1);
|
||||
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, index_key);
|
||||
})
|
||||
}
|
||||
|
||||
pub unsafe fn init_userdata_metatable_newindex(state: *mut ffi::lua_State) -> Result<()> {
|
||||
let newindex_key = &USERDATA_METATABLE_NEWINDEX as *const u8 as *const _;
|
||||
if ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, newindex_key) == ffi::LUA_TFUNCTION {
|
||||
return Ok(());
|
||||
}
|
||||
ffi::lua_pop(state, 1);
|
||||
|
||||
// Create and cache `__newindex` helper
|
||||
let code = cstr!(
|
||||
r#"
|
||||
local error, isfunction = ...
|
||||
return function (__newindex, field_setters)
|
||||
return function (self, key, value)
|
||||
if field_setters ~= nil then
|
||||
local field_setter = field_setters[key]
|
||||
if field_setter ~= nil then
|
||||
field_setter(self, value)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if isfunction(__newindex) then
|
||||
__newindex(self, key, value)
|
||||
elseif __newindex == nil then
|
||||
error("attempt to set an unknown field '"..key.."'")
|
||||
else
|
||||
__newindex[key] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
"#
|
||||
);
|
||||
let code_len = CStr::from_ptr(code).to_bytes().len();
|
||||
protect_lua!(state, 0, 1, |state| {
|
||||
let ret = ffi::luaL_loadbuffer(state, code, code_len, cstr!("__mlua_newindex"));
|
||||
if ret != ffi::LUA_OK {
|
||||
ffi::lua_error(state);
|
||||
}
|
||||
ffi::lua_pushcfunction(state, lua_error_impl);
|
||||
ffi::lua_pushcfunction(state, lua_isfunction_impl);
|
||||
ffi::lua_call(state, 2, 1);
|
||||
|
||||
// Store in the registry
|
||||
ffi::lua_pushvalue(state, -1);
|
||||
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, newindex_key);
|
||||
})
|
||||
}
|
||||
|
||||
// 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` member
|
||||
// to it for the given type and a `__metatable` entry to protect the table from script access.
|
||||
|
@ -360,99 +537,14 @@ pub unsafe fn init_userdata_metatable<T>(
|
|||
field_setters: Option<c_int>,
|
||||
methods: Option<c_int>,
|
||||
) -> Result<()> {
|
||||
// Wrapper to lookup in `field_getters` first, then `methods`, ending original `__index`.
|
||||
// Used only if `field_getters` or `methods` set.
|
||||
unsafe extern "C" fn meta_index_impl(state: *mut ffi::lua_State) -> c_int {
|
||||
// stack: self, key
|
||||
ffi::luaL_checkstack(state, 2, ptr::null());
|
||||
|
||||
// lookup in `field_getters` table
|
||||
if ffi::lua_isnil(state, ffi::lua_upvalueindex(2)) == 0 {
|
||||
ffi::lua_pushvalue(state, -1); // `key` arg
|
||||
if ffi::lua_rawget(state, ffi::lua_upvalueindex(2)) != ffi::LUA_TNIL {
|
||||
ffi::lua_insert(state, -3); // move function
|
||||
ffi::lua_pop(state, 1); // remove `key`
|
||||
ffi::lua_call(state, 1, 1);
|
||||
return 1;
|
||||
}
|
||||
ffi::lua_pop(state, 1); // pop the nil value
|
||||
}
|
||||
// lookup in `methods` table
|
||||
if ffi::lua_isnil(state, ffi::lua_upvalueindex(3)) == 0 {
|
||||
ffi::lua_pushvalue(state, -1); // `key` arg
|
||||
if ffi::lua_rawget(state, ffi::lua_upvalueindex(3)) != ffi::LUA_TNIL {
|
||||
ffi::lua_insert(state, -3);
|
||||
ffi::lua_pop(state, 2);
|
||||
return 1;
|
||||
}
|
||||
ffi::lua_pop(state, 1); // pop the nil value
|
||||
}
|
||||
|
||||
// lookup in `__index`
|
||||
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(1));
|
||||
match ffi::lua_type(state, -1) {
|
||||
ffi::LUA_TNIL => {
|
||||
ffi::lua_pop(state, 1); // pop the nil value
|
||||
let field = ffi::lua_tostring(state, -1);
|
||||
ffi::luaL_error(state, cstr!("attempt to get an unknown field '%s'"), field);
|
||||
}
|
||||
ffi::LUA_TTABLE => {
|
||||
ffi::lua_insert(state, -2);
|
||||
ffi::lua_gettable(state, -2);
|
||||
}
|
||||
ffi::LUA_TFUNCTION => {
|
||||
ffi::lua_insert(state, -3);
|
||||
ffi::lua_call(state, 2, 1);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
1
|
||||
}
|
||||
|
||||
// Similar to `meta_index_impl`, checks `field_setters` table first, then `__newindex` metamethod.
|
||||
// Used only if `field_setters` set.
|
||||
unsafe extern "C" fn meta_newindex_impl(state: *mut ffi::lua_State) -> c_int {
|
||||
// stack: self, key, value
|
||||
ffi::luaL_checkstack(state, 2, ptr::null());
|
||||
|
||||
// lookup in `field_setters` table
|
||||
ffi::lua_pushvalue(state, -2); // `key` arg
|
||||
if ffi::lua_rawget(state, ffi::lua_upvalueindex(2)) != ffi::LUA_TNIL {
|
||||
ffi::lua_remove(state, -3); // remove `key`
|
||||
ffi::lua_insert(state, -3); // move function
|
||||
ffi::lua_call(state, 2, 0);
|
||||
return 0;
|
||||
}
|
||||
ffi::lua_pop(state, 1); // pop the nil value
|
||||
|
||||
// lookup in `__newindex`
|
||||
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(1));
|
||||
match ffi::lua_type(state, -1) {
|
||||
ffi::LUA_TNIL => {
|
||||
ffi::lua_pop(state, 1); // pop the nil value
|
||||
let field = ffi::lua_tostring(state, -2);
|
||||
ffi::luaL_error(state, cstr!("attempt to set an unknown field '%s'"), field);
|
||||
}
|
||||
ffi::LUA_TTABLE => {
|
||||
ffi::lua_insert(state, -3);
|
||||
ffi::lua_settable(state, -3);
|
||||
}
|
||||
ffi::LUA_TFUNCTION => {
|
||||
ffi::lua_insert(state, -4);
|
||||
ffi::lua_call(state, 3, 0);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
ffi::lua_pushvalue(state, metatable);
|
||||
|
||||
if field_getters.is_some() || methods.is_some() {
|
||||
push_string(state, "__index")?;
|
||||
let index_type = ffi::lua_rawget(state, -2);
|
||||
// Push `__index` generator function
|
||||
init_userdata_metatable_index(state)?;
|
||||
|
||||
push_string(state, b"__index", true)?;
|
||||
let index_type = ffi::lua_rawget(state, -3);
|
||||
match index_type {
|
||||
ffi::LUA_TNIL | ffi::LUA_TTABLE | ffi::LUA_TFUNCTION => {
|
||||
for &idx in &[field_getters, methods] {
|
||||
|
@ -462,9 +554,9 @@ pub unsafe fn init_userdata_metatable<T>(
|
|||
ffi::lua_pushnil(state);
|
||||
}
|
||||
}
|
||||
protect_lua!(state, 3, 1, fn(state) {
|
||||
ffi::lua_pushcclosure(state, meta_index_impl, 3);
|
||||
})?;
|
||||
|
||||
// Generate `__index`
|
||||
protect_lua!(state, 4, 1, fn(state) ffi::lua_call(state, 3, 1))?;
|
||||
}
|
||||
_ => mlua_panic!("improper __index type {}", index_type),
|
||||
}
|
||||
|
@ -473,14 +565,16 @@ pub unsafe fn init_userdata_metatable<T>(
|
|||
}
|
||||
|
||||
if let Some(field_setters) = field_setters {
|
||||
push_string(state, "__newindex")?;
|
||||
let newindex_type = ffi::lua_rawget(state, -2);
|
||||
// Push `__newindex` generator function
|
||||
init_userdata_metatable_newindex(state)?;
|
||||
|
||||
push_string(state, b"__newindex", true)?;
|
||||
let newindex_type = ffi::lua_rawget(state, -3);
|
||||
match newindex_type {
|
||||
ffi::LUA_TNIL | ffi::LUA_TTABLE | ffi::LUA_TFUNCTION => {
|
||||
ffi::lua_pushvalue(state, field_setters);
|
||||
protect_lua!(state, 2, 1, fn(state) {
|
||||
ffi::lua_pushcclosure(state, meta_newindex_impl, 2);
|
||||
})?;
|
||||
// Generate `__newindex`
|
||||
protect_lua!(state, 3, 1, fn(state) ffi::lua_call(state, 2, 1))?;
|
||||
}
|
||||
_ => mlua_panic!("improper __newindex type {}", newindex_type),
|
||||
}
|
||||
|
@ -488,8 +582,11 @@ pub unsafe fn init_userdata_metatable<T>(
|
|||
rawset_field(state, -2, "__newindex")?;
|
||||
}
|
||||
|
||||
ffi::lua_pushcfunction(state, userdata_destructor::<T>);
|
||||
rawset_field(state, -2, "__gc")?;
|
||||
#[cfg(not(feature = "luau"))]
|
||||
{
|
||||
ffi::lua_pushcfunction(state, userdata_destructor::<T>);
|
||||
rawset_field(state, -2, "__gc")?;
|
||||
}
|
||||
|
||||
ffi::lua_pushboolean(state, 0);
|
||||
rawset_field(state, -2, "__metatable")?;
|
||||
|
@ -499,6 +596,7 @@ pub unsafe fn init_userdata_metatable<T>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub unsafe extern "C" fn userdata_destructor<T>(state: *mut ffi::lua_State) -> c_int {
|
||||
// It's probably NOT a good idea to catch Rust panics in finalizer
|
||||
// Lua 5.4 ignores it, other versions generates `LUA_ERRGCMM` without calling message handler
|
||||
|
@ -533,7 +631,7 @@ where
|
|||
|
||||
// We cannot shadow Rust errors with Lua ones, we pre-allocate enough memory
|
||||
// to store a wrapped error or panic *before* we proceed.
|
||||
let ud = ffi::lua_newuserdata(state, mem::size_of::<WrappedFailure>());
|
||||
let ud = WrappedFailure::new_userdata(state);
|
||||
ffi::lua_rotate(state, 1, 1);
|
||||
|
||||
match catch_unwind(AssertUnwindSafe(|| f(nargs))) {
|
||||
|
@ -582,7 +680,7 @@ pub unsafe extern "C" fn error_traceback(state: *mut ffi::lua_State) -> c_int {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if get_gc_userdata::<WrappedFailure>(state, -1).is_null() {
|
||||
if get_gc_userdata::<WrappedFailure>(state, -1, ptr::null()).is_null() {
|
||||
let s = ffi::luaL_tolstring(state, -1, ptr::null_mut());
|
||||
if ffi::lua_checkstack(state, ffi::LUA_TRACEBACK_STACK) != 0 {
|
||||
ffi::luaL_traceback(state, state, s, 0);
|
||||
|
@ -593,6 +691,20 @@ pub unsafe extern "C" fn error_traceback(state: *mut ffi::lua_State) -> c_int {
|
|||
1
|
||||
}
|
||||
|
||||
// A variant of `error_traceback` that can safely inspect another (yielded) thread stack
|
||||
pub unsafe fn error_traceback_thread(state: *mut ffi::lua_State, thread: *mut ffi::lua_State) {
|
||||
// Move error object to the main thread to safely call `__tostring` metamethod if present
|
||||
ffi::lua_xmove(thread, state, 1);
|
||||
|
||||
if get_gc_userdata::<WrappedFailure>(state, -1, ptr::null()).is_null() {
|
||||
let s = ffi::luaL_tolstring(state, -1, ptr::null_mut());
|
||||
if ffi::lua_checkstack(state, ffi::LUA_TRACEBACK_STACK) != 0 {
|
||||
ffi::luaL_traceback(state, thread, s, 0);
|
||||
ffi::lua_remove(state, -2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A variant of `pcall` that does not allow Lua to catch Rust panics from `callback_error`.
|
||||
pub unsafe extern "C" fn safe_pcall(state: *mut ffi::lua_State) -> c_int {
|
||||
ffi::luaL_checkstack(state, 2, ptr::null());
|
||||
|
@ -609,7 +721,7 @@ pub unsafe extern "C" fn safe_pcall(state: *mut ffi::lua_State) -> c_int {
|
|||
ffi::lua_gettop(state)
|
||||
} else {
|
||||
if let Some(WrappedFailure::Panic(_)) =
|
||||
get_gc_userdata::<WrappedFailure>(state, -1).as_ref()
|
||||
get_gc_userdata::<WrappedFailure>(state, -1, ptr::null()).as_ref()
|
||||
{
|
||||
ffi::lua_error(state);
|
||||
}
|
||||
|
@ -625,7 +737,7 @@ pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int {
|
|||
ffi::luaL_checkstack(state, 2, ptr::null());
|
||||
|
||||
if let Some(WrappedFailure::Panic(_)) =
|
||||
get_gc_userdata::<WrappedFailure>(state, -1).as_ref()
|
||||
get_gc_userdata::<WrappedFailure>(state, -1, ptr::null()).as_ref()
|
||||
{
|
||||
1
|
||||
} else {
|
||||
|
@ -655,7 +767,7 @@ pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int {
|
|||
ffi::lua_gettop(state) - 1
|
||||
} else {
|
||||
if let Some(WrappedFailure::Panic(_)) =
|
||||
get_gc_userdata::<WrappedFailure>(state, -1).as_ref()
|
||||
get_gc_userdata::<WrappedFailure>(state, -1, ptr::null()).as_ref()
|
||||
{
|
||||
ffi::lua_error(state);
|
||||
}
|
||||
|
@ -686,6 +798,8 @@ pub unsafe fn get_main_state(state: *mut ffi::lua_State) -> Option<*mut ffi::lua
|
|||
None
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "luau")]
|
||||
Some(ffi::lua_mainthread(state))
|
||||
}
|
||||
|
||||
// Initialize the internal (with __gc method) metatable for a type T.
|
||||
|
@ -696,10 +810,13 @@ pub unsafe fn init_gc_metatable<T: Any>(
|
|||
) -> Result<()> {
|
||||
check_stack(state, 6)?;
|
||||
|
||||
push_table(state, 0, 3)?;
|
||||
push_table(state, 0, 3, true)?;
|
||||
|
||||
ffi::lua_pushcfunction(state, userdata_destructor::<T>);
|
||||
rawset_field(state, -2, "__gc")?;
|
||||
#[cfg(not(feature = "luau"))]
|
||||
{
|
||||
ffi::lua_pushcfunction(state, userdata_destructor::<T>);
|
||||
rawset_field(state, -2, "__gc")?;
|
||||
}
|
||||
|
||||
ffi::lua_pushboolean(state, 0);
|
||||
rawset_field(state, -2, "__metatable")?;
|
||||
|
@ -734,7 +851,7 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
|||
callback_error(state, |_| {
|
||||
check_stack(state, 3)?;
|
||||
|
||||
let err_buf = match get_gc_userdata::<WrappedFailure>(state, -1).as_ref() {
|
||||
let err_buf = match get_gc_userdata::<WrappedFailure>(state, -1, ptr::null()).as_ref() {
|
||||
Some(WrappedFailure::Error(error)) => {
|
||||
let err_buf_key = &ERROR_PRINT_BUFFER_KEY as *const u8 as *const c_void;
|
||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, err_buf_key);
|
||||
|
@ -771,7 +888,7 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
|||
}
|
||||
}?;
|
||||
|
||||
push_string(state, &*err_buf)?;
|
||||
push_string(state, (*err_buf).as_bytes(), true)?;
|
||||
(*err_buf).clear();
|
||||
|
||||
Ok(1)
|
||||
|
@ -792,7 +909,7 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
|||
callback_error(state, |_| Err(Error::CallbackDestructed))
|
||||
}
|
||||
|
||||
push_table(state, 0, 26)?;
|
||||
push_table(state, 0, 26, true)?;
|
||||
ffi::lua_pushcfunction(state, destructed_error);
|
||||
for &method in &[
|
||||
"__add",
|
||||
|
@ -834,6 +951,8 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
|||
"__pairs",
|
||||
#[cfg(any(feature = "lua53", feature = "lua52", feature = "luajit52"))]
|
||||
"__ipairs",
|
||||
#[cfg(feature = "luau")]
|
||||
"__iter",
|
||||
#[cfg(feature = "lua54")]
|
||||
"__close",
|
||||
] {
|
||||
|
@ -849,7 +968,7 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
|||
|
||||
// Create error print buffer
|
||||
init_gc_metatable::<String>(state, None)?;
|
||||
push_gc_userdata(state, String::new())?;
|
||||
push_gc_userdata(state, String::new(), true)?;
|
||||
protect_lua!(state, 1, 0, fn(state) {
|
||||
let err_buf_key = &ERROR_PRINT_BUFFER_KEY as *const u8 as *const c_void;
|
||||
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, err_buf_key);
|
||||
|
@ -859,10 +978,28 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
|||
}
|
||||
|
||||
pub(crate) enum WrappedFailure {
|
||||
None,
|
||||
Error(Error),
|
||||
Panic(Option<Box<dyn Any + Send + 'static>>),
|
||||
}
|
||||
|
||||
impl WrappedFailure {
|
||||
pub(crate) unsafe fn new_userdata(state: *mut ffi::lua_State) -> *mut Self {
|
||||
let size = mem::size_of::<WrappedFailure>();
|
||||
#[cfg(feature = "luau")]
|
||||
let ud = {
|
||||
unsafe extern "C" fn destructor(p: *mut c_void) {
|
||||
ptr::drop_in_place(p as *mut WrappedFailure);
|
||||
}
|
||||
ffi::lua_newuserdatadtor(state, size, destructor) as *mut Self
|
||||
};
|
||||
#[cfg(not(feature = "luau"))]
|
||||
let ud = ffi::lua_newuserdata(state, size) as *mut Self;
|
||||
ptr::write(ud, WrappedFailure::None);
|
||||
ud
|
||||
}
|
||||
}
|
||||
|
||||
// Converts the given lua value to a string in a reasonable format without causing a Lua error or
|
||||
// panicking.
|
||||
pub(crate) unsafe fn to_string(state: *mut ffi::lua_State, index: c_int) -> String {
|
||||
|
@ -882,6 +1019,13 @@ pub(crate) unsafe fn to_string(state: *mut ffi::lua_State, index: c_int) -> Stri
|
|||
i.to_string()
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "luau")]
|
||||
ffi::LUA_TVECTOR => {
|
||||
let v = ffi::lua_tovector(state, index);
|
||||
mlua_debug_assert!(!v.is_null(), "vector is null");
|
||||
let (x, y, z) = (*v, *v.add(1), *v.add(2));
|
||||
format!("vector({},{},{})", x, y, z)
|
||||
}
|
||||
ffi::LUA_TSTRING => {
|
||||
let mut size = 0;
|
||||
// This will not trigger a 'm' error, because the reference is guaranteed to be of
|
||||
|
@ -902,5 +1046,14 @@ pub(crate) unsafe fn get_destructed_userdata_metatable(state: *mut ffi::lua_Stat
|
|||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, key);
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn ptr_to_cstr_bytes<'a>(input: *const c_char) -> Option<&'a [u8]> {
|
||||
if input.is_null() {
|
||||
return None;
|
||||
}
|
||||
Some(CStr::from_ptr(input).to_bytes())
|
||||
}
|
||||
|
||||
static DESTRUCTED_USERDATA_METATABLE: u8 = 0;
|
||||
static ERROR_PRINT_BUFFER_KEY: u8 = 0;
|
||||
static USERDATA_METATABLE_INDEX: u8 = 0;
|
||||
static USERDATA_METATABLE_NEWINDEX: u8 = 0;
|
||||
|
|
79
src/value.rs
79
src/value.rs
|
@ -1,13 +1,17 @@
|
|||
use std::iter::{self, FromIterator};
|
||||
use std::{slice, str, vec};
|
||||
use std::ops::Index;
|
||||
use std::os::raw::c_void;
|
||||
use std::{ptr, slice, str, vec};
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
use {
|
||||
serde::ser::{self, Serialize, Serializer},
|
||||
std::convert::TryInto,
|
||||
std::result::Result as StdResult,
|
||||
};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::function::Function;
|
||||
use crate::lua::Lua;
|
||||
use crate::string::String;
|
||||
|
@ -33,6 +37,10 @@ pub enum Value<'lua> {
|
|||
Integer(Integer),
|
||||
/// A floating point number.
|
||||
Number(Number),
|
||||
/// A Luau vector.
|
||||
#[cfg(any(feature = "luau", doc))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||
Vector(f32, f32, f32),
|
||||
/// An interned string, managed by Lua.
|
||||
///
|
||||
/// Unlike Rust strings, Lua strings may not be valid UTF-8.
|
||||
|
@ -60,6 +68,8 @@ impl<'lua> Value<'lua> {
|
|||
Value::LightUserData(_) => "lightuserdata",
|
||||
Value::Integer(_) => "integer",
|
||||
Value::Number(_) => "number",
|
||||
#[cfg(feature = "luau")]
|
||||
Value::Vector(_, _, _) => "vector",
|
||||
Value::String(_) => "string",
|
||||
Value::Table(_) => "table",
|
||||
Value::Function(_) => "function",
|
||||
|
@ -86,6 +96,30 @@ impl<'lua> Value<'lua> {
|
|||
_ => Ok(self == other.as_ref()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the value to a generic C pointer.
|
||||
///
|
||||
/// The value can be a userdata, a table, a thread, a string, or a function; otherwise it returns NULL.
|
||||
/// Different objects will give different pointers.
|
||||
/// There is no way to convert the pointer back to its original value.
|
||||
///
|
||||
/// Typically this function is used only for hashing and debug information.
|
||||
#[inline]
|
||||
pub fn to_pointer(&self) -> *const c_void {
|
||||
unsafe {
|
||||
match self {
|
||||
Value::LightUserData(ud) => ud.0,
|
||||
Value::Table(t) => t.to_pointer(),
|
||||
Value::String(s) => s.to_pointer(),
|
||||
Value::Function(Function(r))
|
||||
| Value::Thread(Thread(r))
|
||||
| Value::UserData(AnyUserData(r)) => {
|
||||
ffi::lua_topointer(r.lua.ref_thread(), r.index)
|
||||
}
|
||||
_ => ptr::null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> PartialEq for Value<'lua> {
|
||||
|
@ -98,6 +132,8 @@ impl<'lua> PartialEq for Value<'lua> {
|
|||
(Value::Integer(a), Value::Number(b)) => *a as Number == *b,
|
||||
(Value::Number(a), Value::Integer(b)) => *a == *b as Number,
|
||||
(Value::Number(a), Value::Number(b)) => *a == *b,
|
||||
#[cfg(feature = "luau")]
|
||||
(Value::Vector(x1, y1, z1), Value::Vector(x2, y2, z2)) => (x1, y1, z1) == (x2, y2, z2),
|
||||
(Value::String(a), Value::String(b)) => a == b,
|
||||
(Value::Table(a), Value::Table(b)) => a == b,
|
||||
(Value::Function(a), Value::Function(b)) => a == b,
|
||||
|
@ -125,9 +161,12 @@ impl<'lua> Serialize for Value<'lua> {
|
|||
Value::Nil => serializer.serialize_unit(),
|
||||
Value::Boolean(b) => serializer.serialize_bool(*b),
|
||||
#[allow(clippy::useless_conversion)]
|
||||
Value::Integer(i) => serializer.serialize_i64((*i).into()),
|
||||
Value::Integer(i) => serializer
|
||||
.serialize_i64((*i).try_into().expect("cannot convert lua_Integer to i64")),
|
||||
#[allow(clippy::useless_conversion)]
|
||||
Value::Number(n) => serializer.serialize_f64((*n).into()),
|
||||
Value::Number(n) => serializer.serialize_f64(*n),
|
||||
#[cfg(feature = "luau")]
|
||||
Value::Vector(x, y, z) => (x, y, z).serialize(serializer),
|
||||
Value::String(s) => s.serialize(serializer),
|
||||
Value::Table(t) => t.serialize(serializer),
|
||||
Value::UserData(ud) => ud.serialize(serializer),
|
||||
|
@ -159,7 +198,7 @@ pub struct MultiValue<'lua>(Vec<Value<'lua>>);
|
|||
impl<'lua> MultiValue<'lua> {
|
||||
/// Creates an empty `MultiValue` containing no values.
|
||||
#[inline]
|
||||
pub fn new() -> MultiValue<'lua> {
|
||||
pub const fn new() -> MultiValue<'lua> {
|
||||
MultiValue(Vec::new())
|
||||
}
|
||||
|
||||
|
@ -200,7 +239,24 @@ impl<'a, 'lua> IntoIterator for &'a MultiValue<'lua> {
|
|||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
(&self.0).iter().rev()
|
||||
self.0.iter().rev()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> Index<usize> for MultiValue<'lua> {
|
||||
type Output = Value<'lua>;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
if let Some(result) = self.get(index) {
|
||||
result
|
||||
} else {
|
||||
panic!(
|
||||
"index out of bounds: the len is {} but the index is {}",
|
||||
self.len(),
|
||||
index
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,19 +274,24 @@ impl<'lua> MultiValue<'lua> {
|
|||
v
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(&self, index: usize) -> Option<&Value<'lua>> {
|
||||
self.0.get(self.0.len() - index - 1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn reserve(&mut self, size: usize) {
|
||||
self.0.reserve(size);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn push_front(&mut self, value: Value<'lua>) {
|
||||
self.0.push(value);
|
||||
pub fn pop_front(&mut self) -> Option<Value<'lua>> {
|
||||
self.0.pop()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn pop_front(&mut self) -> Option<Value<'lua>> {
|
||||
self.0.pop()
|
||||
pub fn push_front(&mut self, value: Value<'lua>) {
|
||||
self.0.push(value);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
125
tests/async.rs
125
tests/async.rs
|
@ -12,8 +12,8 @@ use futures_timer::Delay;
|
|||
use futures_util::stream::TryStreamExt;
|
||||
|
||||
use mlua::{
|
||||
Error, Function, Lua, LuaOptions, MetaMethod, Result, StdLib, Table, TableExt, Thread,
|
||||
UserData, UserDataMethods, Value,
|
||||
Error, Function, Lua, LuaOptions, Result, StdLib, Table, TableExt, Thread, UserData,
|
||||
UserDataMethods, Value,
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -75,7 +75,10 @@ async fn test_async_call() -> Result<()> {
|
|||
async fn test_async_bind_call() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let sum = lua.create_async_function(|_lua, (a, b): (i64, i64)| async move { Ok(a + b) })?;
|
||||
let sum = lua.create_async_function(|_lua, (a, b): (i64, i64)| async move {
|
||||
tokio::task::yield_now().await;
|
||||
Ok(a + b)
|
||||
})?;
|
||||
|
||||
let plus_10 = sum.bind(10)?;
|
||||
lua.globals().set("plus_10", plus_10)?;
|
||||
|
@ -171,6 +174,38 @@ async fn test_async_return_async_closure() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
#[tokio::test]
|
||||
async fn test_async_lua54_to_be_closed() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let globals = lua.globals();
|
||||
globals.set("close_count", 0)?;
|
||||
|
||||
let code = r#"
|
||||
local t <close> = setmetatable({}, {
|
||||
__close = function()
|
||||
close_count = close_count + 1
|
||||
end
|
||||
})
|
||||
error "test"
|
||||
"#;
|
||||
let f = lua.load(code).into_function()?;
|
||||
|
||||
// Test close using call_async
|
||||
let _ = f.call_async::<_, ()>(()).await;
|
||||
assert_eq!(globals.get::<_, usize>("close_count")?, 1);
|
||||
|
||||
// Don't close by default when awaiting async threads
|
||||
let co = lua.create_thread(f.clone())?;
|
||||
let _ = co.clone().into_async::<_, ()>(()).await;
|
||||
assert_eq!(globals.get::<_, usize>("close_count")?, 1);
|
||||
let _ = co.reset(f);
|
||||
assert_eq!(globals.get::<_, usize>("close_count")?, 2);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_async_thread_stream() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
@ -275,6 +310,28 @@ async fn test_async_table() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_async_thread_cache() -> Result<()> {
|
||||
let options = LuaOptions::new().thread_cache_size(4);
|
||||
let lua = Lua::new_with(StdLib::ALL_SAFE, options)?;
|
||||
|
||||
let error_f = lua.create_async_function(|_, ()| async move {
|
||||
Delay::new(Duration::from_millis(10)).await;
|
||||
Err::<(), _>(Error::RuntimeError("test".to_string()))
|
||||
})?;
|
||||
|
||||
let sleep = lua.create_async_function(|_, n| async move {
|
||||
Delay::new(Duration::from_millis(n)).await;
|
||||
Ok(format!("elapsed:{}ms", n))
|
||||
})?;
|
||||
|
||||
assert!(error_f.call_async::<_, ()>(()).await.is_err());
|
||||
// Next call should use cached thread
|
||||
assert_eq!(sleep.call_async::<_, String>(3).await?, "elapsed:3ms");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_async_userdata() -> Result<()> {
|
||||
#[derive(Clone)]
|
||||
|
@ -298,12 +355,38 @@ async fn test_async_userdata() -> Result<()> {
|
|||
Ok(format!("elapsed:{}ms", n))
|
||||
});
|
||||
|
||||
#[cfg(not(feature = "lua51"))]
|
||||
methods.add_async_meta_method(MetaMethod::Call, |_, data, ()| async move {
|
||||
#[cfg(not(any(feature = "lua51", feature = "luau")))]
|
||||
methods.add_async_meta_method(mlua::MetaMethod::Call, |_, data, ()| async move {
|
||||
let n = data.0.load(Ordering::Relaxed);
|
||||
Delay::new(Duration::from_millis(n)).await;
|
||||
Ok(format!("elapsed:{}ms", n))
|
||||
});
|
||||
|
||||
#[cfg(not(any(feature = "lua51", feature = "luau")))]
|
||||
methods.add_async_meta_method(
|
||||
mlua::MetaMethod::Index,
|
||||
|_, data, key: String| async move {
|
||||
Delay::new(Duration::from_millis(10)).await;
|
||||
match key.as_str() {
|
||||
"ms" => Ok(Some(data.0.load(Ordering::Relaxed) as f64)),
|
||||
"s" => Ok(Some((data.0.load(Ordering::Relaxed) as f64) / 1000.0)),
|
||||
_ => Ok(None),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
#[cfg(not(any(feature = "lua51", feature = "luau")))]
|
||||
methods.add_async_meta_method(
|
||||
mlua::MetaMethod::NewIndex,
|
||||
|_, data, (key, value): (String, f64)| async move {
|
||||
Delay::new(Duration::from_millis(10)).await;
|
||||
match key.as_str() {
|
||||
"ms" => Ok(data.0.store(value as u64, Ordering::Relaxed)),
|
||||
"s" => Ok(data.0.store((value * 1000.0) as u64, Ordering::Relaxed)),
|
||||
_ => Err(Error::external(format!("key '{}' not found", key))),
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,11 +407,17 @@ async fn test_async_userdata() -> Result<()> {
|
|||
.exec_async()
|
||||
.await?;
|
||||
|
||||
#[cfg(not(feature = "lua51"))]
|
||||
#[cfg(not(any(feature = "lua51", feature = "luau")))]
|
||||
lua.load(
|
||||
r#"
|
||||
userdata:set_value(15)
|
||||
assert(userdata() == "elapsed:15ms")
|
||||
|
||||
userdata.ms = 2000
|
||||
assert(userdata.s == 2)
|
||||
|
||||
userdata.s = 15
|
||||
assert(userdata.ms == 15000)
|
||||
"#,
|
||||
)
|
||||
.exec_async()
|
||||
|
@ -337,6 +426,30 @@ async fn test_async_userdata() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_async_thread_error() -> Result<()> {
|
||||
struct MyUserData;
|
||||
|
||||
impl UserData for MyUserData {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_meta_method("__tostring", |_, _this, ()| Ok("myuserdata error"))
|
||||
}
|
||||
}
|
||||
|
||||
let lua = Lua::new();
|
||||
let result = lua
|
||||
.load("function x(...) error(...) end x(...)")
|
||||
.set_name("chunk")?
|
||||
.call_async::<_, ()>(MyUserData)
|
||||
.await;
|
||||
assert!(
|
||||
matches!(result, Err(Error::RuntimeError(cause)) if cause.contains("myuserdata error")),
|
||||
"improper error traceback from dead thread"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_async_scope() -> Result<()> {
|
||||
let ref lua = Lua::new();
|
||||
|
|
54
tests/chunk.rs
Normal file
54
tests/chunk.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use std::fs;
|
||||
use std::io;
|
||||
|
||||
use mlua::{Error, Lua, Result};
|
||||
|
||||
#[test]
|
||||
fn test_chunk_path() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
fs::write(
|
||||
temp_dir.path().join("module.lua"),
|
||||
r#"
|
||||
return 321
|
||||
"#,
|
||||
)?;
|
||||
let i: i32 = lua.load(&temp_dir.path().join("module.lua")).eval()?;
|
||||
assert_eq!(i, 321);
|
||||
|
||||
match lua.load(&temp_dir.path().join("module2.lua")).exec() {
|
||||
Err(Error::ExternalError(err))
|
||||
if err.downcast_ref::<io::Error>().unwrap().kind() == io::ErrorKind::NotFound => {}
|
||||
res => panic!("expected io::Error, got {:?}", res),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "macros")]
|
||||
fn test_chunk_macro() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let name = "Rustacean";
|
||||
let table = vec![1];
|
||||
|
||||
let data = lua.create_table()?;
|
||||
data.raw_set("num", 1)?;
|
||||
|
||||
lua.globals().set("g", 123)?;
|
||||
|
||||
lua.load(mlua::chunk! {
|
||||
assert($name == "Rustacean")
|
||||
assert($table[1] == 1)
|
||||
assert($data.num == 1)
|
||||
assert(g == 123)
|
||||
s = 321
|
||||
})
|
||||
.exec()?;
|
||||
|
||||
assert_eq!(lua.globals().get::<_, i32>("s")?, 321);
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
use mlua::{Lua, UserData, UserDataMethods};
|
||||
use mlua::{UserData, UserDataMethods};
|
||||
|
||||
fn main() {
|
||||
let ref lua = Lua::new();
|
||||
|
||||
#[derive(Clone)]
|
||||
struct MyUserData<'a>(&'a i64);
|
||||
|
||||
|
|
|
@ -1,36 +1,14 @@
|
|||
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
|
||||
--> $DIR/async_nonstatic_userdata.rs:11:72
|
||||
error: lifetime may not live long enough
|
||||
--> tests/compile/async_nonstatic_userdata.rs:9:13
|
||||
|
|
||||
11 | methods.add_async_method("print", |_, data, ()| async move {
|
||||
| ________________________________________________________________________^
|
||||
12 | | println!("{}", data.0);
|
||||
13 | | Ok(())
|
||||
14 | | });
|
||||
| |_____________^
|
||||
7 | impl<'a> UserData for MyUserData<'a> {
|
||||
| -- lifetime `'a` defined here
|
||||
8 | fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
| ---- lifetime `'lua` defined here
|
||||
9 | / methods.add_async_method("print", |_, data, ()| async move {
|
||||
10 | | println!("{}", data.0);
|
||||
11 | | Ok(())
|
||||
12 | | });
|
||||
| |______________^ argument requires that `'a` must outlive `'lua`
|
||||
|
|
||||
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 {
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
= help: consider adding the following bound: `'a: 'lua`
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
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.0`, which is owned by the current function
|
||||
--> tests/compile/function_borrow.rs:9:33
|
||||
|
|
||||
9 | let _ = lua.create_function(|_, ()| -> Result<i32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ may outlive borrowed value `test`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ may outlive borrowed value `test.0`
|
||||
10 | Ok(test.0)
|
||||
| ------ `test` is borrowed here
|
||||
| ------ `test.0` is borrowed here
|
||||
|
|
||||
note: function requires argument type to outlive `'static`
|
||||
--> tests/compile/function_borrow.rs:9:13
|
||||
|
@ -14,7 +14,7 @@ note: function requires argument type to outlive `'static`
|
|||
10 | | Ok(test.0)
|
||||
11 | | });
|
||||
| |______^
|
||||
help: to force the closure to take ownership of `test` (and any other referenced variables), use the `move` keyword
|
||||
help: to force the closure to take ownership of `test.0` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
9 | let _ = lua.create_function(move |_, ()| -> Result<i32> {
|
||||
| ++++
|
||||
|
|
|
@ -1,33 +1,20 @@
|
|||
error[E0277]: the type `UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
error[E0277]: the type `UnsafeCell<mlua::lua::LuaInner>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/lua_norefunwindsafe.rs:7:5
|
||||
|
|
||||
7 | catch_unwind(|| lua.create_table().unwrap());
|
||||
| ^^^^^^^^^^^^ `UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| ^^^^^^^^^^^^ `UnsafeCell<mlua::lua::LuaInner>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
|
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<()>`
|
||||
= note: required because it appears within the type `PhantomData<UnsafeCell<()>>`
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::lua::LuaInner>`
|
||||
= note: required because it appears within the type `alloc::sync::ArcInner<UnsafeCell<mlua::lua::LuaInner>>`
|
||||
= note: required because it appears within the type `PhantomData<alloc::sync::ArcInner<UnsafeCell<mlua::lua::LuaInner>>>`
|
||||
= note: required because it appears within the type `Arc<UnsafeCell<mlua::lua::LuaInner>>`
|
||||
= note: required because it appears within the type `Lua`
|
||||
= note: required because of the requirements on the impl of `UnwindSafe` for `&Lua`
|
||||
= note: required because it appears within the type `[closure@$DIR/tests/compile/lua_norefunwindsafe.rs:7:18: 7:48]`
|
||||
note: required by a bound in `catch_unwind`
|
||||
--> $RUST/std/src/panic.rs
|
||||
|
|
||||
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
| ^^^^^^^^^^ required by this bound in `catch_unwind`
|
||||
|
||||
error[E0277]: the type `UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/lua_norefunwindsafe.rs:7:5
|
||||
|
|
||||
7 | catch_unwind(|| lua.create_table().unwrap());
|
||||
| ^^^^^^^^^^^^ `UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
|
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::lua::ExtraData>`
|
||||
= note: required because it appears within the type `alloc::sync::ArcInner<UnsafeCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `PhantomData<alloc::sync::ArcInner<UnsafeCell<mlua::lua::ExtraData>>>`
|
||||
= note: required because it appears within the type `Arc<UnsafeCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `Lua`
|
||||
= note: required because of the requirements on the impl of `UnwindSafe` for `&Lua`
|
||||
= note: required because it appears within the type `[closure@$DIR/tests/compile/lua_norefunwindsafe.rs:7:18: 7:48]`
|
||||
note: required because it's used within this closure
|
||||
--> tests/compile/lua_norefunwindsafe.rs:7:18
|
||||
|
|
||||
7 | catch_unwind(|| lua.create_table().unwrap());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `catch_unwind`
|
||||
--> $RUST/std/src/panic.rs
|
||||
|
|
||||
|
|
|
@ -1,14 +1,26 @@
|
|||
error[E0277]: `Rc<Cell<i32>>` cannot be sent between threads safely
|
||||
--> $DIR/non_send.rs:11:9
|
||||
|
|
||||
11 | lua.create_function(move |_, ()| {
|
||||
| _________^^^^^^^^^^^^^^^_-
|
||||
| | |
|
||||
| | `Rc<Cell<i32>>` cannot be sent between threads safely
|
||||
12 | | Ok(data.get())
|
||||
13 | | })?
|
||||
| |_____- within this `[closure@$DIR/tests/compile/non_send.rs:11:25: 13:6]`
|
||||
|
|
||||
= help: within `[closure@$DIR/tests/compile/non_send.rs:11:25: 13:6]`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
|
||||
= note: required because it appears within the type `[closure@$DIR/tests/compile/non_send.rs:11:25: 13:6]`
|
||||
= note: required because of the requirements on the impl of `mlua::types::MaybeSend` for `[closure@$DIR/tests/compile/non_send.rs:11:25: 13:6]`
|
||||
--> tests/compile/non_send.rs:11:9
|
||||
|
|
||||
11 | lua.create_function(move |_, ()| {
|
||||
| _________^^^^^^^^^^^^^^^_-
|
||||
| | |
|
||||
| | `Rc<Cell<i32>>` cannot be sent between threads safely
|
||||
12 | | Ok(data.get())
|
||||
13 | | })?
|
||||
| |_____- within this `[closure@$DIR/tests/compile/non_send.rs:11:25: 13:6]`
|
||||
|
|
||||
= help: within `[closure@$DIR/tests/compile/non_send.rs:11:25: 13:6]`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
|
||||
note: required because it's used within this closure
|
||||
--> tests/compile/non_send.rs:11:25
|
||||
|
|
||||
11 | lua.create_function(move |_, ()| {
|
||||
| _________________________^
|
||||
12 | | Ok(data.get())
|
||||
13 | | })?
|
||||
| |_____^
|
||||
= note: required because of the requirements on the impl of `mlua::types::MaybeSend` for `[closure@$DIR/tests/compile/non_send.rs:11:25: 13:6]`
|
||||
note: required by a bound in `Lua::create_function`
|
||||
--> src/lua.rs
|
||||
|
|
||||
| F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>,
|
||||
| ^^^^^^^^^ required by this bound in `Lua::create_function`
|
||||
|
|
|
@ -1,37 +1,22 @@
|
|||
error[E0277]: the type `UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
error[E0277]: the type `UnsafeCell<mlua::lua::LuaInner>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:5
|
||||
|
|
||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
||||
| ^^^^^^^^^^^^ `UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
| ^^^^^^^^^^^^ `UnsafeCell<mlua::lua::LuaInner>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
|
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<()>`
|
||||
= note: required because it appears within the type `PhantomData<UnsafeCell<()>>`
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::lua::LuaInner>`
|
||||
= note: required because it appears within the type `alloc::sync::ArcInner<UnsafeCell<mlua::lua::LuaInner>>`
|
||||
= note: required because it appears within the type `PhantomData<alloc::sync::ArcInner<UnsafeCell<mlua::lua::LuaInner>>>`
|
||||
= note: required because it appears within the type `Arc<UnsafeCell<mlua::lua::LuaInner>>`
|
||||
= note: required because it appears within the type `Lua`
|
||||
= note: required because of the requirements on the impl of `UnwindSafe` for `&Lua`
|
||||
= note: required because it appears within the type `mlua::types::LuaRef<'_>`
|
||||
= note: required because it appears within the type `LuaTable<'_>`
|
||||
= note: required because it appears within the type `[closure@$DIR/tests/compile/ref_nounwindsafe.rs:8:18: 8:54]`
|
||||
note: required by a bound in `catch_unwind`
|
||||
--> $RUST/std/src/panic.rs
|
||||
|
|
||||
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
| ^^^^^^^^^^ required by this bound in `catch_unwind`
|
||||
|
||||
error[E0277]: the type `UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:5
|
||||
|
|
||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
||||
| ^^^^^^^^^^^^ `UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
|
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::lua::ExtraData>`
|
||||
= note: required because it appears within the type `alloc::sync::ArcInner<UnsafeCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `PhantomData<alloc::sync::ArcInner<UnsafeCell<mlua::lua::ExtraData>>>`
|
||||
= note: required because it appears within the type `Arc<UnsafeCell<mlua::lua::ExtraData>>`
|
||||
= note: required because it appears within the type `Lua`
|
||||
= note: required because of the requirements on the impl of `UnwindSafe` for `&Lua`
|
||||
= note: required because it appears within the type `mlua::types::LuaRef<'_>`
|
||||
= note: required because it appears within the type `LuaTable<'_>`
|
||||
= note: required because it appears within the type `[closure@$DIR/tests/compile/ref_nounwindsafe.rs:8:18: 8:54]`
|
||||
note: required because it's used within this closure
|
||||
--> tests/compile/ref_nounwindsafe.rs:8:18
|
||||
|
|
||||
8 | catch_unwind(move || table.set("a", "b").unwrap());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `catch_unwind`
|
||||
--> $RUST/std/src/panic.rs
|
||||
|
|
||||
|
|
|
@ -19,7 +19,7 @@ error[E0373]: closure may outlive the current function, but it borrows `inner`,
|
|||
--> tests/compile/scope_callback_inner.rs:8:34
|
||||
|
|
||||
5 | lua.scope(|scope| {
|
||||
| ----- has type `&Scope<'_, '2>`
|
||||
| ----- has type `&mlua::Scope<'_, '2>`
|
||||
...
|
||||
8 | .create_function_mut(|_, t: Table| {
|
||||
| ^^^^^^^^^^^^^ may outlive borrowed value `inner`
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
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.field`, which is owned by the current function
|
||||
--> tests/compile/scope_invariance.rs:14:38
|
||||
|
|
||||
9 | lua.scope(|scope| {
|
||||
| ----- has type `&Scope<'_, '1>`
|
||||
| ----- has type `&mlua::Scope<'_, '1>`
|
||||
...
|
||||
14 | .create_function_mut(|_, ()| {
|
||||
| ^^^^^^^ may outlive borrowed value `test`
|
||||
| ^^^^^^^ may outlive borrowed value `test.field`
|
||||
15 | test.field = 42;
|
||||
| ---------- `test` is borrowed here
|
||||
| ---------- `test.field` is borrowed here
|
||||
|
|
||||
note: function requires argument type to outlive `'1`
|
||||
--> tests/compile/scope_invariance.rs:13:13
|
||||
|
@ -19,7 +19,7 @@ note: function requires argument type to outlive `'1`
|
|||
17 | | Ok(())
|
||||
18 | | })?
|
||||
| |__________________^
|
||||
help: to force the closure to take ownership of `test` (and any other referenced variables), use the `move` keyword
|
||||
help: to force the closure to take ownership of `test.field` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
14 | .create_function_mut(move |_, ()| {
|
||||
| ++++
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0597]: `ibad` does not live long enough
|
||||
--> $DIR/scope_userdata_borrow.rs:15:56
|
||||
--> tests/compile/scope_userdata_borrow.rs:15:56
|
||||
|
|
||||
11 | lua.scope(|scope| {
|
||||
| ----- has type `&Scope<'_, '1>`
|
||||
| ----- has type `&mlua::Scope<'_, '1>`
|
||||
...
|
||||
15 | scope.create_nonstatic_userdata(MyUserData(&ibad)).unwrap();
|
||||
| -------------------------------------------^^^^^--
|
||||
|
|
|
@ -1,35 +1,31 @@
|
|||
error[E0597]: `lua` does not live long enough
|
||||
--> $DIR/static_callback_args.rs:12:5
|
||||
--> tests/compile/static_callback_args.rs:12:5
|
||||
|
|
||||
12 | lua.create_function(|_, table: Table| {
|
||||
| -^^
|
||||
| |
|
||||
| _____borrowed value does not live long enough
|
||||
| |
|
||||
13 | | BAD_TIME.with(|bt| {
|
||||
14 | | *bt.borrow_mut() = Some(table);
|
||||
15 | | });
|
||||
16 | | Ok(())
|
||||
17 | | })?
|
||||
| |______- argument requires that `lua` is borrowed for `'static`
|
||||
12 | / lua.create_function(|_, table: Table| {
|
||||
13 | | BAD_TIME.with(|bt| {
|
||||
| |_________-
|
||||
14 | || *bt.borrow_mut() = Some(table);
|
||||
15 | || });
|
||||
| ||__________- argument requires that `lua` is borrowed for `'static`
|
||||
16 | | Ok(())
|
||||
17 | | })?
|
||||
| |______^ borrowed value does not live long enough
|
||||
...
|
||||
32 | }
|
||||
| - `lua` dropped here while still borrowed
|
||||
32 | }
|
||||
| - `lua` dropped here while still borrowed
|
||||
|
||||
error[E0505]: cannot move out of `lua` because it is borrowed
|
||||
--> $DIR/static_callback_args.rs:22:10
|
||||
--> tests/compile/static_callback_args.rs:22:10
|
||||
|
|
||||
12 | lua.create_function(|_, table: Table| {
|
||||
| ---
|
||||
| |
|
||||
| _____borrow of `lua` occurs here
|
||||
| |
|
||||
13 | | BAD_TIME.with(|bt| {
|
||||
14 | | *bt.borrow_mut() = Some(table);
|
||||
15 | | });
|
||||
16 | | Ok(())
|
||||
17 | | })?
|
||||
| |______- argument requires that `lua` is borrowed for `'static`
|
||||
12 | / lua.create_function(|_, table: Table| {
|
||||
13 | | BAD_TIME.with(|bt| {
|
||||
| |_________-
|
||||
14 | || *bt.borrow_mut() = Some(table);
|
||||
15 | || });
|
||||
| ||__________- argument requires that `lua` is borrowed for `'static`
|
||||
16 | | Ok(())
|
||||
17 | | })?
|
||||
| |______- borrow of `lua` occurs here
|
||||
...
|
||||
22 | drop(lua);
|
||||
| ^^^ move out of `lua` occurs here
|
||||
22 | drop(lua);
|
||||
| ^^^ move out of `lua` occurs here
|
||||
|
|
|
@ -42,11 +42,17 @@ fn test_bind() -> Result<()> {
|
|||
concat = concat.bind("foo")?;
|
||||
concat = concat.bind("bar")?;
|
||||
concat = concat.bind(("baz", "baf"))?;
|
||||
assert_eq!(concat.call::<_, String>(())?, "foobarbazbaf");
|
||||
assert_eq!(
|
||||
concat.call::<_, String>(("hi", "wut"))?,
|
||||
"foobarbazbafhiwut"
|
||||
);
|
||||
|
||||
let mut concat2 = globals.get::<_, Function>("concat")?;
|
||||
concat2 = concat2.bind(())?;
|
||||
assert_eq!(concat2.call::<_, String>(())?, "");
|
||||
assert_eq!(concat2.call::<_, String>(("ab", "cd"))?, "abcd");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -93,6 +99,7 @@ fn test_c_function() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[test]
|
||||
fn test_dump() -> Result<()> {
|
||||
let lua = unsafe { Lua::unsafe_new() };
|
||||
|
@ -106,3 +113,57 @@ fn test_dump() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_function_info() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let globals = lua.globals();
|
||||
lua.load(
|
||||
r#"
|
||||
function function1()
|
||||
return function() end
|
||||
end
|
||||
"#,
|
||||
)
|
||||
.set_name("source1")?
|
||||
.exec()?;
|
||||
|
||||
let function1 = globals.get::<_, Function>("function1")?;
|
||||
let function2 = function1.call::<_, Function>(())?;
|
||||
let function3 = lua.create_function(|_, ()| Ok(()))?;
|
||||
|
||||
let function1_info = function1.info();
|
||||
#[cfg(feature = "luau")]
|
||||
assert_eq!(function1_info.name, Some(b"function1".to_vec()));
|
||||
assert_eq!(function1_info.source, Some(b"source1".to_vec()));
|
||||
assert_eq!(function1_info.line_defined, 2);
|
||||
#[cfg(not(feature = "luau"))]
|
||||
assert_eq!(function1_info.last_line_defined, 4);
|
||||
assert_eq!(function1_info.what, Some(b"Lua".to_vec()));
|
||||
|
||||
let function2_info = function2.info();
|
||||
assert_eq!(function2_info.name, None);
|
||||
assert_eq!(function2_info.source, Some(b"source1".to_vec()));
|
||||
assert_eq!(function2_info.line_defined, 3);
|
||||
#[cfg(not(feature = "luau"))]
|
||||
assert_eq!(function2_info.last_line_defined, 3);
|
||||
assert_eq!(function2_info.what, Some(b"Lua".to_vec()));
|
||||
|
||||
let function3_info = function3.info();
|
||||
assert_eq!(function3_info.name, None);
|
||||
assert_eq!(function3_info.source, Some(b"=[C]".to_vec()));
|
||||
assert_eq!(function3_info.line_defined, -1);
|
||||
#[cfg(not(feature = "luau"))]
|
||||
assert_eq!(function3_info.last_line_defined, -1);
|
||||
assert_eq!(function3_info.what, Some(b"C".to_vec()));
|
||||
|
||||
let print_info = globals.get::<_, Function>("print")?.info();
|
||||
#[cfg(feature = "luau")]
|
||||
assert_eq!(print_info.name, Some(b"print".to_vec()));
|
||||
assert_eq!(print_info.source, Some(b"=[C]".to_vec()));
|
||||
assert_eq!(print_info.what, Some(b"C".to_vec()));
|
||||
assert_eq!(print_info.line_defined, -1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#![cfg(not(feature = "luau"))]
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::ops::Deref;
|
||||
use std::str;
|
||||
use std::sync::atomic::{AtomicI64, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use mlua::{DebugEvent, Error, HookTriggers, Lua, Result, Value};
|
||||
|
@ -126,18 +129,17 @@ fn test_error_within_hook() -> Result<()> {
|
|||
#[test]
|
||||
fn test_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
|
||||
#[cfg(feature = "luajit")]
|
||||
lua.load("jit.off()").exec()?;
|
||||
|
||||
let max_instructions = AtomicI64::new(10000);
|
||||
lua.set_hook(
|
||||
HookTriggers::every_nth_instruction(30),
|
||||
move |_lua, debug| {
|
||||
assert_eq!(debug.event(), DebugEvent::Count);
|
||||
max_instructions -= 30;
|
||||
if max_instructions < 0 {
|
||||
if max_instructions.fetch_sub(30, Ordering::Relaxed) <= 30 {
|
||||
Err(Error::RuntimeError("time's up".to_string()))
|
||||
} else {
|
||||
Ok(())
|
||||
|
|
310
tests/luau.rs
Normal file
310
tests/luau.rs
Normal file
|
@ -0,0 +1,310 @@
|
|||
#![cfg(feature = "luau")]
|
||||
|
||||
use std::env;
|
||||
use std::fmt::Debug;
|
||||
use std::fs;
|
||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use mlua::{Compiler, CoverageInfo, Error, Lua, Result, Table, ThreadStatus, Value, VmState};
|
||||
|
||||
#[test]
|
||||
fn test_require() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
fs::write(
|
||||
temp_dir.path().join("module.luau"),
|
||||
r#"
|
||||
counter = (counter or 0) + 1
|
||||
return {
|
||||
counter = counter,
|
||||
error = function() error("test") end,
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
|
||||
env::set_var("LUAU_PATH", temp_dir.path().join("?.luau"));
|
||||
lua.load(
|
||||
r#"
|
||||
local module = require("module")
|
||||
assert(module.counter == 1)
|
||||
module = require("module")
|
||||
assert(module.counter == 1)
|
||||
|
||||
local ok, err = pcall(module.error)
|
||||
assert(not ok and string.find(err, "module.luau") ~= nil)
|
||||
"#,
|
||||
)
|
||||
.exec()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vectors() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let v: [f32; 3] = lua.load("vector(1, 2, 3) + vector(3, 2, 1)").eval()?;
|
||||
assert_eq!(v, [4.0, 4.0, 4.0]);
|
||||
|
||||
// Test vector methods
|
||||
lua.load(
|
||||
r#"
|
||||
local v = vector(1, 2, 3)
|
||||
assert(v.x == 1)
|
||||
assert(v.y == 2)
|
||||
assert(v.z == 3)
|
||||
"#,
|
||||
)
|
||||
.exec()?;
|
||||
|
||||
// Test vector methods (fastcall)
|
||||
lua.load(
|
||||
r#"
|
||||
local v = vector(1, 2, 3)
|
||||
assert(v.x == 1)
|
||||
assert(v.y == 2)
|
||||
assert(v.z == 3)
|
||||
"#,
|
||||
)
|
||||
.set_compiler(Compiler::new().set_vector_ctor(Some("vector".to_string())))
|
||||
.exec()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_readonly_table() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let t = lua.create_sequence_from([1])?;
|
||||
assert!(!t.is_readonly());
|
||||
t.set_readonly(true);
|
||||
assert!(t.is_readonly());
|
||||
|
||||
#[track_caller]
|
||||
fn check_readonly_error<T: Debug>(res: Result<T>) {
|
||||
match res {
|
||||
Err(Error::RuntimeError(e)) if e.contains("attempt to modify a readonly table") => {}
|
||||
r => panic!("expected RuntimeError(...) with a specific message, got {r:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
check_readonly_error(t.set("key", "value"));
|
||||
check_readonly_error(t.raw_set("key", "value"));
|
||||
check_readonly_error(t.raw_insert(1, "value"));
|
||||
check_readonly_error(t.raw_remove(1));
|
||||
check_readonly_error(t.push("value"));
|
||||
check_readonly_error(t.pop::<Value>());
|
||||
check_readonly_error(t.raw_push("value"));
|
||||
check_readonly_error(t.raw_pop::<Value>());
|
||||
|
||||
// Special case
|
||||
match catch_unwind(AssertUnwindSafe(|| t.set_metatable(None))) {
|
||||
Ok(_) => panic!("expected panic, got nothing"),
|
||||
Err(_) => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sandbox() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
lua.sandbox(true)?;
|
||||
|
||||
lua.load("global = 123").exec()?;
|
||||
let n: i32 = lua.load("return global").eval()?;
|
||||
assert_eq!(n, 123);
|
||||
assert_eq!(lua.globals().get::<_, Option<i32>>("global")?, Some(123));
|
||||
|
||||
// Threads should inherit "main" globals
|
||||
let f = lua.create_function(|lua, ()| lua.globals().get::<_, i32>("global"))?;
|
||||
let co = lua.create_thread(f.clone())?;
|
||||
assert_eq!(co.resume::<_, Option<i32>>(())?, Some(123));
|
||||
|
||||
// Sandboxed threads should also inherit "main" globals
|
||||
let co = lua.create_thread(f)?;
|
||||
co.sandbox()?;
|
||||
assert_eq!(co.resume::<_, Option<i32>>(())?, Some(123));
|
||||
|
||||
lua.sandbox(false)?;
|
||||
|
||||
// Previously set variable `global` should be cleared now
|
||||
assert_eq!(lua.globals().get::<_, Option<i32>>("global")?, None);
|
||||
|
||||
// Readonly flags should be cleared as well
|
||||
let table = lua.globals().get::<_, Table>("table")?;
|
||||
table.set("test", "test")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sandbox_threads() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let f = lua.create_function(|lua, v: Value| lua.globals().set("global", v))?;
|
||||
|
||||
let co = lua.create_thread(f.clone())?;
|
||||
co.resume(321)?;
|
||||
// The main state should see the `global` variable (as the thread is not sandboxed)
|
||||
assert_eq!(lua.globals().get::<_, Option<i32>>("global")?, Some(321));
|
||||
|
||||
let co = lua.create_thread(f.clone())?;
|
||||
co.sandbox()?;
|
||||
co.resume(123)?;
|
||||
// The main state should see the previous `global` value (as the thread is sandboxed)
|
||||
assert_eq!(lua.globals().get::<_, Option<i32>>("global")?, Some(321));
|
||||
|
||||
// Try to reset the (sandboxed) thread
|
||||
co.reset(f)?;
|
||||
co.resume(111)?;
|
||||
assert_eq!(lua.globals().get::<_, Option<i32>>("global")?, Some(111));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_interrupts() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let interrupts_count = Arc::new(AtomicU64::new(0));
|
||||
let interrupts_count2 = interrupts_count.clone();
|
||||
|
||||
lua.set_interrupt(move || {
|
||||
interrupts_count2.fetch_add(1, Ordering::Relaxed);
|
||||
Ok(VmState::Continue)
|
||||
});
|
||||
let f = lua
|
||||
.load(
|
||||
r#"
|
||||
local x = 2 + 3
|
||||
local y = x * 63
|
||||
local z = string.len(x..", "..y)
|
||||
"#,
|
||||
)
|
||||
.into_function()?;
|
||||
f.call(())?;
|
||||
|
||||
assert!(interrupts_count.load(Ordering::Relaxed) > 0);
|
||||
|
||||
//
|
||||
// Test yields from interrupt
|
||||
//
|
||||
let yield_count = Arc::new(AtomicU64::new(0));
|
||||
let yield_count2 = yield_count.clone();
|
||||
lua.set_interrupt(move || {
|
||||
if yield_count2.fetch_add(1, Ordering::Relaxed) == 1 {
|
||||
return Ok(VmState::Yield);
|
||||
}
|
||||
Ok(VmState::Continue)
|
||||
});
|
||||
let co = lua.create_thread(
|
||||
lua.load(
|
||||
r#"
|
||||
local a = {1, 2, 3}
|
||||
local b = 0
|
||||
for _, x in ipairs(a) do b += x end
|
||||
return b
|
||||
"#,
|
||||
)
|
||||
.into_function()?,
|
||||
)?;
|
||||
co.resume(())?;
|
||||
assert_eq!(co.status(), ThreadStatus::Resumable);
|
||||
let result: i32 = co.resume(())?;
|
||||
assert_eq!(result, 6);
|
||||
assert_eq!(yield_count.load(Ordering::Relaxed), 7);
|
||||
assert_eq!(co.status(), ThreadStatus::Unresumable);
|
||||
|
||||
//
|
||||
// Test errors in interrupts
|
||||
//
|
||||
lua.set_interrupt(|| Err(Error::RuntimeError("error from interrupt".into())));
|
||||
match f.call::<_, ()>(()) {
|
||||
Err(Error::CallbackError { cause, .. }) => match *cause {
|
||||
Error::RuntimeError(ref m) if m == "error from interrupt" => {}
|
||||
ref e => panic!("expected RuntimeError with a specific message, got {:?}", e),
|
||||
},
|
||||
r => panic!("expected CallbackError, got {:?}", r),
|
||||
}
|
||||
|
||||
lua.remove_interrupt();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_coverage() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
lua.set_compiler(Compiler::default().set_coverage_level(1));
|
||||
|
||||
let f = lua
|
||||
.load(
|
||||
r#"local v = vector(1, 2, 3)
|
||||
assert(v.x == 1 and v.y == 2 and v.z == 3)
|
||||
|
||||
function abc(i)
|
||||
if i < 5 then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
(function()
|
||||
(function() abc(10) end)()
|
||||
end)()
|
||||
"#,
|
||||
)
|
||||
.into_function()?;
|
||||
|
||||
f.call(())?;
|
||||
|
||||
let mut report = Vec::new();
|
||||
f.coverage(|cov| {
|
||||
report.push(cov);
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
report[0],
|
||||
CoverageInfo {
|
||||
function: None,
|
||||
line_defined: 1,
|
||||
depth: 0,
|
||||
hits: vec![-1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1],
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
report[1],
|
||||
CoverageInfo {
|
||||
function: Some("abc".into()),
|
||||
line_defined: 4,
|
||||
depth: 1,
|
||||
hits: vec![-1, -1, -1, -1, -1, 1, 0, -1, 1, -1, -1, -1, -1, -1, -1, -1],
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
report[2],
|
||||
CoverageInfo {
|
||||
function: None,
|
||||
line_defined: 12,
|
||||
depth: 1,
|
||||
hits: vec![-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1],
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
report[3],
|
||||
CoverageInfo {
|
||||
function: None,
|
||||
line_defined: 13,
|
||||
depth: 2,
|
||||
hits: vec![-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1],
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
#![cfg(feature = "macros")]
|
||||
|
||||
use mlua::{chunk, Lua, Result};
|
||||
|
||||
#[test]
|
||||
fn test_chunk_macro() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let name = "Rustacean";
|
||||
let table = vec![1];
|
||||
|
||||
let data = lua.create_table()?;
|
||||
data.raw_set("num", 1)?;
|
||||
|
||||
lua.globals().set("g", 123)?;
|
||||
|
||||
lua.load(chunk! {
|
||||
assert($name == "Rustacean")
|
||||
assert($table[1] == 1)
|
||||
assert($data.num == 1)
|
||||
assert(g == 123)
|
||||
s = 321
|
||||
})
|
||||
.exec()?;
|
||||
|
||||
assert_eq!(lua.globals().get::<_, i32>("s")?, 321);
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use mlua::{Lua, Result, UserData};
|
||||
use mlua::{GCMode, Lua, Result, UserData};
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
use mlua::Error;
|
||||
|
@ -39,9 +39,17 @@ fn test_gc_control() -> Result<()> {
|
|||
let globals = lua.globals();
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
assert_eq!(lua.gc_gen(0, 0), mlua::GCMode::Incremental);
|
||||
{
|
||||
assert_eq!(lua.gc_gen(0, 0), GCMode::Incremental);
|
||||
assert_eq!(lua.gc_inc(0, 0, 0), GCMode::Generational);
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luau"
|
||||
))]
|
||||
{
|
||||
assert!(lua.gc_is_running());
|
||||
lua.gc_stop();
|
||||
|
@ -50,6 +58,8 @@ fn test_gc_control() -> Result<()> {
|
|||
assert!(lua.gc_is_running());
|
||||
}
|
||||
|
||||
assert_eq!(lua.gc_inc(200, 100, 13), GCMode::Incremental);
|
||||
|
||||
struct MyUserdata(Arc<()>);
|
||||
impl UserData for MyUserdata {}
|
||||
|
||||
|
@ -62,9 +72,6 @@ fn test_gc_control() -> Result<()> {
|
|||
lua.gc_collect()?;
|
||||
assert_eq!(Arc::strong_count(&rc), 1);
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
assert_eq!(lua.gc_inc(0, 0, 0), mlua::GCMode::Generational);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
[target.x86_64-apple-darwin]
|
||||
rustflags = ["-C", "link-args=-rdynamic"]
|
||||
rustflags = [
|
||||
"-C", "link-arg=-undefined",
|
||||
"-C", "link-arg=dynamic_lookup",
|
||||
]
|
||||
|
||||
[target.aarch64-apple-darwin]
|
||||
rustflags = ["-C", "link-args=-rdynamic"]
|
||||
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
rustflags = ["-C", "link-args=-rdynamic"]
|
||||
rustflags = [
|
||||
"-C", "link-arg=-undefined",
|
||||
"-C", "link-arg=dynamic_lookup",
|
||||
]
|
||||
|
|
|
@ -1,16 +1,23 @@
|
|||
[package]
|
||||
name = "module_runner"
|
||||
name = "rust_module"
|
||||
version = "0.0.0"
|
||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"loader",
|
||||
]
|
||||
|
||||
[features]
|
||||
lua54 = ["mlua/lua54"]
|
||||
lua53 = ["mlua/lua53"]
|
||||
lua52 = ["mlua/lua52"]
|
||||
lua51 = ["mlua/lua51"]
|
||||
luajit = ["mlua/luajit"]
|
||||
vendored = ["mlua/vendored"]
|
||||
|
||||
[dependencies]
|
||||
mlua = { path = "../.." }
|
||||
mlua = { path = "../..", features = ["module"] }
|
||||
|
|
8
tests/module/loader/.cargo/config
Normal file
8
tests/module/loader/.cargo/config
Normal file
|
@ -0,0 +1,8 @@
|
|||
[target.x86_64-apple-darwin]
|
||||
rustflags = ["-C", "link-args=-rdynamic"]
|
||||
|
||||
[target.aarch64-apple-darwin]
|
||||
rustflags = ["-C", "link-args=-rdynamic"]
|
||||
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
rustflags = ["-C", "link-args=-rdynamic"]
|
16
tests/module/loader/Cargo.toml
Normal file
16
tests/module/loader/Cargo.toml
Normal file
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "module_loader"
|
||||
version = "0.0.0"
|
||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
lua54 = ["mlua/lua54"]
|
||||
lua53 = ["mlua/lua53"]
|
||||
lua52 = ["mlua/lua52"]
|
||||
lua51 = ["mlua/lua51"]
|
||||
luajit = ["mlua/luajit"]
|
||||
vendored = ["mlua/vendored"]
|
||||
|
||||
[dependencies]
|
||||
mlua = { path = "../../.." }
|
39
tests/module/src/lib.rs
Normal file
39
tests/module/src/lib.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
use mlua::prelude::*;
|
||||
|
||||
fn sum(_: &Lua, (a, b): (i64, i64)) -> LuaResult<i64> {
|
||||
Ok(a + b)
|
||||
}
|
||||
|
||||
fn used_memory(lua: &Lua, _: ()) -> LuaResult<usize> {
|
||||
Ok(lua.used_memory())
|
||||
}
|
||||
|
||||
fn check_userdata(_: &Lua, ud: MyUserData) -> LuaResult<i32> {
|
||||
Ok(ud.0)
|
||||
}
|
||||
|
||||
#[mlua::lua_module]
|
||||
fn rust_module(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let exports = lua.create_table()?;
|
||||
exports.set("sum", lua.create_function(sum)?)?;
|
||||
exports.set("used_memory", lua.create_function(used_memory)?)?;
|
||||
exports.set("check_userdata", lua.create_function(check_userdata)?)?;
|
||||
Ok(exports)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct MyUserData(i32);
|
||||
|
||||
impl LuaUserData for MyUserData {}
|
||||
|
||||
#[mlua::lua_module]
|
||||
fn rust_module_second(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let exports = lua.create_table()?;
|
||||
exports.set("userdata", lua.create_userdata(MyUserData(123))?)?;
|
||||
Ok(exports)
|
||||
}
|
||||
|
||||
#[mlua::lua_module]
|
||||
fn rust_module_error(_: &Lua) -> LuaResult<LuaTable> {
|
||||
Err("custom module error".to_lua_err())
|
||||
}
|
|
@ -144,6 +144,29 @@ fn test_serialize_failure() -> Result<(), Box<dyn std::error::Error>> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
#[test]
|
||||
fn test_serialize_vector() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let globals = lua.globals();
|
||||
globals.set(
|
||||
"vector",
|
||||
lua.create_function(|_, (x, y, z)| Ok(Value::Vector(x, y, z)))?,
|
||||
)?;
|
||||
|
||||
let val = lua.load("{_vector = vector(1, 2, 3)}").eval::<Value>()?;
|
||||
let json = serde_json::json!({
|
||||
"_vector": [1.0, 2.0, 3.0],
|
||||
});
|
||||
assert_eq!(serde_json::to_value(&val)?, json);
|
||||
|
||||
let expected_json = lua.from_value::<serde_json::Value>(val)?;
|
||||
assert_eq!(expected_json, json);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_value_struct() -> LuaResult<()> {
|
||||
let lua = Lua::new();
|
||||
|
@ -352,6 +375,19 @@ fn test_from_value_struct() -> Result<(), Box<dyn std::error::Error>> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_value_newtype_struct() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let lua = Lua::new();
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
struct Test(f64);
|
||||
|
||||
let got = lua.from_value(Value::Number(123.456))?;
|
||||
assert_eq!(Test(123.456), got);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_value_enum() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let lua = Lua::new();
|
||||
|
|
114
tests/static.rs
Normal file
114
tests/static.rs
Normal file
|
@ -0,0 +1,114 @@
|
|||
use std::cell::RefCell;
|
||||
|
||||
use mlua::{Lua, Result, Table};
|
||||
|
||||
#[test]
|
||||
fn test_static_lua() -> Result<()> {
|
||||
let lua = Lua::new().into_static();
|
||||
|
||||
thread_local! {
|
||||
static TABLE: RefCell<Option<Table<'static>>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
let f = lua.create_function(|_, table: Table| {
|
||||
TABLE.with(|t| {
|
||||
table.raw_insert(1, "hello")?;
|
||||
*t.borrow_mut() = Some(table);
|
||||
Ok(())
|
||||
})
|
||||
})?;
|
||||
|
||||
f.call(lua.create_table()?)?;
|
||||
drop(f);
|
||||
lua.gc_collect()?;
|
||||
|
||||
TABLE.with(|t| {
|
||||
assert!(t.borrow().as_ref().unwrap().len().unwrap() == 1);
|
||||
*t.borrow_mut() = None;
|
||||
});
|
||||
|
||||
// Consume the Lua instance
|
||||
unsafe { Lua::from_static(lua) };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_static_lua_coroutine() -> Result<()> {
|
||||
let lua = Lua::new().into_static();
|
||||
|
||||
thread_local! {
|
||||
static TABLE: RefCell<Option<Table<'static>>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
let f = lua.create_function(|_, table: Table| {
|
||||
TABLE.with(|t| {
|
||||
table.raw_insert(1, "hello")?;
|
||||
*t.borrow_mut() = Some(table);
|
||||
Ok(())
|
||||
})
|
||||
})?;
|
||||
|
||||
let co = lua.create_thread(f)?;
|
||||
co.resume::<_, ()>(lua.create_table()?)?;
|
||||
drop(co);
|
||||
lua.gc_collect()?;
|
||||
|
||||
TABLE.with(|t| {
|
||||
assert_eq!(
|
||||
t.borrow().as_ref().unwrap().get::<_, String>(1i32).unwrap(),
|
||||
"hello".to_string()
|
||||
);
|
||||
*t.borrow_mut() = None;
|
||||
});
|
||||
|
||||
// Consume the Lua instance
|
||||
unsafe { Lua::from_static(lua) };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[tokio::test]
|
||||
async fn test_static_async() -> Result<()> {
|
||||
let lua = Lua::new().into_static();
|
||||
|
||||
let timer =
|
||||
lua.create_async_function(|_, (i, n, f): (u64, u64, mlua::Function)| async move {
|
||||
tokio::task::spawn_local(async move {
|
||||
let dur = std::time::Duration::from_millis(i);
|
||||
for _ in 0..n {
|
||||
tokio::task::spawn_local(f.call_async::<(), ()>(()));
|
||||
tokio::time::sleep(dur).await;
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
})?;
|
||||
lua.globals().set("timer", timer)?;
|
||||
|
||||
{
|
||||
let local_set = tokio::task::LocalSet::new();
|
||||
local_set
|
||||
.run_until(
|
||||
lua.load(
|
||||
r#"
|
||||
local cnt = 0
|
||||
timer(1, 100, function()
|
||||
cnt = cnt + 1
|
||||
if cnt % 10 == 0 then
|
||||
collectgarbage()
|
||||
end
|
||||
end)
|
||||
"#,
|
||||
)
|
||||
.exec_async(),
|
||||
)
|
||||
.await?;
|
||||
local_set.await;
|
||||
}
|
||||
|
||||
// Consume the Lua instance
|
||||
unsafe { Lua::from_static(lua) };
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
use std::borrow::Cow;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use mlua::{Lua, Result, String};
|
||||
|
||||
|
@ -67,3 +68,18 @@ fn test_raw_string() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_hash() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let set: HashSet<String> = lua.load(r#"{"hello", "world", "abc", 321}"#).eval()?;
|
||||
assert_eq!(set.len(), 4);
|
||||
assert!(set.contains(b"hello".as_ref()));
|
||||
assert!(set.contains(b"world".as_ref()));
|
||||
assert!(set.contains(b"abc".as_ref()));
|
||||
assert!(set.contains(b"321".as_ref()));
|
||||
assert!(!set.contains(b"Hello".as_ref()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -109,6 +109,49 @@ fn test_table() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_table_push_pop() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
// Test raw access
|
||||
let table1 = lua.create_sequence_from(vec![123])?;
|
||||
table1.raw_push(321)?;
|
||||
assert_eq!(
|
||||
table1
|
||||
.clone()
|
||||
.raw_sequence_values::<i64>()
|
||||
.collect::<Result<Vec<_>>>()?,
|
||||
vec![123, 321]
|
||||
);
|
||||
assert_eq!(table1.raw_pop::<i64>()?, 321);
|
||||
assert_eq!(table1.raw_pop::<i64>()?, 123);
|
||||
assert_eq!(table1.raw_pop::<Value>()?, Value::Nil); // An extra pop should do nothing
|
||||
assert_eq!(table1.raw_len(), 0);
|
||||
|
||||
// Test access through metamethods
|
||||
let table2 = lua
|
||||
.load(
|
||||
r#"
|
||||
local proxy_table = {234}
|
||||
table2 = setmetatable({}, {
|
||||
__len = function() return #proxy_table end,
|
||||
__index = proxy_table,
|
||||
__newindex = proxy_table,
|
||||
})
|
||||
return table2
|
||||
"#,
|
||||
)
|
||||
.eval::<Table>()?;
|
||||
table2.push(345)?;
|
||||
assert_eq!(table2.len()?, 2);
|
||||
assert_eq!(table2.pop::<i64>()?, 345);
|
||||
assert_eq!(table2.pop::<i64>()?, 234);
|
||||
assert_eq!(table2.pop::<Value>()?, Value::Nil);
|
||||
assert_eq!(table2.len()?, 0);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_table_sequence_from() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
|
|
@ -11,6 +11,7 @@ use mlua::{
|
|||
UserData, Value, Variadic,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[test]
|
||||
fn test_safety() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
@ -46,23 +47,6 @@ fn test_safety() -> Result<()> {
|
|||
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
|
||||
|
@ -89,6 +73,7 @@ fn test_load() -> Result<()> {
|
|||
let result: i32 = func.call(())?;
|
||||
assert_eq!(result, 3);
|
||||
|
||||
assert!(lua.load("").exec().is_ok());
|
||||
assert!(lua.load("§$%§&$%&").exec().is_err());
|
||||
|
||||
Ok(())
|
||||
|
@ -120,6 +105,7 @@ fn test_exec() -> Result<()> {
|
|||
"#,
|
||||
)
|
||||
.eval()?;
|
||||
println!("checkpoint");
|
||||
assert!(module.contains_key("func")?);
|
||||
assert_eq!(
|
||||
module.get::<_, Function>("func")?.call::<_, String>(())?,
|
||||
|
@ -166,7 +152,10 @@ fn test_load_mode() -> Result<()> {
|
|||
Err(e) => panic!("expected SyntaxError, got {:?}", e),
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
let bytecode = lua.load("return 1 + 1").into_function()?.dump(true);
|
||||
#[cfg(feature = "luau")]
|
||||
let bytecode = mlua::Compiler::new().compile("return 1 + 1");
|
||||
assert_eq!(lua.load(&bytecode).eval::<i32>()?, 2);
|
||||
assert_eq!(
|
||||
lua.load(&bytecode)
|
||||
|
@ -250,15 +239,7 @@ fn test_error() -> Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
impl error::Error for TestError {
|
||||
fn description(&self) -> &str {
|
||||
"test error"
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&dyn error::Error> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl error::Error for TestError {}
|
||||
|
||||
let lua = Lua::new();
|
||||
|
||||
|
@ -295,8 +276,8 @@ fn test_error() -> Result<()> {
|
|||
end, 3)
|
||||
|
||||
local function handler(err)
|
||||
if string.match(_VERSION, ' 5%.1$') or string.match(_VERSION, ' 5%.2$') then
|
||||
-- Special case for Lua 5.1/5.2
|
||||
if string.match(_VERSION, ' 5%.1$') or string.match(_VERSION, ' 5%.2$') or _VERSION == "Luau" then
|
||||
-- Special case for Lua 5.1/5.2 and Luau
|
||||
local caps = string.match(err, ': (%d+)$')
|
||||
if caps then
|
||||
err = caps
|
||||
|
@ -580,7 +561,12 @@ fn test_num_conversion() -> Result<()> {
|
|||
assert_eq!(lua.load("1.0").eval::<f64>()?, 1.0);
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
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",
|
||||
feature = "luau"
|
||||
))]
|
||||
assert_eq!(lua.load("1.0").eval::<String>()?, "1");
|
||||
|
||||
assert_eq!(lua.load("1.5").eval::<i64>()?, 1);
|
||||
|
@ -807,6 +793,17 @@ fn test_replace_registry_value() -> Result<()> {
|
|||
let key = lua.create_registry_value::<i32>(42)?;
|
||||
lua.replace_registry_value(&key, "new value")?;
|
||||
assert_eq!(lua.registry_value::<String>(&key)?, "new value");
|
||||
lua.replace_registry_value(&key, Value::Nil)?;
|
||||
assert_eq!(lua.registry_value::<Value>(&key)?, Value::Nil);
|
||||
lua.replace_registry_value(&key, 123)?;
|
||||
assert_eq!(lua.registry_value::<i32>(&key)?, 123);
|
||||
|
||||
// It should be impossible to replace (initial) nil value with non-nil
|
||||
let key2 = lua.create_registry_value(Value::Nil)?;
|
||||
match lua.replace_registry_value(&key2, "abc") {
|
||||
Err(Error::RuntimeError(_)) => {}
|
||||
r => panic!("expected RuntimeError, got {r:?}"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -858,6 +855,28 @@ fn test_mismatched_registry_key() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_registry_value_reuse() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let r1 = lua.create_registry_value("value1")?;
|
||||
let r1_slot = format!("{r1:?}");
|
||||
drop(r1);
|
||||
|
||||
// Previous slot must not be reused by nil value
|
||||
let r2 = lua.create_registry_value(Value::Nil)?;
|
||||
let r2_slot = format!("{r2:?}");
|
||||
assert_ne!(r1_slot, r2_slot);
|
||||
drop(r2);
|
||||
|
||||
// But should be reused by non-nil value
|
||||
let r3 = lua.create_registry_value("value3")?;
|
||||
let r3_slot = format!("{r3:?}");
|
||||
assert_eq!(r1_slot, r3_slot);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_application_data() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
@ -1096,7 +1115,11 @@ fn test_context_thread() -> Result<()> {
|
|||
))]
|
||||
f.call::<_, ()>(lua.current_thread())?;
|
||||
|
||||
#[cfg(any(feature = "lua51", all(feature = "luajit", not(feature = "luajit52"))))]
|
||||
#[cfg(any(
|
||||
feature = "lua51",
|
||||
all(feature = "luajit", not(feature = "luajit52")),
|
||||
feature = "luau"
|
||||
))]
|
||||
f.call::<_, ()>(Nil)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -1288,3 +1311,14 @@ fn test_luajit_cdata() {
|
|||
)
|
||||
.eval();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "send")]
|
||||
fn test_send() {
|
||||
let lua = Lua::new();
|
||||
std::thread::spawn(move || {
|
||||
let _lua = lua;
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
|
|
@ -94,7 +94,11 @@ fn test_thread() -> Result<()> {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored")))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
all(feature = "luajit", feature = "vendored"),
|
||||
feature = "luau",
|
||||
))]
|
||||
fn test_thread_reset() -> Result<()> {
|
||||
use mlua::{AnyUserData, UserData};
|
||||
use std::sync::Arc;
|
||||
|
@ -121,14 +125,14 @@ fn test_thread_reset() -> Result<()> {
|
|||
assert_eq!(Arc::strong_count(&arc), 1);
|
||||
}
|
||||
|
||||
// Check for errors (Lua 5.4 only)
|
||||
// Check for errors
|
||||
let func: Function = lua.load(r#"function(ud) error("test error") end"#).eval()?;
|
||||
let thread = lua.create_thread(func.clone())?;
|
||||
let _ = thread.resume::<_, AnyUserData>(MyUserData(arc.clone()));
|
||||
assert_eq!(thread.status(), ThreadStatus::Error);
|
||||
assert_eq!(Arc::strong_count(&arc), 2);
|
||||
#[cfg(feature = "lua54")]
|
||||
{
|
||||
let func: Function = lua.load(r#"function(ud) error("test error") end"#).eval()?;
|
||||
let thread = lua.create_thread(func.clone())?;
|
||||
let _ = thread.resume::<_, AnyUserData>(MyUserData(arc.clone()));
|
||||
assert_eq!(thread.status(), ThreadStatus::Error);
|
||||
assert_eq!(Arc::strong_count(&arc), 2);
|
||||
assert!(thread.reset(func.clone()).is_err());
|
||||
// Reset behavior has changed in Lua v5.4.4
|
||||
// It's became possible to force reset thread by popping error object
|
||||
|
@ -140,6 +144,11 @@ fn test_thread_reset() -> Result<()> {
|
|||
// assert!(thread.reset(func.clone()).is_ok());
|
||||
// assert_eq!(thread.status(), ThreadStatus::Resumable);
|
||||
}
|
||||
#[cfg(any(feature = "lua54", feature = "luau"))]
|
||||
{
|
||||
assert!(thread.reset(func.clone()).is_ok());
|
||||
assert_eq!(thread.status(), ThreadStatus::Resumable);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -155,7 +164,8 @@ fn test_coroutine_from_closure() -> Result<()> {
|
|||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luajit"
|
||||
feature = "luajit",
|
||||
feature = "luau"
|
||||
))]
|
||||
let thrd: Thread = lua.load("coroutine.create(main)").eval()?;
|
||||
#[cfg(feature = "lua51")]
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::sync::Arc;
|
||||
#[cfg(not(feature = "parking_lot"))]
|
||||
use std::sync::{Mutex, RwLock};
|
||||
|
||||
#[cfg(feature = "parking_lot")]
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
|
||||
#[cfg(not(feature = "send"))]
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
@ -350,7 +355,7 @@ fn test_userdata_take() -> Result<()> {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_destroy_userdata() -> Result<()> {
|
||||
fn test_userdata_destroy() -> Result<()> {
|
||||
struct MyUserdata(Arc<()>);
|
||||
|
||||
impl UserData for MyUserdata {}
|
||||
|
@ -358,12 +363,15 @@ fn test_destroy_userdata() -> Result<()> {
|
|||
let rc = Arc::new(());
|
||||
|
||||
let lua = Lua::new();
|
||||
lua.globals().set("userdata", MyUserdata(rc.clone()))?;
|
||||
let ud = lua.create_userdata(MyUserdata(rc.clone()))?;
|
||||
ud.set_user_value(MyUserdata(rc.clone()))?;
|
||||
lua.globals().set("userdata", ud)?;
|
||||
|
||||
assert_eq!(Arc::strong_count(&rc), 2);
|
||||
assert_eq!(Arc::strong_count(&rc), 3);
|
||||
|
||||
// should destroy all objects
|
||||
let _ = lua.globals().raw_remove("userdata")?;
|
||||
// Should destroy all objects
|
||||
lua.globals().raw_remove("userdata")?;
|
||||
lua.gc_collect()?;
|
||||
lua.gc_collect()?;
|
||||
|
||||
assert_eq!(Arc::strong_count(&rc), 1);
|
||||
|
@ -620,7 +628,10 @@ fn test_userdata_wrapped() -> Result<()> {
|
|||
"#,
|
||||
)
|
||||
.exec()?;
|
||||
#[cfg(not(feature = "parking_lot"))]
|
||||
assert_eq!(ud2.lock().unwrap().0, 3);
|
||||
#[cfg(feature = "parking_lot")]
|
||||
assert_eq!(ud2.lock().0, 3);
|
||||
|
||||
let ud3 = Arc::new(RwLock::new(MyUserData(3)));
|
||||
globals.set("arc_rwlock_ud", ud3.clone())?;
|
||||
|
@ -631,7 +642,10 @@ fn test_userdata_wrapped() -> Result<()> {
|
|||
"#,
|
||||
)
|
||||
.exec()?;
|
||||
#[cfg(not(feature = "parking_lot"))]
|
||||
assert_eq!(ud3.read().unwrap().0, 4);
|
||||
#[cfg(feature = "parking_lot")]
|
||||
assert_eq!(ud3.read().0, 4);
|
||||
|
||||
// Test drop
|
||||
globals.set("arc_mutex_ud", Nil)?;
|
||||
|
@ -642,3 +656,44 @@ fn test_userdata_wrapped() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_userdata_proxy() -> Result<()> {
|
||||
struct MyUserData(i64);
|
||||
|
||||
impl UserData for MyUserData {
|
||||
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
fields.add_field_function_get("static_field", |_, _| Ok(123));
|
||||
fields.add_field_method_get("n", |_, this| Ok(this.0));
|
||||
}
|
||||
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_function("new", |_, n| Ok(Self(n)));
|
||||
|
||||
methods.add_method("plus", |_, this, n: i64| Ok(this.0 + n));
|
||||
}
|
||||
}
|
||||
|
||||
let lua = Lua::new();
|
||||
let globals = lua.globals();
|
||||
globals.set("MyUserData", lua.create_proxy::<MyUserData>()?)?;
|
||||
|
||||
lua.load(
|
||||
r#"
|
||||
assert(MyUserData.static_field == 123)
|
||||
local data = MyUserData.new(321)
|
||||
assert(data.static_field == 123)
|
||||
assert(data.n == 321)
|
||||
assert(data:plus(1) == 322)
|
||||
|
||||
-- Error when accessing the proxy object fields and methods that require instance
|
||||
|
||||
local ok = pcall(function() return MyUserData.n end)
|
||||
assert(not ok)
|
||||
|
||||
ok = pcall(function() return MyUserData:plus(1) end)
|
||||
assert(not ok)
|
||||
"#,
|
||||
)
|
||||
.exec()
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue