mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
Compare commits
228 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| c85616137a | |||
| f52d106a82 | |||
| 10826a7e67 | |||
| 18c3255c90 | |||
| 6190427f37 | |||
| 9a5a341e44 | |||
| dd91ebfbe5 | |||
| f9fe869b76 | |||
| 6e4033abba | |||
| c213a85ef0 | |||
| 4963cc1b8b | |||
| 418e8fba32 | |||
| 08a7e30820 | |||
| 19676bda40 | |||
| 5a06778fbc | |||
| e33bdddc7a | |||
| cfb5d3fd45 | |||
| 84a174c94d | |||
| 888b2bbf8d | |||
| 386eb7a2b7 | |||
| 66c9c633b2 | |||
| f1e357ce52 | |||
| be09a1fabf | |||
| 30af045c6f | |||
| e809640b7e | |||
| cb3ef20ffc | |||
| 3b6564c02a | |||
| 89580dd863 | |||
| a0554a56d4 | |||
| 2fee3e7891 | |||
| 9f073ad879 | |||
| 1b74c89509 | |||
| 440862de38 | |||
| 066d28f5e5 | |||
| 4528f93345 | |||
| d49757c7db | |||
| 170818c469 | |||
| 55c8af1e6b | |||
| e2ebe65306 | |||
| f0f5a8a0af | |||
| 0e1be19cbb | |||
| 0ef709672d | |||
| 41503b4fb8 | |||
| 19bd254e1e | |||
| 50f20e0c2c | |||
| 7efe807199 | |||
| 63ea8c7662 | |||
| 863d36d5a1 | |||
| a8017c10b9 | |||
| 2c7d7117d2 | |||
| 6d689c35aa | |||
| 8af1304fd0 | |||
| 153502ec73 | |||
| 2ea2b1f4fb | |||
| ef8c1556e6 | |||
| b0da2fc439 | |||
| 204eedde3c | |||
| fbc2973aff | |||
| d0641d812f | |||
| ad70ba54a5 | |||
| 806f0bcef4 | |||
| 0741db7565 | |||
| d88a4282c7 | |||
| d7d987fa14 | |||
| 4d3ac6d8c5 | |||
| a9ca99349c | |||
| f71db80a74 | |||
| 09af3e021a | |||
| 9e3d495f91 | |||
| cab2e5a48e | |||
| 25a4879cde | |||
| ed48b11e7f | |||
| 559f9e6c6b | |||
| 458b06796c | |||
| 259eb09ae1 | |||
| a544e41b33 | |||
| 235fba821e | |||
| c8c64a1b5a | |||
| eff0bbb052 | |||
| d098c9ccf6 | |||
| c62b17a5c8 | |||
| 584b377640 | |||
| 1141073a65 | |||
| 5b1483bd56 | |||
| a74b637ed4 | |||
| 7623016d4a | |||
| bdd3c923ba | |||
| d586eef0f5 | |||
| 01154c0616 | |||
| e42d67c70d | |||
| 771a7775c5 | |||
| ee1c8a1a3d | |||
| 3597e34ffb |
@@ -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 lua53,vendored,async,send,serialize,macros --out xml --exclude-files benches --exclude-files build --exclude-files mlua_derive --exclude-files src/ffi --exclude-files tests
|
||||
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
|
||||
|
||||
+140
-149
@@ -7,98 +7,94 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-18.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-18.04
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
- 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-18.04' && matrix.lua != 'lua54' }}
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends liblua5.3-dev liblua5.2-dev liblua5.1-0-dev libluajit-5.1-dev
|
||||
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-18.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-18.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-18.04, macos-latest, windows-latest]
|
||||
os: [ubuntu-22.04, macos-latest, windows-latest]
|
||||
rust: [stable, nightly]
|
||||
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||
lua: [lua54, lua53, lua52, lua51, luajit, luajit52, luau]
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
- 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 lua53)
|
||||
if: ${{ matrix.os == 'macos-latest' && matrix.lua == 'lua53' }}
|
||||
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-18.04]
|
||||
os: [ubuntu-22.04]
|
||||
rust: [nightly]
|
||||
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||
lua: [lua54, lua53, lua52, lua51, luajit, luau]
|
||||
include:
|
||||
- os: ubuntu-18.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-18.04, macos-latest]
|
||||
os: [ubuntu-22.04, macos-latest]
|
||||
rust: [stable]
|
||||
lua: [lua54, lua53, lua52, lua51, luajit]
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
- 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-18.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-18.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"
|
||||
|
||||
+135
@@ -1,3 +1,138 @@
|
||||
## 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.
|
||||
No need to call `Lua::expire_registry_values` when creating/dropping registry values.
|
||||
- Added `Lua::replace_registry_value` to change value of an existing Registry Key
|
||||
- Async calls optimization
|
||||
|
||||
## v0.7.3
|
||||
|
||||
- Fixed cross-compilation issue (introduced in 84a174c)
|
||||
|
||||
## v0.7.2
|
||||
|
||||
- Allow `pkg-config` to omit include paths if they equals to standard (#114).
|
||||
- Various bugfixes (eg. #121)
|
||||
|
||||
## v0.7.1
|
||||
|
||||
- Fixed traceback generation for errors (#112)
|
||||
- `Lua::into_static/from_static` methods have been removed from the docs and are discouraged for use
|
||||
|
||||
## v0.7.0
|
||||
|
||||
- New "application data" api to store arbitrary objects inside Lua
|
||||
- New feature flag `luajit52` to build/support LuaJIT with partial compatibility with Lua 5.2
|
||||
- Added async meta methods for all Lua (except 5.1)
|
||||
- Added `AnyUserData::take()` to take UserData objects from Lua
|
||||
- Added `set_nth_user_value`/`get_nth_user_value` to `AnyUserData` for all Lua versions
|
||||
- Added `set_named_user_value`/`get_named_user_value` to `AnyUserData` for all Lua versions
|
||||
- Added `Lua::inspect_stack()` to get information about the interpreter runtime stack
|
||||
- Added `set_warning_function`/`remove_warning_function`/`warning` functions to `Lua` for 5.4
|
||||
- Added `TableExt::call()` to call tables with `__call` metamethod as functions
|
||||
- Added `Lua::unload()` to unload modules
|
||||
- `ToLua` implementation for arrays changed to const generics
|
||||
- Added thread (coroutine) cache for async execution (disabled by default and works for Lua 5.4/JIT)
|
||||
- LuaOptions and (De)SerializeOptions marked as const
|
||||
- Fixed recursive tables serialization when using `serde::Serialize` for Lua Tables
|
||||
- Improved errors reporting. Now source included to `fmt::Display` implementation for `Error::CallbackError`
|
||||
- Major performance improvements
|
||||
|
||||
## v0.6.6
|
||||
|
||||
- Fixed calculating `LUA_REGISTRYINDEX` when cross-compiling for lua51/jit (#82)
|
||||
- Updated documentation & examples
|
||||
|
||||
## v0.6.5
|
||||
|
||||
- Fixed bug when polling async futures (#77)
|
||||
- Refactor Waker handling in async code (+10% performance gain when calling async functions)
|
||||
- Added `Location::caller()` information to `Lua::load()` if chunk's name is None (Rust 1.46+)
|
||||
- Added serialization of i128/u128 types (serde)
|
||||
|
||||
## v0.6.4
|
||||
|
||||
- Performance optimizations
|
||||
- Fixed table traversal used in recursion detection in deserializer
|
||||
|
||||
## v0.6.3
|
||||
|
||||
- Disabled catching Rust panics in userdata finalizers on drop. It also has positive performance impact.
|
||||
|
||||
+18
-13
@@ -1,30 +1,28 @@
|
||||
[package]
|
||||
name = "mlua"
|
||||
version = "0.6.3" # remember to update html_root_url and mlua_derive
|
||||
version = "0.8.4" # 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)
|
||||
with async/await features and support of writing native lua modules in Rust.
|
||||
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 = ["lua53", "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]
|
||||
@@ -33,6 +31,8 @@ lua53 = []
|
||||
lua52 = []
|
||||
lua51 = []
|
||||
luajit = []
|
||||
luajit52 = ["luajit"]
|
||||
luau = ["luau0-src"]
|
||||
vendored = ["lua-src", "luajit-src"]
|
||||
module = ["mlua_derive"]
|
||||
async = ["futures-core", "futures-task", "futures-util"]
|
||||
@@ -41,24 +41,27 @@ 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" }
|
||||
rustc-hash = "1.0"
|
||||
futures-core = { version = "0.3.5", optional = true }
|
||||
futures-task = { version = "0.3.5", optional = true }
|
||||
futures-util = { version = "0.3.5", optional = true }
|
||||
serde = { version = "1.0", optional = true }
|
||||
erased-serde = { version = "0.3", optional = true }
|
||||
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.1.2, < 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 = "8.0"
|
||||
rustyline = "10.0"
|
||||
criterion = { version = "0.3.4", features = ["html_reports", "async_tokio"] }
|
||||
trybuild = "1.0"
|
||||
futures = "0.3.5"
|
||||
@@ -66,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"
|
||||
@@ -84,7 +89,7 @@ required-features = ["async", "serialize", "macros"]
|
||||
|
||||
[[example]]
|
||||
name = "async_http_server"
|
||||
required-features = ["async", "send"]
|
||||
required-features = ["async", "macros"]
|
||||
|
||||
[[example]]
|
||||
name = "async_tcp_server"
|
||||
|
||||
@@ -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.
|
||||
@@ -1,5 +1,5 @@
|
||||
# mlua
|
||||
[![Build Status]][github-actions] [![Latest Version]][crates.io] [![API Documentation]][docs.rs] [![Coverage Status]][codecov.io]
|
||||
[![Build Status]][github-actions] [![Latest Version]][crates.io] [![API Documentation]][docs.rs] [![Coverage Status]][codecov.io] ![MSRV]
|
||||
|
||||
[Build Status]: https://github.com/khvzak/mlua/workflows/CI/badge.svg
|
||||
[github-actions]: https://github.com/khvzak/mlua/actions
|
||||
@@ -9,17 +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.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](https://github.com/amethyst/rlua/tree/0.15.3) fork, `mlua` supports Lua 5.4, 5.3, 5.2 and 5.1 including LuaJIT (2.0.5 and 2.1 beta) and allows to write native Lua modules in Rust as well as use Lua in a standalone mode.
|
||||
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
|
||||
|
||||
@@ -33,28 +39,35 @@ Below is a list of the available feature flags. By default `mlua` does not enabl
|
||||
* `lua52`: activate Lua [5.2] support
|
||||
* `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)
|
||||
@@ -74,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`, 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.
|
||||
@@ -97,7 +110,7 @@ Add to `Cargo.toml` :
|
||||
|
||||
``` toml
|
||||
[dependencies]
|
||||
mlua = { version = "0.6", features = ["lua53", "vendored"] }
|
||||
mlua = { version = "0.8", features = ["lua54", "vendored"] }
|
||||
```
|
||||
|
||||
`main.rs`
|
||||
@@ -121,7 +134,7 @@ fn main() -> LuaResult<()> {
|
||||
```
|
||||
|
||||
### Module mode
|
||||
In a module mode `mlua` allows to create a compiled Lua module that can be loaded from Lua code using [`require`](https://www.lua.org/manual/5.3/manual.html#pdf-require). In this case `mlua` uses an external Lua runtime which could lead to potential unsafety due to unpredictability of the Lua environment and usage of libraries such as [`debug`](https://www.lua.org/manual/5.3/manual.html#6.10).
|
||||
In a module mode `mlua` allows to create a compiled Lua module that can be loaded from Lua code using [`require`](https://www.lua.org/manual/5.4/manual.html#pdf-require). In this case `mlua` uses an external Lua runtime which could lead to potential unsafety due to unpredictability of the Lua environment and usage of libraries such as [`debug`](https://www.lua.org/manual/5.4/manual.html#6.10).
|
||||
|
||||
[Example](examples/module)
|
||||
|
||||
@@ -132,7 +145,7 @@ Add to `Cargo.toml` :
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
mlua = { version = "0.6", features = ["lua53", "vendored", "module"] }
|
||||
mlua = { version = "0.8", features = ["lua54", "vendored", "module"] }
|
||||
```
|
||||
|
||||
`lib.rs` :
|
||||
@@ -158,7 +171,7 @@ And then (**macOS** example):
|
||||
``` sh
|
||||
$ cargo rustc -- -C link-arg=-undefined -C link-arg=dynamic_lookup
|
||||
$ ln -s ./target/debug/libmy_module.dylib ./my_module.so
|
||||
$ lua5.3 -e 'require("my_module").hello("world")'
|
||||
$ lua5.4 -e 'require("my_module").hello("world")'
|
||||
hello, world!
|
||||
```
|
||||
|
||||
@@ -247,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)
|
||||
|
||||
+32
-2
@@ -120,7 +120,8 @@ fn call_sum_callback(c: &mut Criterion) {
|
||||
}
|
||||
|
||||
fn call_async_sum_callback(c: &mut Criterion) {
|
||||
let lua = Lua::new();
|
||||
let options = LuaOptions::new().thread_cache_size(1024);
|
||||
let lua = Lua::new_with(LuaStdLib::ALL_SAFE, options).unwrap();
|
||||
let callback = lua
|
||||
.create_async_function(|_, (a, b, c): (i64, i64, i64)| async move {
|
||||
task::yield_now().await;
|
||||
@@ -208,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 {
|
||||
@@ -244,7 +272,8 @@ fn call_async_userdata_method(c: &mut Criterion) {
|
||||
}
|
||||
}
|
||||
|
||||
let lua = Lua::new();
|
||||
let options = LuaOptions::new().thread_cache_size(1024);
|
||||
let lua = Lua::new_with(LuaStdLib::ALL_SAFE, options).unwrap();
|
||||
lua.globals().set("userdata", UserData(10)).unwrap();
|
||||
|
||||
c.bench_function("call async [userdata method] 10", |b| {
|
||||
@@ -281,6 +310,7 @@ criterion_group! {
|
||||
call_concat_callback,
|
||||
create_registry_values,
|
||||
create_userdata,
|
||||
call_userdata_index,
|
||||
call_userdata_method,
|
||||
call_async_userdata_method,
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn probe_lua() -> PathBuf {
|
||||
unreachable!()
|
||||
pub fn probe_lua() -> Option<PathBuf> {
|
||||
None
|
||||
}
|
||||
|
||||
+26
-52
@@ -1,3 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::env;
|
||||
use std::ops::Bound;
|
||||
use std::path::PathBuf;
|
||||
@@ -10,7 +12,7 @@ fn get_env_var(name: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn probe_lua() -> PathBuf {
|
||||
pub fn probe_lua() -> Option<PathBuf> {
|
||||
let include_dir = get_env_var("LUA_INC");
|
||||
let lib_dir = get_env_var("LUA_LIB");
|
||||
let lua_lib = get_env_var("LUA_LIB_NAME");
|
||||
@@ -38,82 +40,54 @@ pub fn probe_lua() -> PathBuf {
|
||||
println!("cargo:rustc-link-search=native={}", lib_dir);
|
||||
println!("cargo:rustc-link-lib={}{}", link_lib, lua_lib);
|
||||
}
|
||||
return PathBuf::from(include_dir);
|
||||
return Some(PathBuf::from(include_dir));
|
||||
}
|
||||
|
||||
// Find using `pkg-config`
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
{
|
||||
let mut lua = pkg_config::Config::new()
|
||||
.range_version((Bound::Included("5.4"), Bound::Excluded("5.5")))
|
||||
.cargo_metadata(need_lua_lib)
|
||||
.probe("lua");
|
||||
|
||||
if lua.is_err() {
|
||||
lua = pkg_config::Config::new()
|
||||
.cargo_metadata(need_lua_lib)
|
||||
.probe("lua5.4");
|
||||
}
|
||||
|
||||
lua.unwrap().include_paths[0].clone()
|
||||
}
|
||||
|
||||
let (incl_bound, excl_bound, alt_probe, ver) = ("5.4", "5.5", "lua5.4", "5.4");
|
||||
#[cfg(feature = "lua53")]
|
||||
{
|
||||
let mut lua = pkg_config::Config::new()
|
||||
.range_version((Bound::Included("5.3"), Bound::Excluded("5.4")))
|
||||
.cargo_metadata(need_lua_lib)
|
||||
.probe("lua");
|
||||
|
||||
if lua.is_err() {
|
||||
lua = pkg_config::Config::new()
|
||||
.cargo_metadata(need_lua_lib)
|
||||
.probe("lua5.3");
|
||||
}
|
||||
|
||||
lua.unwrap().include_paths[0].clone()
|
||||
}
|
||||
|
||||
let (incl_bound, excl_bound, alt_probe, ver) = ("5.3", "5.4", "lua5.3", "5.3");
|
||||
#[cfg(feature = "lua52")]
|
||||
{
|
||||
let mut lua = pkg_config::Config::new()
|
||||
.range_version((Bound::Included("5.2"), Bound::Excluded("5.3")))
|
||||
.cargo_metadata(need_lua_lib)
|
||||
.probe("lua");
|
||||
|
||||
if lua.is_err() {
|
||||
lua = pkg_config::Config::new()
|
||||
.cargo_metadata(need_lua_lib)
|
||||
.probe("lua5.2");
|
||||
}
|
||||
|
||||
lua.unwrap().include_paths[0].clone()
|
||||
}
|
||||
|
||||
let (incl_bound, excl_bound, alt_probe, ver) = ("5.2", "5.3", "lua5.2", "5.2");
|
||||
#[cfg(feature = "lua51")]
|
||||
let (incl_bound, excl_bound, alt_probe, ver) = ("5.1", "5.2", "lua5.1", "5.1");
|
||||
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "lua51"
|
||||
))]
|
||||
{
|
||||
let mut lua = pkg_config::Config::new()
|
||||
.range_version((Bound::Included("5.1"), Bound::Excluded("5.2")))
|
||||
.range_version((Bound::Included(incl_bound), Bound::Excluded(excl_bound)))
|
||||
.cargo_metadata(need_lua_lib)
|
||||
.probe("lua");
|
||||
|
||||
if lua.is_err() {
|
||||
lua = pkg_config::Config::new()
|
||||
.cargo_metadata(need_lua_lib)
|
||||
.probe("lua5.1");
|
||||
.probe(alt_probe);
|
||||
}
|
||||
|
||||
lua.unwrap().include_paths[0].clone()
|
||||
lua.unwrap_or_else(|_| panic!("cannot find Lua {} using `pkg-config`", ver))
|
||||
.include_paths
|
||||
.get(0)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
#[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");
|
||||
|
||||
lua.unwrap().include_paths[0].clone()
|
||||
lua.expect("cannot find LuaJIT using `pkg-config`")
|
||||
.include_paths
|
||||
.get(0)
|
||||
.cloned()
|
||||
}
|
||||
}
|
||||
|
||||
+13
-4
@@ -1,6 +1,8 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn probe_lua() -> PathBuf {
|
||||
pub fn probe_lua() -> Option<PathBuf> {
|
||||
#[cfg(feature = "lua54")]
|
||||
let artifacts = lua_src::Build::new().build(lua_src::Lua54);
|
||||
#[cfg(feature = "lua53")]
|
||||
@@ -10,10 +12,17 @@ pub fn probe_lua() -> PathBuf {
|
||||
#[cfg(feature = "lua51")]
|
||||
let artifacts = lua_src::Build::new().build(lua_src::Lua51);
|
||||
#[cfg(feature = "luajit")]
|
||||
let artifacts = luajit_src::Build::new().build();
|
||||
let artifacts = {
|
||||
let mut builder = luajit_src::Build::new();
|
||||
if cfg!(feature = "luajit52") {
|
||||
builder.lua52compat(true);
|
||||
}
|
||||
builder.build()
|
||||
};
|
||||
#[cfg(feature = "luau")]
|
||||
let artifacts = luau0_src::Build::new().build();
|
||||
|
||||
#[cfg(not(feature = "module"))]
|
||||
artifacts.print_cargo_metadata();
|
||||
|
||||
artifacts.include_dir().to_owned()
|
||||
Some(artifacts.include_dir().to_owned())
|
||||
}
|
||||
|
||||
+53
-181
@@ -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,168 +33,25 @@ 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),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn build_glue<P: AsRef<Path> + std::fmt::Debug>(include_path: &P) {
|
||||
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
|
||||
let mut config = cc::Build::new();
|
||||
config.include(include_path);
|
||||
|
||||
// Compile and run glue.c
|
||||
let glue = build_dir.join("glue");
|
||||
|
||||
config
|
||||
.get_compiler()
|
||||
.to_command()
|
||||
.arg("src/ffi/glue/glue.c")
|
||||
.arg("-o")
|
||||
.arg(&glue)
|
||||
.execute()
|
||||
.unwrap();
|
||||
|
||||
Command::new(glue)
|
||||
.arg(build_dir.join("glue.rs"))
|
||||
.execute()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// When cross-compiling, we cannot use `build_glue` as we cannot run the generated
|
||||
// executable. Instead, let's take a stab at synthesizing the likely values.
|
||||
// If you're cross-compiling and using a non-vendored library then there is a chance
|
||||
// that the values selected here may be incorrect, but we have no way to determine
|
||||
// that here.
|
||||
fn generate_glue() -> Result<()> {
|
||||
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
let mut glue = File::create(build_dir.join("glue.rs"))?;
|
||||
writeln!(
|
||||
glue,
|
||||
"/* This file was generated by build/main.rs; do not modify by hand */"
|
||||
)?;
|
||||
writeln!(glue, "use std::os::raw::*;")?;
|
||||
|
||||
writeln!(glue, "/* luaconf.h */")?;
|
||||
let pointer_bit_width: usize = env::var("CARGO_CFG_TARGET_POINTER_WIDTH")
|
||||
.unwrap()
|
||||
.parse()
|
||||
.unwrap();
|
||||
writeln!(
|
||||
glue,
|
||||
"pub const LUA_EXTRASPACE: c_int = {} / 8;",
|
||||
pointer_bit_width
|
||||
)?;
|
||||
|
||||
// This is generally hardcoded to this size
|
||||
writeln!(glue, "pub const LUA_IDSIZE: c_int = 60;")?;
|
||||
|
||||
// Unless the target is restricted, the defaults are 64 bit
|
||||
writeln!(glue, "pub type LUA_NUMBER = c_double;")?;
|
||||
writeln!(glue, "pub type LUA_INTEGER = i64;")?;
|
||||
writeln!(glue, "pub type LUA_UNSIGNED = u64;")?;
|
||||
|
||||
writeln!(glue, "/* lua.h */")?;
|
||||
let version = if cfg!(any(feature = "luajit", feature = "lua51")) {
|
||||
(5, 1, 0)
|
||||
} else if cfg!(feature = "lua52") {
|
||||
(5, 2, 0)
|
||||
} else if cfg!(feature = "lua53") {
|
||||
(5, 3, 0)
|
||||
} else if cfg!(feature = "lua54") {
|
||||
(5, 4, 0)
|
||||
} else {
|
||||
unreachable!();
|
||||
};
|
||||
writeln!(
|
||||
glue,
|
||||
"pub const LUA_VERSION_NUM: c_int = {};",
|
||||
(version.0 * 100) + version.1
|
||||
)?;
|
||||
|
||||
let max_stack = if pointer_bit_width >= 32 {
|
||||
1_000_000
|
||||
} else {
|
||||
15_000
|
||||
};
|
||||
writeln!(
|
||||
glue,
|
||||
"pub const LUA_REGISTRYINDEX: c_int = -{} - 1000;",
|
||||
max_stack
|
||||
)?;
|
||||
|
||||
// These two are only defined in lua 5.1
|
||||
writeln!(glue, "pub const LUA_ENVIRONINDEX: c_int = -10001;")?;
|
||||
writeln!(glue, "pub const LUA_GLOBALSINDEX: c_int = -10002;")?;
|
||||
|
||||
writeln!(glue, "/* lauxlib.h */")?;
|
||||
// This is only defined in lua 5.3 and up, but we can always generate its value here,
|
||||
// even if we don't use it.
|
||||
// This matches the default definition in lauxlib.h
|
||||
writeln!(glue, "pub const LUAL_NUMSIZES: c_int = std::mem::size_of::<LUA_INTEGER>() as c_int * 16 + std::mem::size_of::<LUA_NUMBER>() as c_int;")?;
|
||||
|
||||
writeln!(glue, "/* lualib.h */")?;
|
||||
write!(
|
||||
glue,
|
||||
r#"
|
||||
#[cfg(feature = "luajit")]
|
||||
pub const LUA_BITLIBNAME: &str = "bit";
|
||||
#[cfg(not(feature = "luajit"))]
|
||||
pub const LUA_BITLIBNAME: &str = "bit32";
|
||||
|
||||
pub const LUA_COLIBNAME: &str = "coroutine";
|
||||
pub const LUA_DBLIBNAME: &str = "debug";
|
||||
pub const LUA_IOLIBNAME: &str = "io";
|
||||
pub const LUA_LOADLIBNAME: &str = "package";
|
||||
pub const LUA_MATHLIBNAME: &str = "math";
|
||||
pub const LUA_OSLIBNAME: &str = "os";
|
||||
pub const LUA_STRLIBNAME: &str = "string";
|
||||
pub const LUA_TABLIBNAME: &str = "table";
|
||||
pub const LUA_UTF8LIBNAME: &str = "utf8";
|
||||
|
||||
pub const LUA_JITLIBNAME: &str = "jit";
|
||||
pub const LUA_FFILIBNAME: &str = "ffi";
|
||||
"#
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[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");
|
||||
compile_error!(
|
||||
"You must enable one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau"
|
||||
);
|
||||
|
||||
#[cfg(all(
|
||||
feature = "lua54",
|
||||
@@ -207,22 +59,44 @@ 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");
|
||||
compile_error!(
|
||||
"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");
|
||||
compile_error!(
|
||||
"You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau"
|
||||
);
|
||||
|
||||
#[cfg(all(feature = "lua52", any(feature = "lua51", feature = "luajit")))]
|
||||
compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit");
|
||||
#[cfg(all(
|
||||
feature = "lua52",
|
||||
any(feature = "lua51", feature = "luajit", feature = "luau")
|
||||
))]
|
||||
compile_error!(
|
||||
"You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau"
|
||||
);
|
||||
|
||||
#[cfg(all(feature = "lua51", feature = "luajit"))]
|
||||
compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, 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, 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
|
||||
#[cfg(all(feature = "vendored", feature = "module", target_os = "windows"))]
|
||||
@@ -231,13 +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() {
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -1,26 +1,17 @@
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use hyper::body::{Body as HyperBody, HttpBody as _};
|
||||
use hyper::Client as HyperClient;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use mlua::{chunk, ExternalResult, Lua, Result, UserData, UserDataMethods};
|
||||
use mlua::{chunk, AnyUserData, ExternalResult, Lua, Result, UserData, UserDataMethods};
|
||||
|
||||
#[derive(Clone)]
|
||||
struct BodyReader(Arc<Mutex<HyperBody>>);
|
||||
|
||||
impl BodyReader {
|
||||
fn new(body: HyperBody) -> Self {
|
||||
BodyReader(Arc::new(Mutex::new(body)))
|
||||
}
|
||||
}
|
||||
struct BodyReader(HyperBody);
|
||||
|
||||
impl UserData for BodyReader {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_async_method("read", |lua, reader, ()| async move {
|
||||
let mut reader = reader.0.lock().await;
|
||||
if let Some(bytes) = reader.data().await {
|
||||
methods.add_async_function("read", |lua, reader: AnyUserData| async move {
|
||||
let mut reader = reader.borrow_mut::<Self>()?;
|
||||
if let Some(bytes) = reader.0.data().await {
|
||||
let bytes = bytes.to_lua_err()?;
|
||||
return Some(lua.create_string(&bytes)).transpose();
|
||||
}
|
||||
@@ -50,7 +41,7 @@ async fn main() -> Result<()> {
|
||||
}
|
||||
|
||||
lua_resp.set("headers", headers)?;
|
||||
lua_resp.set("body", BodyReader::new(resp.into_body()))?;
|
||||
lua_resp.set("body", BodyReader(resp.into_body()))?;
|
||||
|
||||
Ok(lua_resp)
|
||||
})?;
|
||||
@@ -58,7 +49,7 @@ async fn main() -> Result<()> {
|
||||
let f = lua
|
||||
.load(chunk! {
|
||||
local res = $fetch_url(...)
|
||||
print(res.status)
|
||||
print("status: "..res.status)
|
||||
for key, vals in pairs(res.headers) do
|
||||
for _, val in ipairs(vals) do
|
||||
print(key..": "..val)
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
use std::future::Future;
|
||||
use std::net::SocketAddr;
|
||||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use hyper::server::conn::AddrStream;
|
||||
use hyper::service::{make_service_fn, service_fn};
|
||||
use hyper::service::Service;
|
||||
use hyper::{Body, Request, Response, Server};
|
||||
|
||||
use mlua::{Error, Function, Lua, Result, Table, UserData, UserDataMethods};
|
||||
use mlua::{
|
||||
chunk, Error as LuaError, Function, Lua, String as LuaString, Table, UserData, UserDataMethods,
|
||||
};
|
||||
|
||||
struct LuaRequest(SocketAddr, Request<Body>);
|
||||
|
||||
@@ -15,75 +21,106 @@ impl UserData for LuaRequest {
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_server(handler: Function<'static>) -> Result<()> {
|
||||
let make_svc = make_service_fn(|socket: &AddrStream| {
|
||||
let remote_addr = socket.remote_addr();
|
||||
let handler = handler.clone();
|
||||
async move {
|
||||
Ok::<_, Error>(service_fn(move |req: Request<Body>| {
|
||||
let handler = handler.clone();
|
||||
async move {
|
||||
let lua_req = LuaRequest(remote_addr, req);
|
||||
let lua_resp: Table = handler.call_async(lua_req).await?;
|
||||
let body = lua_resp
|
||||
.get::<_, Option<String>>("body")?
|
||||
.unwrap_or_default();
|
||||
pub struct Svc(Rc<Lua>, SocketAddr);
|
||||
|
||||
let mut resp = Response::builder()
|
||||
.status(lua_resp.get::<_, Option<u16>>("status")?.unwrap_or(200));
|
||||
impl Service<Request<Body>> for Svc {
|
||||
type Response = Response<Body>;
|
||||
type Error = LuaError;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
|
||||
|
||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
||||
// If handler returns an error then generate 5xx response
|
||||
let lua = self.0.clone();
|
||||
let lua_req = LuaRequest(self.1, req);
|
||||
Box::pin(async move {
|
||||
let handler: Function = lua.named_registry_value("http_handler")?;
|
||||
match handler.call_async::<_, Table>(lua_req).await {
|
||||
Ok(lua_resp) => {
|
||||
let status = lua_resp.get::<_, Option<u16>>("status")?.unwrap_or(200);
|
||||
let mut resp = Response::builder().status(status);
|
||||
|
||||
// Set headers
|
||||
if let Some(headers) = lua_resp.get::<_, Option<Table>>("headers")? {
|
||||
for pair in headers.pairs::<String, String>() {
|
||||
for pair in headers.pairs::<String, LuaString>() {
|
||||
let (h, v) = pair?;
|
||||
resp = resp.header(&h, v);
|
||||
resp = resp.header(&h, v.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
Ok::<_, Error>(resp.body(Body::from(body)).unwrap())
|
||||
let body = lua_resp
|
||||
.get::<_, Option<LuaString>>("body")?
|
||||
.map(|b| Body::from(b.as_bytes().to_vec()))
|
||||
.unwrap_or_else(Body::empty);
|
||||
|
||||
Ok(resp.body(body).unwrap())
|
||||
}
|
||||
}))
|
||||
}
|
||||
});
|
||||
Err(err) => {
|
||||
eprintln!("{}", err);
|
||||
Ok(Response::builder()
|
||||
.status(500)
|
||||
.body(Body::from("Internal Server Error"))
|
||||
.unwrap())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() {
|
||||
let lua = Rc::new(Lua::new());
|
||||
|
||||
// Create Lua handler function
|
||||
let handler: Function = lua
|
||||
.load(chunk! {
|
||||
function(req)
|
||||
return {
|
||||
status = 200,
|
||||
headers = {
|
||||
["X-Req-Method"] = req:method(),
|
||||
["X-Remote-Addr"] = req:remote_addr(),
|
||||
},
|
||||
body = "Hello from Lua!\n"
|
||||
}
|
||||
end
|
||||
})
|
||||
.eval()
|
||||
.expect("cannot create Lua handler");
|
||||
|
||||
// Store it in the Registry
|
||||
lua.set_named_registry_value("http_handler", handler)
|
||||
.expect("cannot store Lua handler");
|
||||
|
||||
let addr = ([127, 0, 0, 1], 3000).into();
|
||||
let server = Server::bind(&addr).executor(LocalExec).serve(make_svc);
|
||||
let server = Server::bind(&addr).executor(LocalExec).serve(MakeSvc(lua));
|
||||
|
||||
println!("Listening on http://{}", addr);
|
||||
|
||||
tokio::task::LocalSet::new()
|
||||
.run_until(server)
|
||||
.await
|
||||
.map_err(Error::external)
|
||||
// Create `LocalSet` to spawn !Send futures
|
||||
let local = tokio::task::LocalSet::new();
|
||||
local.run_until(server).await.expect("cannot run server")
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let lua = Lua::new().into_static();
|
||||
struct MakeSvc(Rc<Lua>);
|
||||
|
||||
let handler: Function = lua
|
||||
.load(
|
||||
r#"
|
||||
function(req)
|
||||
return {
|
||||
status = 200,
|
||||
headers = {
|
||||
["X-Req-Method"] = req:method(),
|
||||
["X-Remote-Addr"] = req:remote_addr(),
|
||||
},
|
||||
body = "Hello, World!\n"
|
||||
}
|
||||
end
|
||||
"#,
|
||||
)
|
||||
.eval()?;
|
||||
impl Service<&AddrStream> for MakeSvc {
|
||||
type Response = Svc;
|
||||
type Error = hyper::Error;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
|
||||
|
||||
run_server(handler).await?;
|
||||
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
// Consume the static reference and drop it.
|
||||
// This is safe as long as we don't hold any other references to Lua
|
||||
// or alive resources.
|
||||
unsafe { Lua::from_static(lua) };
|
||||
Ok(())
|
||||
fn call(&mut self, stream: &AddrStream) -> Self::Future {
|
||||
let lua = self.0.clone();
|
||||
let remote_addr = stream.remote_addr();
|
||||
Box::pin(async move { Ok(Svc(lua, remote_addr)) })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
||||
@@ -1,122 +1,121 @@
|
||||
use std::sync::Arc;
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::rc::Rc;
|
||||
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::task;
|
||||
|
||||
use mlua::{chunk, Function, Lua, Result, String as LuaString, UserData, UserDataMethods};
|
||||
use mlua::{
|
||||
chunk, AnyUserData, Function, Lua, RegistryKey, String as LuaString, UserData, UserDataMethods,
|
||||
};
|
||||
|
||||
struct LuaTcp;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct LuaTcpListener(Arc<Mutex<TcpListener>>);
|
||||
|
||||
#[derive(Clone)]
|
||||
struct LuaTcpStream(Arc<Mutex<TcpStream>>);
|
||||
|
||||
impl UserData for LuaTcp {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_async_function("bind", |_, addr: String| async move {
|
||||
let listener = TcpListener::bind(addr).await?;
|
||||
Ok(LuaTcpListener(Arc::new(Mutex::new(listener))))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for LuaTcpListener {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_async_method("accept", |_, listener, ()| async move {
|
||||
let (stream, _) = listener.0.lock().await.accept().await?;
|
||||
Ok(LuaTcpStream(Arc::new(Mutex::new(stream))))
|
||||
});
|
||||
}
|
||||
}
|
||||
struct LuaTcpStream(TcpStream);
|
||||
|
||||
impl UserData for LuaTcpStream {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_async_method("peer_addr", |_, stream, ()| async move {
|
||||
Ok(stream.0.lock().await.peer_addr()?.to_string())
|
||||
methods.add_method("peer_addr", |_, this, ()| {
|
||||
Ok(this.0.peer_addr()?.to_string())
|
||||
});
|
||||
|
||||
methods.add_async_method("read", |lua, stream, size: usize| async move {
|
||||
let mut buf = vec![0; size];
|
||||
let n = stream.0.lock().await.read(&mut buf).await?;
|
||||
buf.truncate(n);
|
||||
lua.create_string(&buf)
|
||||
});
|
||||
methods.add_async_function(
|
||||
"read",
|
||||
|lua, (this, size): (AnyUserData, usize)| async move {
|
||||
let mut this = this.borrow_mut::<Self>()?;
|
||||
let mut buf = vec![0; size];
|
||||
let n = this.0.read(&mut buf).await?;
|
||||
buf.truncate(n);
|
||||
lua.create_string(&buf)
|
||||
},
|
||||
);
|
||||
|
||||
methods.add_async_method("write", |_, stream, data: LuaString| async move {
|
||||
let n = stream.0.lock().await.write(&data.as_bytes()).await?;
|
||||
Ok(n)
|
||||
});
|
||||
methods.add_async_function(
|
||||
"write",
|
||||
|_, (this, data): (AnyUserData, LuaString)| async move {
|
||||
let mut this = this.borrow_mut::<Self>()?;
|
||||
let n = this.0.write(&data.as_bytes()).await?;
|
||||
Ok(n)
|
||||
},
|
||||
);
|
||||
|
||||
methods.add_async_method("close", |_, stream, ()| async move {
|
||||
stream.0.lock().await.shutdown().await?;
|
||||
methods.add_async_function("close", |_, this: AnyUserData| async move {
|
||||
let mut this = this.borrow_mut::<Self>()?;
|
||||
this.0.shutdown().await?;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_server(lua: &'static Lua) -> Result<()> {
|
||||
let spawn = lua.create_function(move |_, func: Function| {
|
||||
task::spawn_local(async move { func.call_async::<_, ()>(()).await });
|
||||
Ok(())
|
||||
})?;
|
||||
async fn run_server(lua: Lua, handler: RegistryKey) -> io::Result<()> {
|
||||
let addr: SocketAddr = ([127, 0, 0, 1], 3000).into();
|
||||
let listener = TcpListener::bind(addr).await.expect("cannot bind addr");
|
||||
|
||||
let tcp = LuaTcp;
|
||||
println!("Listening on {}", addr);
|
||||
|
||||
let server = lua
|
||||
let lua = Rc::new(lua);
|
||||
let handler = Rc::new(handler);
|
||||
loop {
|
||||
let (stream, _) = match listener.accept().await {
|
||||
Ok(res) => res,
|
||||
Err(err) if is_transient_error(&err) => continue,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
|
||||
let lua = lua.clone();
|
||||
let handler = handler.clone();
|
||||
task::spawn_local(async move {
|
||||
let handler: Function = lua
|
||||
.registry_value(&handler)
|
||||
.expect("cannot get Lua handler");
|
||||
|
||||
let stream = LuaTcpStream(stream);
|
||||
if let Err(err) = handler.call_async::<_, ()>(stream).await {
|
||||
eprintln!("{}", err);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() {
|
||||
let lua = Lua::new();
|
||||
|
||||
// Create Lua handler function
|
||||
let handler_fn = lua
|
||||
.load(chunk! {
|
||||
local addr = ...
|
||||
local listener = $tcp.bind(addr)
|
||||
print("listening on "..addr)
|
||||
|
||||
local accept_new = true
|
||||
while true do
|
||||
local stream = listener:accept()
|
||||
function(stream)
|
||||
local peer_addr = stream:peer_addr()
|
||||
print("connected from "..peer_addr)
|
||||
|
||||
if not accept_new then
|
||||
return
|
||||
end
|
||||
|
||||
$spawn(function()
|
||||
while true do
|
||||
local data = stream:read(100)
|
||||
data = data:match("^%s*(.-)%s*$") -- trim
|
||||
print("["..peer_addr.."] "..data)
|
||||
if data == "bye" then
|
||||
stream:write("bye bye\n")
|
||||
stream:close()
|
||||
return
|
||||
end
|
||||
if data == "exit" then
|
||||
stream:close()
|
||||
accept_new = false
|
||||
return
|
||||
end
|
||||
stream:write("echo: "..data.."\n")
|
||||
while true do
|
||||
local data = stream:read(100)
|
||||
data = data:match("^%s*(.-)%s*$") // trim
|
||||
print("["..peer_addr.."] "..data)
|
||||
if data == "bye" then
|
||||
stream:write("bye bye\n")
|
||||
stream:close()
|
||||
return
|
||||
end
|
||||
end)
|
||||
stream:write("echo: "..data.."\n")
|
||||
end
|
||||
end
|
||||
})
|
||||
.into_function()?;
|
||||
.eval::<Function>()
|
||||
.expect("cannot create Lua handler");
|
||||
|
||||
// Store it in the Registry
|
||||
let handler = lua
|
||||
.create_registry_value(handler_fn)
|
||||
.expect("cannot store Lua handler");
|
||||
|
||||
task::LocalSet::new()
|
||||
.run_until(server.call_async::<_, ()>("0.0.0.0:1234"))
|
||||
.run_until(run_server(lua, handler))
|
||||
.await
|
||||
.expect("cannot run server")
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let lua = Lua::new().into_static();
|
||||
|
||||
run_server(lua).await.unwrap();
|
||||
|
||||
// Consume the static reference and drop it.
|
||||
// This is safe as long as we don't hold any other references to Lua
|
||||
// or alive resources.
|
||||
unsafe { Lua::from_static(lua) };
|
||||
fn is_transient_error(e: &io::Error) -> bool {
|
||||
e.kind() == io::ErrorKind::ConnectionRefused
|
||||
|| e.kind() == io::ErrorKind::ConnectionAborted
|
||||
|| e.kind() == io::ErrorKind::ConnectionReset
|
||||
}
|
||||
|
||||
@@ -3,3 +3,9 @@ rustflags = [
|
||||
"-C", "link-arg=-undefined",
|
||||
"-C", "link-arg=dynamic_lookup",
|
||||
]
|
||||
|
||||
[target.aarch64-apple-darwin]
|
||||
rustflags = [
|
||||
"-C", "link-arg=-undefined",
|
||||
"-C", "link-arg=dynamic_lookup",
|
||||
]
|
||||
|
||||
@@ -7,13 +7,14 @@ edition = "2018"
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[workspace]
|
||||
|
||||
[features]
|
||||
lua54 = ["mlua/lua54"]
|
||||
lua53 = ["mlua/lua53"]
|
||||
lua52 = ["mlua/lua52"]
|
||||
lua51 = ["mlua/lua51"]
|
||||
luajit = ["mlua/luajit"]
|
||||
vendored = ["mlua/vendored"]
|
||||
|
||||
[dependencies]
|
||||
mlua = { path = "../..", features = ["module"] }
|
||||
|
||||
@@ -8,32 +8,10 @@ fn used_memory(lua: &Lua, _: ()) -> LuaResult<usize> {
|
||||
Ok(lua.used_memory())
|
||||
}
|
||||
|
||||
fn check_userdata(_: &Lua, ud: MyUserData) -> LuaResult<i32> {
|
||||
Ok(ud.0)
|
||||
}
|
||||
|
||||
#[mlua::lua_module]
|
||||
fn rust_module(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let exports = lua.create_table()?;
|
||||
exports.set("sum", lua.create_function(sum)?)?;
|
||||
exports.set("used_memory", lua.create_function(used_memory)?)?;
|
||||
exports.set("check_userdata", lua.create_function(check_userdata)?)?;
|
||||
Ok(exports)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct MyUserData(i32);
|
||||
|
||||
impl LuaUserData for MyUserData {}
|
||||
|
||||
#[mlua::lua_module]
|
||||
fn rust_module_second(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let exports = lua.create_table()?;
|
||||
exports.set("userdata", lua.create_userdata(MyUserData(123))?)?;
|
||||
Ok(exports)
|
||||
}
|
||||
|
||||
#[mlua::lua_module]
|
||||
fn rust_module_error(_: &Lua) -> LuaResult<LuaTable> {
|
||||
Err("custom module error".to_lua_err())
|
||||
}
|
||||
|
||||
+1
-1
@@ -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>>> {
|
||||
|
||||
@@ -175,8 +175,7 @@ impl Tokens {
|
||||
pub(crate) fn retokenize(tt: TokenStream) -> Tokens {
|
||||
Tokens(
|
||||
tt.into_iter()
|
||||
.map(Tokens::from)
|
||||
.flatten()
|
||||
.flat_map(Tokens::from)
|
||||
.peekable()
|
||||
.batching(|iter| {
|
||||
// Find variable tokens
|
||||
@@ -217,7 +216,7 @@ impl From<TokenTree> for Tokens {
|
||||
|
||||
vec![Token::new_delim(b, tt.clone(), true)]
|
||||
.into_iter()
|
||||
.chain(g.stream().into_iter().map(Tokens::from).flatten())
|
||||
.chain(g.stream().into_iter().flat_map(Tokens::from))
|
||||
.chain(vec![Token::new_delim(e, tt, false)])
|
||||
.collect()
|
||||
}
|
||||
|
||||
+510
@@ -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
|
||||
}
|
||||
}
|
||||
+134
-67
@@ -2,6 +2,7 @@
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::hash::{BuildHasher, Hash};
|
||||
use std::string::String as StdString;
|
||||
@@ -20,24 +21,28 @@ use crate::userdata::{AnyUserData, UserData};
|
||||
use crate::value::{FromLua, Nil, ToLua, Value};
|
||||
|
||||
impl<'lua> ToLua<'lua> for Value<'lua> {
|
||||
#[inline]
|
||||
fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for Value<'lua> {
|
||||
#[inline]
|
||||
fn from_lua(lua_value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||
Ok(lua_value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for String<'lua> {
|
||||
#[inline]
|
||||
fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::String(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for String<'lua> {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<String<'lua>> {
|
||||
let ty = value.type_name();
|
||||
lua.coerce_string(value)?
|
||||
@@ -50,12 +55,14 @@ impl<'lua> FromLua<'lua> for String<'lua> {
|
||||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for Table<'lua> {
|
||||
#[inline]
|
||||
fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Table(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for Table<'lua> {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Table<'lua>> {
|
||||
match value {
|
||||
Value::Table(table) => Ok(table),
|
||||
@@ -69,12 +76,14 @@ impl<'lua> FromLua<'lua> for Table<'lua> {
|
||||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for Function<'lua> {
|
||||
#[inline]
|
||||
fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Function(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for Function<'lua> {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Function<'lua>> {
|
||||
match value {
|
||||
Value::Function(table) => Ok(table),
|
||||
@@ -88,12 +97,14 @@ impl<'lua> FromLua<'lua> for Function<'lua> {
|
||||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for Thread<'lua> {
|
||||
#[inline]
|
||||
fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Thread(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for Thread<'lua> {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Thread<'lua>> {
|
||||
match value {
|
||||
Value::Thread(t) => Ok(t),
|
||||
@@ -107,12 +118,14 @@ impl<'lua> FromLua<'lua> for Thread<'lua> {
|
||||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for AnyUserData<'lua> {
|
||||
#[inline]
|
||||
fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::UserData(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for AnyUserData<'lua> {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<AnyUserData<'lua>> {
|
||||
match value {
|
||||
Value::UserData(ud) => Ok(ud),
|
||||
@@ -126,12 +139,14 @@ impl<'lua> FromLua<'lua> for AnyUserData<'lua> {
|
||||
}
|
||||
|
||||
impl<'lua, T: 'static + MaybeSend + UserData> ToLua<'lua> for T {
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::UserData(lua.create_userdata(self)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: 'static + UserData + Clone> FromLua<'lua> for T {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<T> {
|
||||
match value {
|
||||
Value::UserData(ud) => Ok(ud.borrow::<T>()?.clone()),
|
||||
@@ -145,12 +160,14 @@ impl<'lua, T: 'static + UserData + Clone> FromLua<'lua> for T {
|
||||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for Error {
|
||||
#[inline]
|
||||
fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Error(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for Error {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Error> {
|
||||
match value {
|
||||
Value::Error(err) => Ok(err),
|
||||
@@ -164,12 +181,14 @@ impl<'lua> FromLua<'lua> for Error {
|
||||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for bool {
|
||||
#[inline]
|
||||
fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Boolean(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for bool {
|
||||
#[inline]
|
||||
fn from_lua(v: Value<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||
match v {
|
||||
Value::Nil => Ok(false),
|
||||
@@ -180,12 +199,14 @@ impl<'lua> FromLua<'lua> for bool {
|
||||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for LightUserData {
|
||||
#[inline]
|
||||
fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::LightUserData(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for LightUserData {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||
match value {
|
||||
Value::LightUserData(ud) => Ok(ud),
|
||||
@@ -199,12 +220,14 @@ impl<'lua> FromLua<'lua> for LightUserData {
|
||||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for StdString {
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::String(lua.create_string(&self)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for StdString {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
let ty = value.type_name();
|
||||
Ok(lua
|
||||
@@ -220,24 +243,28 @@ impl<'lua> FromLua<'lua> for StdString {
|
||||
}
|
||||
|
||||
impl<'lua> ToLua<'lua> for &str {
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::String(lua.create_string(self)?))
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@@ -254,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
|
||||
@@ -282,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(
|
||||
@@ -316,44 +349,51 @@ 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>> {
|
||||
if let Some(i) = cast(self) {
|
||||
Ok(Value::Integer(i))
|
||||
} else {
|
||||
cast(self)
|
||||
.ok_or_else(|| Error::ToLuaConversionError {
|
||||
from: stringify!($x),
|
||||
to: "number",
|
||||
message: Some("out of range".to_owned()),
|
||||
})
|
||||
.map(Value::Number)
|
||||
}
|
||||
cast(self)
|
||||
.map(Value::Integer)
|
||||
.or_else(|| cast(self).map(Value::Number))
|
||||
// This is impossible error because conversion to Number never fails
|
||||
.ok_or_else(|| Error::ToLuaConversionError {
|
||||
from: stringify!($x),
|
||||
to: "number",
|
||||
message: Some("out of range".to_owned()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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 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,
|
||||
@@ -381,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 {
|
||||
@@ -393,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)?
|
||||
@@ -420,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())?,
|
||||
@@ -427,75 +470,89 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! lua_convert_array {
|
||||
($($N:literal)+) => {
|
||||
$(
|
||||
impl<'lua, T> ToLua<'lua> for [T; $N]
|
||||
where
|
||||
T: Clone + ToLua<'lua>,
|
||||
{
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
(&self).to_lua(lua)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T> ToLua<'lua> for &[T; $N]
|
||||
where
|
||||
T: Clone + ToLua<'lua>,
|
||||
{
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
Ok(Value::Table(
|
||||
lua.create_sequence_from(self.iter().cloned())?,
|
||||
))
|
||||
}
|
||||
}
|
||||
)+
|
||||
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)?))
|
||||
}
|
||||
}
|
||||
|
||||
lua_convert_array! {
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
10 11 12 13 14 15 16 17 18 19
|
||||
20 21 22 23 24 25 26 27 28 29
|
||||
30 31 32
|
||||
impl<'lua, T, const N: usize> FromLua<'lua> for [T; N]
|
||||
where
|
||||
T: FromLua<'lua>,
|
||||
{
|
||||
#[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()),
|
||||
})
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -503,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)?))
|
||||
}
|
||||
@@ -511,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()
|
||||
@@ -525,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()
|
||||
@@ -545,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)),
|
||||
@@ -553,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(),
|
||||
@@ -570,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)),
|
||||
@@ -578,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(),
|
||||
@@ -595,6 +660,7 @@ impl<'lua, T: Ord + FromLua<'lua>> FromLua<'lua> for BTreeSet<T> {
|
||||
}
|
||||
|
||||
impl<'lua, T: ToLua<'lua>> ToLua<'lua> for Option<T> {
|
||||
#[inline]
|
||||
fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
|
||||
match self {
|
||||
Some(val) => val.to_lua(lua),
|
||||
@@ -604,6 +670,7 @@ impl<'lua, T: ToLua<'lua>> ToLua<'lua> for Option<T> {
|
||||
}
|
||||
|
||||
impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Option<T> {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
match value {
|
||||
Nil => Ok(None),
|
||||
|
||||
+43
-16
@@ -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),
|
||||
@@ -96,8 +97,8 @@ pub enum Error {
|
||||
/// [`Thread::status`] can be used to check if the coroutine can be resumed without causing this
|
||||
/// error.
|
||||
///
|
||||
/// [`Thread::resume`]: struct.Thread.html#method.resume
|
||||
/// [`Thread::status`]: struct.Thread.html#method.status
|
||||
/// [`Thread::resume`]: crate::Thread::resume
|
||||
/// [`Thread::status`]: crate::Thread::status
|
||||
CoroutineInactive,
|
||||
/// An [`AnyUserData`] is not the expected type in a borrow.
|
||||
///
|
||||
@@ -105,15 +106,15 @@ pub enum Error {
|
||||
/// metamethods for binary operators. Refer to the documentation of [`UserDataMethods`] for
|
||||
/// details.
|
||||
///
|
||||
/// [`AnyUserData`]: struct.AnyUserData.html
|
||||
/// [`UserDataMethods`]: trait.UserDataMethods.html
|
||||
/// [`AnyUserData`]: crate::AnyUserData
|
||||
/// [`UserDataMethods`]: crate::UserDataMethods
|
||||
UserDataTypeMismatch,
|
||||
/// An [`AnyUserData`] borrow failed because it has been destructed.
|
||||
///
|
||||
/// This error can happen either due to to being destructed in a previous __gc, or due to being
|
||||
/// destructed from exiting a `Lua::scope` call.
|
||||
///
|
||||
/// [`AnyUserData`]: struct.AnyUserData.html
|
||||
/// [`AnyUserData`]: crate::AnyUserData
|
||||
UserDataDestructed,
|
||||
/// An [`AnyUserData`] immutable borrow failed because it is already borrowed mutably.
|
||||
///
|
||||
@@ -121,8 +122,8 @@ pub enum Error {
|
||||
/// tries to call a method on the same [`UserData`] type. Consider restructuring your API to
|
||||
/// prevent these errors.
|
||||
///
|
||||
/// [`AnyUserData`]: struct.AnyUserData.html
|
||||
/// [`UserData`]: trait.UserData.html
|
||||
/// [`AnyUserData`]: crate::AnyUserData
|
||||
/// [`UserData`]: crate::UserData
|
||||
UserDataBorrowError,
|
||||
/// An [`AnyUserData`] mutable borrow failed because it is already borrowed.
|
||||
///
|
||||
@@ -130,22 +131,24 @@ pub enum Error {
|
||||
/// tries to call a method on the same [`UserData`] type. Consider restructuring your API to
|
||||
/// prevent these errors.
|
||||
///
|
||||
/// [`AnyUserData`]: struct.AnyUserData.html
|
||||
/// [`UserData`]: trait.UserData.html
|
||||
/// [`AnyUserData`]: crate::AnyUserData
|
||||
/// [`UserData`]: crate::UserData
|
||||
UserDataBorrowMutError,
|
||||
/// A [`MetaMethod`] operation is restricted (typically for `__gc` or `__metatable`).
|
||||
///
|
||||
/// [`MetaMethod`]: enum.MetaMethod.html
|
||||
/// [`MetaMethod`]: crate::MetaMethod
|
||||
MetaMethodRestricted(StdString),
|
||||
/// A [`MetaMethod`] (eg. `__index` or `__newindex`) has invalid type.
|
||||
///
|
||||
/// [`MetaMethod`]: enum.MetaMethod.html
|
||||
/// [`MetaMethod`]: crate::MetaMethod
|
||||
MetaMethodTypeError {
|
||||
method: StdString,
|
||||
type_name: &'static str,
|
||||
message: Option<StdString>,
|
||||
},
|
||||
/// A `RegistryKey` produced from a different Lua state was used.
|
||||
/// A [`RegistryKey`] produced from a different Lua state was used.
|
||||
///
|
||||
/// [`RegistryKey`]: crate::RegistryKey
|
||||
MismatchedRegistryKey,
|
||||
/// A Rust callback returned `Err`, raising the contained `Error` as a Lua error.
|
||||
CallbackError {
|
||||
@@ -245,8 +248,28 @@ impl fmt::Display for Error {
|
||||
Error::MismatchedRegistryKey => {
|
||||
write!(fmt, "RegistryKey used from different Lua state")
|
||||
}
|
||||
Error::CallbackError { ref traceback, .. } => {
|
||||
write!(fmt, "callback error\n{}", traceback)
|
||||
Error::CallbackError { ref cause, ref traceback } => {
|
||||
writeln!(fmt, "callback error")?;
|
||||
// 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 {
|
||||
cause = cause2;
|
||||
full_traceback = Some(traceback2);
|
||||
}
|
||||
if let Some(full_traceback) = full_traceback {
|
||||
let traceback = traceback.trim_start_matches("stack traceback:");
|
||||
let traceback = traceback.trim_start().trim_end();
|
||||
// Try to find local traceback within the full traceback
|
||||
if let Some(pos) = full_traceback.find(traceback) {
|
||||
write!(fmt, "{}", &full_traceback[..pos])?;
|
||||
writeln!(fmt, ">{}", &full_traceback[pos..].trim_end())?;
|
||||
} else {
|
||||
writeln!(fmt, "{}", full_traceback.trim_end())?;
|
||||
}
|
||||
} else {
|
||||
writeln!(fmt, "{}", traceback.trim_end())?;
|
||||
}
|
||||
write!(fmt, "caused by: {}", cause)
|
||||
}
|
||||
Error::PreviouslyResumedPanic => {
|
||||
write!(fmt, "previously resumed panic returned again")
|
||||
@@ -267,7 +290,11 @@ impl fmt::Display for Error {
|
||||
impl StdError for Error {
|
||||
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
||||
match *self {
|
||||
Error::CallbackError { ref cause, .. } => Some(cause.as_ref()),
|
||||
// An error type with a source error should either return that error via source or
|
||||
// include that source's error message in its own Display output, but never both.
|
||||
// https://blog.rust-lang.org/inside-rust/2021/07/01/What-the-error-handling-project-group-is-working-towards.html
|
||||
// Given that we include source to fmt::Display implementation for `CallbackError`, this call returns nothing.
|
||||
Error::CallbackError { .. } => None,
|
||||
Error::ExternalError(ref err) => err.source(),
|
||||
_ => None,
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
-830
@@ -1,830 +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`.
|
||||
|
||||
#[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 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.
|
||||
pub type lua_State = c_void;
|
||||
|
||||
// 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;
|
||||
|
||||
#[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: 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.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);
|
||||
}
|
||||
@@ -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
|
||||
//
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
//
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
//
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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
|
||||
//
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
//
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
+50
-262
@@ -1,262 +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::*;
|
||||
|
||||
// constants from lauxlib.h
|
||||
pub use self::lauxlib::{LUA_ERRFILE, LUA_NOREF, LUA_REFNIL};
|
||||
#[cfg(feature = "luau")]
|
||||
pub use luau::*;
|
||||
|
||||
// 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",
|
||||
@@ -268,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(
|
||||
@@ -277,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 _);
|
||||
@@ -290,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;
|
||||
|
||||
+166
-31
@@ -1,3 +1,4 @@
|
||||
use std::mem;
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
@@ -5,8 +6,10 @@ 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, protect_lua, StackGuard};
|
||||
use crate::value::{FromLuaMulti, MultiValue, ToLuaMulti};
|
||||
use crate::util::{
|
||||
assert_stack, check_stack, error_traceback, pop_error, ptr_to_cstr_bytes, StackGuard,
|
||||
};
|
||||
use crate::value::{FromLuaMulti, ToLuaMulti};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
use {futures_core::future::LocalBoxFuture, futures_util::future};
|
||||
@@ -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.
|
||||
///
|
||||
@@ -59,7 +85,7 @@ impl<'lua> Function<'lua> {
|
||||
pub fn call<A: ToLuaMulti<'lua>, R: FromLuaMulti<'lua>>(&self, args: A) -> Result<R> {
|
||||
let lua = self.0.lua;
|
||||
|
||||
let args = args.to_lua_multi(lua)?;
|
||||
let mut args = args.to_lua_multi(lua)?;
|
||||
let nargs = args.len() as c_int;
|
||||
|
||||
let results = unsafe {
|
||||
@@ -69,7 +95,7 @@ impl<'lua> Function<'lua> {
|
||||
ffi::lua_pushcfunction(lua.state, error_traceback);
|
||||
let stack_start = ffi::lua_gettop(lua.state);
|
||||
lua.push_ref(&self.0);
|
||||
for arg in args {
|
||||
for arg in args.drain_all() {
|
||||
lua.push_value(arg)?;
|
||||
}
|
||||
let ret = ffi::lua_pcall(lua.state, nargs, ffi::LUA_MULTRET, stack_start);
|
||||
@@ -77,7 +103,7 @@ impl<'lua> Function<'lua> {
|
||||
return Err(pop_error(lua.state, ret));
|
||||
}
|
||||
let nresults = ffi::lua_gettop(lua.state) - stack_start;
|
||||
let mut results = MultiValue::new();
|
||||
let mut results = args; // Reuse MultiValue container
|
||||
assert_stack(lua.state, 2);
|
||||
for _ in 0..nresults {
|
||||
results.push_front(lua.pop_value());
|
||||
@@ -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`].
|
||||
@@ -116,7 +142,7 @@ impl<'lua> Function<'lua> {
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`AsyncThread`]: struct.AsyncThread.html
|
||||
/// [`AsyncThread`]: crate::AsyncThread
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
pub fn call_async<'fut, A, R>(&self, args: A) -> LocalBoxFuture<'fut, Result<R>>
|
||||
@@ -126,8 +152,12 @@ impl<'lua> Function<'lua> {
|
||||
R: FromLuaMulti<'lua> + 'fut,
|
||||
{
|
||||
let lua = self.0.lua;
|
||||
match lua.create_thread(self.clone()) {
|
||||
Ok(t) => Box::pin(t.into_async(args)),
|
||||
match lua.create_recycled_thread(self.clone()) {
|
||||
Ok(t) => {
|
||||
let mut t = t.into_async(args);
|
||||
t.set_recyclable(true);
|
||||
Box::pin(t)
|
||||
}
|
||||
Err(e) => Box::pin(future::err(e)),
|
||||
}
|
||||
}
|
||||
@@ -160,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;
|
||||
@@ -185,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, |state| {
|
||||
ffi::lua_pushcclosure(state, bind_call_impl, nargs + 2);
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,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,
|
||||
@@ -231,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> {
|
||||
|
||||
+139
-70
@@ -1,75 +1,115 @@
|
||||
use std::ffi::CStr;
|
||||
use std::marker::PhantomData;
|
||||
use std::cell::UnsafeCell;
|
||||
#[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, lua_State};
|
||||
use crate::ffi::{self, lua_Debug};
|
||||
use crate::lua::Lua;
|
||||
use crate::util::callback_error;
|
||||
use crate::util::ptr_to_cstr_bytes;
|
||||
|
||||
/// Contains information about currently executing Lua code.
|
||||
///
|
||||
/// The `Debug` structure is provided as a parameter to the hook function set with
|
||||
/// [`Lua::set_hook`]. You may call the methods on this structure to retrieve information about the
|
||||
/// Lua code executing at the time that the hook function was called. Further information can be
|
||||
/// found in the [Lua 5.3 documentation][lua_doc].
|
||||
/// found in the Lua [documentation][lua_doc].
|
||||
///
|
||||
/// [lua_doc]: https://www.lua.org/manual/5.3/manual.html#lua_Debug
|
||||
/// [`Lua::set_hook`]: struct.Lua.html#method.set_hook
|
||||
#[derive(Clone)]
|
||||
pub struct Debug<'a> {
|
||||
ar: *mut lua_Debug,
|
||||
state: *mut lua_State,
|
||||
_phantom: PhantomData<&'a ()>,
|
||||
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#lua_Debug
|
||||
/// [`Lua::set_hook`]: crate::Lua::set_hook
|
||||
pub struct Debug<'lua> {
|
||||
lua: &'lua Lua,
|
||||
ar: ActivationRecord,
|
||||
#[cfg(feature = "luau")]
|
||||
level: c_int,
|
||||
}
|
||||
|
||||
impl<'a> Debug<'a> {
|
||||
impl<'lua> Debug<'lua> {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
pub(crate) fn new(lua: &'lua Lua, ar: *mut lua_Debug) -> Self {
|
||||
Debug {
|
||||
lua,
|
||||
ar: ActivationRecord::Borrowed(ar),
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the specific event that triggered the hook.
|
||||
///
|
||||
/// For [Lua 5.1] `DebugEvent::TailCall` is used for return events to indicate a return
|
||||
/// 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).event {
|
||||
match (*self.ar.get()).event {
|
||||
ffi::LUA_HOOKCALL => DebugEvent::Call,
|
||||
ffi::LUA_HOOKRET => DebugEvent::Ret,
|
||||
ffi::LUA_HOOKTAILCALL => DebugEvent::TailCall,
|
||||
ffi::LUA_HOOKLINE => DebugEvent::Line,
|
||||
ffi::LUA_HOOKCOUNT => DebugEvent::Count,
|
||||
event => mlua_panic!("Unknown Lua event code: {}", event),
|
||||
event => DebugEvent::Unknown(event),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Corresponds to the `n` what mask.
|
||||
pub fn names(&self) -> DebugNames<'a> {
|
||||
pub fn names(&self) -> DebugNames<'lua> {
|
||||
unsafe {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.state, cstr!("n"), self.ar) != 0,
|
||||
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).name),
|
||||
name_what: ptr_to_str((*self.ar).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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Corresponds to the `S` what mask.
|
||||
pub fn source(&self) -> DebugSource<'a> {
|
||||
pub fn source(&self) -> DebugSource<'lua> {
|
||||
unsafe {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.state, cstr!("S"), self.ar) != 0,
|
||||
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).source),
|
||||
short_src: ptr_to_str((*self.ar).short_src.as_ptr()),
|
||||
line_defined: (*self.ar).linedefined as i32,
|
||||
last_line_defined: (*self.ar).lastlinedefined as i32,
|
||||
what: ptr_to_str((*self.ar).what),
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,40 +117,81 @@ impl<'a> Debug<'a> {
|
||||
/// 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.state, cstr!("l"), self.ar) != 0,
|
||||
ffi::lua_getinfo(self.lua.state, cstr!("l"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `l`"
|
||||
);
|
||||
(*self.ar).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!(
|
||||
ffi::lua_getinfo(self.state, cstr!("t"), self.ar) != 0,
|
||||
ffi::lua_getinfo(self.lua.state, cstr!("t"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `t`"
|
||||
);
|
||||
(*self.ar).currentline != 0
|
||||
(*self.ar.get()).currentline != 0
|
||||
}
|
||||
}
|
||||
|
||||
/// Corresponds to the `u` what mask.
|
||||
pub fn stack(&self) -> DebugStack {
|
||||
unsafe {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
mlua_assert!(
|
||||
ffi::lua_getinfo(self.state, cstr!("u"), self.ar) != 0,
|
||||
ffi::lua_getinfo(self.lua.state, cstr!("u"), self.ar.get()) != 0,
|
||||
"lua_getinfo failed with `u`"
|
||||
);
|
||||
DebugStack {
|
||||
num_ups: (*self.ar).nups as i32,
|
||||
#[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).nparams as i32,
|
||||
num_params: (*self.ar.get()).nparams as i32,
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
is_vararg: (*self.ar).isvararg != 0,
|
||||
}
|
||||
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>),
|
||||
}
|
||||
|
||||
impl ActivationRecord {
|
||||
#[inline]
|
||||
fn get(&self) -> *mut lua_Debug {
|
||||
match self {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
ActivationRecord::Borrowed(x) => *x,
|
||||
ActivationRecord::Owned(x) => x.get(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,6 +204,7 @@ pub enum DebugEvent {
|
||||
TailCall,
|
||||
Line,
|
||||
Count,
|
||||
Unknown(c_int),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -136,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]>,
|
||||
}
|
||||
@@ -143,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", doc))]
|
||||
/// 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", doc))]
|
||||
/// 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.
|
||||
@@ -169,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.
|
||||
///
|
||||
@@ -235,6 +331,7 @@ impl HookTriggers {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
impl BitOr for HookTriggers {
|
||||
type Output = Self;
|
||||
|
||||
@@ -249,37 +346,9 @@ impl BitOr for HookTriggers {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "luau"))]
|
||||
impl BitOrAssign for HookTriggers {
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
*self = *self | rhs;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe extern "C" fn hook_proc(state: *mut lua_State, ar: *mut lua_Debug) {
|
||||
callback_error(state, |_| {
|
||||
let debug = Debug {
|
||||
ar,
|
||||
state,
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
|
||||
let lua = mlua_expect!(Lua::make_from_ptr(state), "cannot make Lua instance");
|
||||
let hook_cb = mlua_expect!(lua.hook_callback(), "no hook callback set in hook_proc");
|
||||
|
||||
#[allow(clippy::match_wild_err_arm)]
|
||||
match hook_cb.try_borrow_mut() {
|
||||
Ok(mut b) => (&mut *b)(&lua, debug),
|
||||
Err(_) => mlua_panic!("Lua should not allow hooks to be called within another hook"),
|
||||
}?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn ptr_to_str<'a>(input: *const c_char) -> Option<&'a [u8]> {
|
||||
if input.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(CStr::from_ptr(input).to_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
+57
-27
@@ -50,29 +50,29 @@
|
||||
//! to [`Function`]s and [`UserData`].
|
||||
//!
|
||||
//! [Lua programming language]: https://www.lua.org/
|
||||
//! [`Lua`]: struct.Lua.html
|
||||
//! [executing]: struct.Chunk.html#method.exec
|
||||
//! [evaluating]: struct.Chunk.html#method.eval
|
||||
//! [globals]: struct.Lua.html#method.globals
|
||||
//! [`ToLua`]: trait.ToLua.html
|
||||
//! [`FromLua`]: trait.FromLua.html
|
||||
//! [`ToLuaMulti`]: trait.ToLuaMulti.html
|
||||
//! [`FromLuaMulti`]: trait.FromLuaMulti.html
|
||||
//! [`Function`]: struct.Function.html
|
||||
//! [`UserData`]: trait.UserData.html
|
||||
//! [`UserDataFields`]: trait.UserDataFields.html
|
||||
//! [`UserDataMethods`]: trait.UserDataMethods.html
|
||||
//! [`LuaSerdeExt`]: serde/trait.LuaSerdeExt.html
|
||||
//! [`Value`]: enum.Value.html
|
||||
//! [`create_async_function`]: struct.Lua.html#method.create_async_function
|
||||
//! [`call_async`]: struct.Function.html#method.call_async
|
||||
//! [`AsyncThread`]: struct.AsyncThread.html
|
||||
//! [`Future`]: ../futures_core/future/trait.Future.html
|
||||
//! [`Lua`]: crate::Lua
|
||||
//! [executing]: crate::Chunk::exec
|
||||
//! [evaluating]: crate::Chunk::eval
|
||||
//! [globals]: crate::Lua::globals
|
||||
//! [`ToLua`]: crate::ToLua
|
||||
//! [`FromLua`]: crate::FromLua
|
||||
//! [`ToLuaMulti`]: crate::ToLuaMulti
|
||||
//! [`FromLuaMulti`]: crate::FromLuaMulti
|
||||
//! [`Function`]: crate::Function
|
||||
//! [`UserData`]: crate::UserData
|
||||
//! [`UserDataFields`]: crate::UserDataFields
|
||||
//! [`UserDataMethods`]: crate::UserDataMethods
|
||||
//! [`LuaSerdeExt`]: crate::LuaSerdeExt
|
||||
//! [`Value`]: crate::Value
|
||||
//! [`create_async_function`]: crate::Lua::create_async_function
|
||||
//! [`call_async`]: crate::Function::call_async
|
||||
//! [`AsyncThread`]: crate::AsyncThread
|
||||
//! [`Future`]: std::future::Future
|
||||
//! [`serde::Serialize`]: https://docs.serde.rs/serde/ser/trait.Serialize.html
|
||||
//! [`serde::Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html
|
||||
|
||||
// mlua types in rustdoc of other crates get linked to here.
|
||||
#![doc(html_root_url = "https://docs.rs/mlua/0.6.3")]
|
||||
#![doc(html_root_url = "https://docs.rs/mlua/0.8.4")]
|
||||
// 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,15 +98,19 @@ mod table;
|
||||
mod thread;
|
||||
mod types;
|
||||
mod userdata;
|
||||
mod userdata_impl;
|
||||
mod util;
|
||||
mod value;
|
||||
|
||||
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;
|
||||
@@ -116,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;
|
||||
|
||||
@@ -125,7 +139,6 @@ pub use crate::serde::{
|
||||
de::Options as DeserializeOptions, ser::Options as SerializeOptions, LuaSerdeExt,
|
||||
};
|
||||
|
||||
pub mod prelude;
|
||||
#[cfg(feature = "serialize")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
|
||||
pub mod serde;
|
||||
@@ -184,13 +197,30 @@ extern crate mlua_derive;
|
||||
///
|
||||
/// Everything else should work.
|
||||
///
|
||||
/// [`AsChunk`]: trait.AsChunk.html
|
||||
/// [`UserData`]: trait.UserData.html
|
||||
/// [`ToLua`]: trait.ToLua.html
|
||||
/// [`AsChunk`]: crate::AsChunk
|
||||
/// [`UserData`]: crate::UserData
|
||||
/// [`ToLua`]: crate::ToLua
|
||||
#[cfg(any(feature = "macros"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
|
||||
pub use mlua_derive::chunk;
|
||||
|
||||
#[cfg(any(feature = "module"))]
|
||||
/// Registers Lua module entrypoint.
|
||||
///
|
||||
/// You can register multiple entrypoints as required.
|
||||
///
|
||||
/// ```
|
||||
/// use mlua::{Lua, Result, Table};
|
||||
///
|
||||
/// #[mlua::lua_module]
|
||||
/// fn my_module(lua: &Lua) -> Result<Table> {
|
||||
/// let exports = lua.create_table()?;
|
||||
/// exports.set("hello", "world")?;
|
||||
/// Ok(exports)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Internally in the code above the compiler defines C function `luaopen_my_module`.
|
||||
///
|
||||
#[cfg(any(feature = "module", docsrs))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "module")))]
|
||||
pub use mlua_derive::lua_module;
|
||||
|
||||
+1301
-1124
File diff suppressed because it is too large
Load Diff
+124
@@ -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
|
||||
}
|
||||
@@ -94,3 +94,18 @@ macro_rules! require_module_feature {
|
||||
compile_error!("Feature `module` must be enabled in the `mlua` crate");
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! protect_lua {
|
||||
($state:expr, $nargs:expr, $nresults:expr, $f:expr) => {
|
||||
crate::util::protect_lua_closure($state, $nargs, $nresults, $f)
|
||||
};
|
||||
|
||||
($state:expr, $nargs:expr, $nresults:expr, fn($state_inner:ident) $code:expr) => {{
|
||||
unsafe extern "C" fn do_call($state_inner: *mut ffi::lua_State) -> ::std::os::raw::c_int {
|
||||
$code;
|
||||
$nresults
|
||||
}
|
||||
|
||||
crate::util::protect_lua_call($state, $nargs, do_call)
|
||||
}};
|
||||
}
|
||||
|
||||
+32
-16
@@ -11,9 +11,9 @@ 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();
|
||||
|
||||
let mut result = MultiValue::new_or_cached(lua);
|
||||
match self {
|
||||
Ok(v) => result.push_front(v.to_lua(lua)?),
|
||||
Err(e) => {
|
||||
@@ -21,32 +21,37 @@ impl<'lua, T: ToLua<'lua>, E: ToLua<'lua>> ToLuaMulti<'lua> for StdResult<T, E>
|
||||
result.push_front(Nil);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
let mut v = MultiValue::new_or_cached(lua);
|
||||
v.push_front(self.to_lua(lua)?);
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for T {
|
||||
#[inline]
|
||||
fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
T::from_lua(values.pop_front().unwrap_or(Nil), lua)
|
||||
let res = T::from_lua(values.pop_front().unwrap_or(Nil), lua);
|
||||
lua.cache_multivalue(values);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -76,14 +81,14 @@ impl<'lua> FromLuaMulti<'lua> for MultiValue<'lua> {
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`FromLua`]: trait.FromLua.html
|
||||
/// [`MultiValue`]: struct.MultiValue.html
|
||||
/// [`FromLua`]: crate::FromLua
|
||||
/// [`MultiValue`]: crate::MultiValue
|
||||
#[derive(Debug, Clone)]
|
||||
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,31 +129,40 @@ 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>> {
|
||||
self.0.into_iter().map(|e| e.to_lua(lua)).collect()
|
||||
let mut values = MultiValue::new_or_cached(lua);
|
||||
values.refill(self.0.into_iter().map(|e| e.to_lua(lua)))?;
|
||||
Ok(values)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for Variadic<T> {
|
||||
fn from_lua_multi(values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
values
|
||||
.into_iter()
|
||||
#[inline]
|
||||
fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
let res = values
|
||||
.drain_all()
|
||||
.map(|e| T::from_lua(e, lua))
|
||||
.collect::<Result<Vec<T>>>()
|
||||
.map(Variadic)
|
||||
.map(Variadic);
|
||||
lua.cache_multivalue(values);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_tuple {
|
||||
() => (
|
||||
impl<'lua> ToLuaMulti<'lua> for () {
|
||||
fn to_lua_multi(self, _: &'lua Lua) -> Result<MultiValue<'lua>> {
|
||||
Ok(MultiValue::new())
|
||||
#[inline]
|
||||
fn to_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
|
||||
Ok(MultiValue::new_or_cached(lua))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLuaMulti<'lua> for () {
|
||||
fn from_lua_multi(_: MultiValue<'lua>, _: &'lua Lua) -> Result<Self> {
|
||||
#[inline]
|
||||
fn from_lua_multi(values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
lua.cache_multivalue(values);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -161,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;
|
||||
|
||||
@@ -176,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)?;
|
||||
|
||||
+20
-9
@@ -1,23 +1,34 @@
|
||||
//! Re-exports most types with an extra `Lua*` prefix to prevent name clashes.
|
||||
|
||||
#[doc(no_inline)]
|
||||
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, 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,
|
||||
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;
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
#[doc(inline)]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::{
|
||||
DeserializeOptions as LuaDeserializeOptions, LuaSerdeExt,
|
||||
SerializeOptions as LuaSerializeOptions,
|
||||
|
||||
+134
-57
@@ -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")]
|
||||
@@ -18,11 +17,14 @@ use crate::userdata::{
|
||||
AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
|
||||
};
|
||||
use crate::util::{
|
||||
assert_stack, check_stack, get_userdata, init_userdata_metatable, protect_lua, push_table,
|
||||
rawset_field, take_userdata, StackGuard,
|
||||
assert_stack, check_stack, get_userdata, init_userdata_metatable, push_table, rawset_field,
|
||||
take_userdata, StackGuard,
|
||||
};
|
||||
use crate::value::{FromLua, FromLuaMulti, MultiValue, ToLua, ToLuaMulti, Value};
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
use crate::userdata::USER_VALUE_MAXSLOT;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
use {
|
||||
crate::types::{AsyncCallback, AsyncCallbackUpvalue, AsyncPollUpvalue},
|
||||
@@ -35,7 +37,7 @@ use {
|
||||
///
|
||||
/// See [`Lua::scope`] for more details.
|
||||
///
|
||||
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
||||
/// [`Lua::scope`]: crate::Lua.html::scope
|
||||
pub struct Scope<'lua, 'scope> {
|
||||
lua: &'lua Lua,
|
||||
destructors: RefCell<Vec<(LuaRef<'lua>, DestructorCallback<'lua>)>>,
|
||||
@@ -58,8 +60,8 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||
/// This is a version of [`Lua::create_function`] that creates a callback which expires on
|
||||
/// scope drop. See [`Lua::scope`] for more details.
|
||||
///
|
||||
/// [`Lua::create_function`]: struct.Lua.html#method.create_function
|
||||
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
||||
/// [`Lua::create_function`]: crate::Lua::create_function
|
||||
/// [`Lua::scope`]: crate::Lua::scope
|
||||
pub fn create_function<'callback, A, R, F>(&'callback self, func: F) -> Result<Function<'lua>>
|
||||
where
|
||||
A: FromLuaMulti<'callback>,
|
||||
@@ -87,8 +89,8 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||
/// This is a version of [`Lua::create_function_mut`] that creates a callback which expires
|
||||
/// on scope drop. See [`Lua::scope`] and [`Scope::create_function`] for more details.
|
||||
///
|
||||
/// [`Lua::create_function_mut`]: struct.Lua.html#method.create_function_mut
|
||||
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
||||
/// [`Lua::create_function_mut`]: crate::Lua::create_function_mut
|
||||
/// [`Lua::scope`]: crate::Lua::scope
|
||||
/// [`Scope::create_function`]: #method.create_function
|
||||
pub fn create_function_mut<'callback, A, R, F>(
|
||||
&'callback self,
|
||||
@@ -101,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)
|
||||
})
|
||||
@@ -114,9 +116,9 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`Lua::create_async_function`]: struct.Lua.html#method.create_async_function
|
||||
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
||||
/// [`Lua::async_scope`]: struct.Lua.html#method.async_scope
|
||||
/// [`Lua::create_async_function`]: crate::Lua::create_async_function
|
||||
/// [`Lua::scope`]: crate::Lua::scope
|
||||
/// [`Lua::async_scope`]: crate::Lua::async_scope
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
pub fn create_async_function<'callback, A, R, F, FR>(
|
||||
@@ -147,8 +149,8 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||
/// UserData be 'static).
|
||||
/// See [`Lua::scope`] for more details.
|
||||
///
|
||||
/// [`Lua::create_userdata`]: struct.Lua.html#method.create_userdata
|
||||
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
||||
/// [`Lua::create_userdata`]: crate::Lua::create_userdata
|
||||
/// [`Lua::scope`]: crate::Lua::scope
|
||||
pub fn create_userdata<T>(&self, data: T) -> Result<AnyUserData<'lua>>
|
||||
where
|
||||
T: 'static + UserData,
|
||||
@@ -165,8 +167,8 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||
///
|
||||
/// Requires `feature = "serialize"`
|
||||
///
|
||||
/// [`Lua::create_ser_userdata`]: struct.Lua.html#method.create_ser_userdata
|
||||
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
||||
/// [`Lua::create_ser_userdata`]: crate::Lua::create_ser_userdata
|
||||
/// [`Lua::scope`]: crate::Lua::scope
|
||||
#[cfg(feature = "serialize")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
|
||||
pub fn create_ser_userdata<T>(&self, data: T) -> Result<AnyUserData<'lua>>
|
||||
@@ -192,16 +194,27 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||
let _sg = StackGuard::new(state);
|
||||
assert_stack(state, 2);
|
||||
|
||||
ud.lua.push_ref(&ud);
|
||||
// Check that userdata is not destructed (via `take()` call)
|
||||
if ud.lua.push_userdata_ref(&ud).is_err() {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
// We know the destructor has not run yet because we hold a reference to the userdata.
|
||||
|
||||
// Clear uservalue
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
ffi::lua_pushnil(state);
|
||||
// Clear associated user values
|
||||
#[cfg(feature = "lua54")]
|
||||
for i in 1..=USER_VALUE_MAXSLOT {
|
||||
ffi::lua_pushnil(state);
|
||||
ffi::lua_setiuservalue(state, -2, i as c_int);
|
||||
}
|
||||
#[cfg(any(feature = "lua53", feature = "lua52", feature = "luau"))]
|
||||
{
|
||||
ffi::lua_pushnil(state);
|
||||
ffi::lua_setuservalue(state, -2);
|
||||
}
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
ud.lua.push_ref(&newtable.0);
|
||||
ffi::lua_setuservalue(state, -2);
|
||||
{
|
||||
ud.lua.push_ref(&newtable.0);
|
||||
ffi::lua_setuservalue(state, -2);
|
||||
}
|
||||
|
||||
vec![Box::new(take_userdata::<UserDataCell<T>>(state))]
|
||||
});
|
||||
@@ -233,9 +246,9 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||
/// creating the userdata metatable each time a new userdata is created.
|
||||
///
|
||||
/// [`Scope::create_userdata`]: #method.create_userdata
|
||||
/// [`Lua::create_userdata`]: struct.Lua.html#method.create_userdata
|
||||
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
||||
/// [`UserDataMethods`]: trait.UserDataMethods.html
|
||||
/// [`Lua::create_userdata`]: crate::Lua::create_userdata
|
||||
/// [`Lua::scope`]:crate::Lua::scope
|
||||
/// [`UserDataMethods`]: crate::UserDataMethods
|
||||
pub fn create_nonstatic_userdata<T>(&self, data: T) -> Result<AnyUserData<'lua>>
|
||||
where
|
||||
T: 'scope + UserData,
|
||||
@@ -250,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: *mut 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
|
||||
@@ -264,9 +277,9 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||
if let Some(Value::UserData(ud)) = value {
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 3)?;
|
||||
lua.push_userdata_ref(&ud.0, false)?;
|
||||
if get_userdata(lua.state, -1) == data_ptr {
|
||||
check_stack(lua.state, 2)?;
|
||||
lua.push_userdata_ref(&ud.0)?;
|
||||
if get_userdata(lua.state, -1) as *const _ == ud_ptr {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
@@ -293,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) }
|
||||
}
|
||||
@@ -301,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
|
||||
@@ -322,16 +335,38 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 13)?;
|
||||
|
||||
let data_ptr = protect_lua(lua.state, 0, 1, |state| {
|
||||
ffi::lua_newuserdata(state, mem::size_of::<UserDataCell<Rc<RefCell<T>>>>())
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[allow(clippy::let_and_return)]
|
||||
let ud_ptr = protect_lua!(lua.state, 0, 1, |state| {
|
||||
let ud =
|
||||
ffi::lua_newuserdata(state, mem::size_of::<UserDataCell<Rc<RefCell<T>>>>());
|
||||
|
||||
// Set empty environment for Lua 5.1
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
{
|
||||
ffi::lua_newtable(state);
|
||||
ffi::lua_setuservalue(state, -2);
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -343,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));
|
||||
@@ -355,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));
|
||||
@@ -368,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));
|
||||
@@ -390,12 +425,13 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||
+ methods_index.map(|_| 1).unwrap_or(0);
|
||||
ffi::lua_pop(lua.state, count);
|
||||
|
||||
let mt_id = ffi::lua_topointer(lua.state, -1);
|
||||
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_id as isize);
|
||||
lua.register_userdata_metatable(mt_ptr, None);
|
||||
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
let newtable = lua.create_table()?;
|
||||
@@ -404,22 +440,33 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||
let _sg = StackGuard::new(state);
|
||||
assert_stack(state, 2);
|
||||
|
||||
ud.lua.push_ref(&ud);
|
||||
|
||||
// We know the destructor has not run yet because we hold a reference to the userdata.
|
||||
// Check that userdata is valid (very likely)
|
||||
if ud.lua.push_userdata_ref(&ud).is_err() {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
// Deregister metatable
|
||||
ffi::lua_getmetatable(state, -1);
|
||||
let mt_id = ffi::lua_topointer(state, -1);
|
||||
let mt_ptr = ffi::lua_topointer(state, -1);
|
||||
ffi::lua_pop(state, 1);
|
||||
ud.lua.deregister_userdata_metatable(mt_id as isize);
|
||||
ud.lua.deregister_userdata_metatable(mt_ptr);
|
||||
|
||||
// Clear uservalue
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
ffi::lua_pushnil(state);
|
||||
// Clear associated user values
|
||||
#[cfg(feature = "lua54")]
|
||||
for i in 1..=USER_VALUE_MAXSLOT {
|
||||
ffi::lua_pushnil(state);
|
||||
ffi::lua_setiuservalue(state, -2, i as c_int);
|
||||
}
|
||||
#[cfg(any(feature = "lua53", feature = "lua52", feature = "luau"))]
|
||||
{
|
||||
ffi::lua_pushnil(state);
|
||||
ffi::lua_setuservalue(state, -2);
|
||||
}
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
ud.lua.push_ref(&newtable.0);
|
||||
ffi::lua_setuservalue(state, -2);
|
||||
{
|
||||
ud.lua.push_ref(&newtable.0);
|
||||
ffi::lua_setuservalue(state, -2);
|
||||
}
|
||||
|
||||
// A hack to drop non-static `T`
|
||||
unsafe fn seal<T>(t: T) -> Box<dyn FnOnce() + 'static> {
|
||||
@@ -496,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
|
||||
@@ -550,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>>>),
|
||||
@@ -691,6 +739,21 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
|
||||
));
|
||||
}
|
||||
|
||||
#[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>>,
|
||||
{
|
||||
// The panic should never happen as async non-static code wouldn't compile
|
||||
// Non-static lifetime must be bounded to 'lua lifetime
|
||||
mlua_panic!("asynchronous meta methods are not supported for non-static userdata")
|
||||
}
|
||||
|
||||
fn add_meta_function<S, A, R, F>(&mut self, meta: S, function: F)
|
||||
where
|
||||
S: Into<MetaMethod>,
|
||||
@@ -720,6 +783,20 @@ impl<'lua, T: UserData> UserDataMethods<'lua, T> for NonStaticUserDataMethods<'l
|
||||
})),
|
||||
));
|
||||
}
|
||||
|
||||
#[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>>,
|
||||
{
|
||||
// The panic should never happen as async non-static code wouldn't compile
|
||||
// Non-static lifetime must be bounded to 'lua lifetime
|
||||
mlua_panic!("asynchronous meta functions are not supported for non-static userdata")
|
||||
}
|
||||
}
|
||||
|
||||
struct NonStaticUserDataFields<'lua, T: UserData> {
|
||||
|
||||
+116
-37
@@ -1,13 +1,14 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashSet;
|
||||
use std::convert::TryInto;
|
||||
use std::os::raw::c_void;
|
||||
use std::rc::Rc;
|
||||
use std::string::String as StdString;
|
||||
|
||||
use rustc_hash::FxHashSet;
|
||||
use serde::de::{self, IntoDeserializer};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::table::{TablePairs, TableSequence};
|
||||
use crate::table::{Table, TablePairs, TableSequence};
|
||||
use crate::value::Value;
|
||||
|
||||
/// A struct for deserializing Lua values into Rust values.
|
||||
@@ -15,18 +16,23 @@ use crate::value::Value;
|
||||
pub struct Deserializer<'lua> {
|
||||
value: Value<'lua>,
|
||||
options: Options,
|
||||
visited: Rc<RefCell<HashSet<*const c_void>>>,
|
||||
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
|
||||
}
|
||||
|
||||
/// A struct with options to change default deserializer behavior.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[non_exhaustive]
|
||||
pub struct Options {
|
||||
/// If true, an attempt to serialize types such as `Thread`, `UserData`, `LightUserData`
|
||||
/// and `Error` will cause an error.
|
||||
/// If true, an attempt to serialize types such as [`Thread`], [`UserData`], [`LightUserData`]
|
||||
/// and [`Error`] will cause an error.
|
||||
/// Otherwise these types skipped when iterating or serialized as unit type.
|
||||
///
|
||||
/// Default: **true**
|
||||
///
|
||||
/// [`Thread`]: crate::Thread
|
||||
/// [`UserData`]: crate::UserData
|
||||
/// [`LightUserData`]: crate::LightUserData
|
||||
/// [`Error`]: crate::Error
|
||||
pub deny_unsupported_types: bool,
|
||||
|
||||
/// If true, an attempt to serialize a recursive table (table that refers to itself)
|
||||
@@ -39,23 +45,24 @@ pub struct Options {
|
||||
|
||||
impl Default for Options {
|
||||
fn default() -> Self {
|
||||
Options {
|
||||
deny_unsupported_types: true,
|
||||
deny_recursive_tables: true,
|
||||
}
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Options {
|
||||
/// Returns a new instance of `Options` with default parameters.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
pub const fn new() -> Self {
|
||||
Options {
|
||||
deny_unsupported_types: true,
|
||||
deny_recursive_tables: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets [`deny_unsupported_types`] option.
|
||||
///
|
||||
/// [`deny_unsupported_types`]: #structfield.deny_unsupported_types
|
||||
pub fn deny_unsupported_types(mut self, enabled: bool) -> Self {
|
||||
#[must_use]
|
||||
pub const fn deny_unsupported_types(mut self, enabled: bool) -> Self {
|
||||
self.deny_unsupported_types = enabled;
|
||||
self
|
||||
}
|
||||
@@ -63,6 +70,7 @@ impl Options {
|
||||
/// Sets [`deny_recursive_tables`] option.
|
||||
///
|
||||
/// [`deny_recursive_tables`]: #structfield.deny_recursive_tables
|
||||
#[must_use]
|
||||
pub fn deny_recursive_tables(mut self, enabled: bool) -> Self {
|
||||
self.deny_recursive_tables = enabled;
|
||||
self
|
||||
@@ -80,14 +88,14 @@ impl<'lua> Deserializer<'lua> {
|
||||
Deserializer {
|
||||
value,
|
||||
options,
|
||||
visited: Rc::new(RefCell::new(HashSet::new())),
|
||||
visited: Rc::new(RefCell::new(FxHashSet::default())),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_parts(
|
||||
value: Value<'lua>,
|
||||
options: Options,
|
||||
visited: Rc<RefCell<HashSet<*const c_void>>>,
|
||||
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
|
||||
) -> Self {
|
||||
Deserializer {
|
||||
value,
|
||||
@@ -109,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()),
|
||||
@@ -158,11 +170,9 @@ impl<'lua, 'de> serde::Deserializer<'de> for Deserializer<'lua> {
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
let (variant, value) = match self.value {
|
||||
let (variant, value, _guard) = match self.value {
|
||||
Value::Table(table) => {
|
||||
let lua = table.0.lua;
|
||||
let ptr = unsafe { lua.get_ref_ptr(&table.0) };
|
||||
self.visited.borrow_mut().insert(ptr);
|
||||
let _guard = RecursionGuard::new(&table, &self.visited);
|
||||
|
||||
let mut iter = table.pairs::<StdString, Value>();
|
||||
let (variant, value) = match iter.next() {
|
||||
@@ -185,9 +195,9 @@ impl<'lua, 'de> serde::Deserializer<'de> for Deserializer<'lua> {
|
||||
return Err(de::Error::custom("bad enum value"));
|
||||
}
|
||||
|
||||
(variant, Some(value))
|
||||
(variant, Some(value), Some(_guard))
|
||||
}
|
||||
Value::String(variant) => (variant.to_str()?.to_owned(), None),
|
||||
Value::String(variant) => (variant.to_str()?.to_owned(), None, None),
|
||||
_ => return Err(de::Error::custom("bad enum value")),
|
||||
};
|
||||
|
||||
@@ -205,10 +215,18 @@ 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 lua = t.0.lua;
|
||||
let ptr = unsafe { lua.get_ref_ptr(&t.0) };
|
||||
self.visited.borrow_mut().insert(ptr);
|
||||
let _guard = RecursionGuard::new(&t, &self.visited);
|
||||
|
||||
let len = t.raw_len() as usize;
|
||||
let mut deserializer = SeqDeserializer {
|
||||
@@ -261,9 +279,7 @@ impl<'lua, 'de> serde::Deserializer<'de> for Deserializer<'lua> {
|
||||
{
|
||||
match self.value {
|
||||
Value::Table(t) => {
|
||||
let lua = t.0.lua;
|
||||
let ptr = unsafe { lua.get_ref_ptr(&t.0) };
|
||||
self.visited.borrow_mut().insert(ptr);
|
||||
let _guard = RecursionGuard::new(&t, &self.visited);
|
||||
|
||||
let mut deserializer = MapDeserializer {
|
||||
pairs: t.pairs(),
|
||||
@@ -303,17 +319,24 @@ 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 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf unit unit_struct newtype_struct
|
||||
identifier ignored_any
|
||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes
|
||||
byte_buf unit unit_struct identifier ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
struct SeqDeserializer<'lua> {
|
||||
seq: TableSequence<'lua, Value<'lua>>,
|
||||
options: Options,
|
||||
visited: Rc<RefCell<HashSet<*const c_void>>>,
|
||||
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
|
||||
}
|
||||
|
||||
impl<'lua, 'de> de::SeqAccess<'de> for SeqDeserializer<'lua> {
|
||||
@@ -347,11 +370,44 @@ 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>>,
|
||||
options: Options,
|
||||
visited: Rc<RefCell<HashSet<*const c_void>>>,
|
||||
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
|
||||
processed: usize,
|
||||
}
|
||||
|
||||
@@ -407,7 +463,7 @@ struct EnumDeserializer<'lua> {
|
||||
variant: StdString,
|
||||
value: Option<Value<'lua>>,
|
||||
options: Options,
|
||||
visited: Rc<RefCell<HashSet<*const c_void>>>,
|
||||
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
|
||||
}
|
||||
|
||||
impl<'lua, 'de> de::EnumAccess<'de> for EnumDeserializer<'lua> {
|
||||
@@ -431,7 +487,7 @@ impl<'lua, 'de> de::EnumAccess<'de> for EnumDeserializer<'lua> {
|
||||
struct VariantDeserializer<'lua> {
|
||||
value: Option<Value<'lua>>,
|
||||
options: Options,
|
||||
visited: Rc<RefCell<HashSet<*const c_void>>>,
|
||||
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
|
||||
}
|
||||
|
||||
impl<'lua, 'de> de::VariantAccess<'de> for VariantDeserializer<'lua> {
|
||||
@@ -495,15 +551,38 @@ impl<'lua, 'de> de::VariantAccess<'de> for VariantDeserializer<'lua> {
|
||||
}
|
||||
}
|
||||
|
||||
// Adds `ptr` to the `visited` map and removes on drop
|
||||
// Used to track recursive tables but allow to traverse same tables multiple times
|
||||
struct RecursionGuard {
|
||||
ptr: *const c_void,
|
||||
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
|
||||
}
|
||||
|
||||
impl RecursionGuard {
|
||||
#[inline]
|
||||
fn new(table: &Table, visited: &Rc<RefCell<FxHashSet<*const c_void>>>) -> Self {
|
||||
let visited = Rc::clone(visited);
|
||||
let ptr = table.to_pointer();
|
||||
visited.borrow_mut().insert(ptr);
|
||||
RecursionGuard { ptr, visited }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RecursionGuard {
|
||||
fn drop(&mut self) {
|
||||
self.visited.borrow_mut().remove(&self.ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Checks `options` and decides should we emit an error or skip next element
|
||||
fn check_value_if_skip(
|
||||
value: &Value,
|
||||
options: Options,
|
||||
visited: &Rc<RefCell<HashSet<*const c_void>>>,
|
||||
visited: &RefCell<FxHashSet<*const c_void>>,
|
||||
) -> Result<bool> {
|
||||
match value {
|
||||
Value::Table(table) => {
|
||||
let lua = table.0.lua;
|
||||
let ptr = unsafe { lua.get_ref_ptr(&table.0) };
|
||||
let ptr = table.to_pointer();
|
||||
if visited.borrow().contains(&ptr) {
|
||||
if options.deny_recursive_tables {
|
||||
return Err(de::Error::custom("recursive table detected"));
|
||||
|
||||
+16
-13
@@ -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, protect_lua, StackGuard};
|
||||
use crate::util::{assert_stack, check_stack, StackGuard};
|
||||
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.
|
||||
///
|
||||
@@ -69,11 +70,11 @@ pub trait LuaSerdeExt<'lua> {
|
||||
/// ```
|
||||
fn array_metatable(&'lua self) -> Table<'lua>;
|
||||
|
||||
/// Converts `T` into a `Value` instance.
|
||||
/// Converts `T` into a [`Value`] instance.
|
||||
///
|
||||
/// Requires `feature = "serialize"`
|
||||
///
|
||||
/// [`Value`]: enum.Value.html
|
||||
/// [`Value`]: crate::Value
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@@ -102,11 +103,11 @@ pub trait LuaSerdeExt<'lua> {
|
||||
/// ```
|
||||
fn to_value<T: Serialize + ?Sized>(&'lua self, t: &T) -> Result<Value<'lua>>;
|
||||
|
||||
/// Converts `T` into a `Value` instance with options.
|
||||
/// Converts `T` into a [`Value`] instance with options.
|
||||
///
|
||||
/// Requires `feature = "serialize"`
|
||||
///
|
||||
/// [`Value`]: enum.Value.html
|
||||
/// [`Value`]: crate::Value
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@@ -129,11 +130,11 @@ pub trait LuaSerdeExt<'lua> {
|
||||
where
|
||||
T: Serialize + ?Sized;
|
||||
|
||||
/// Deserializes a `Value` into any serde deserializable object.
|
||||
/// Deserializes a [`Value`] into any serde deserializable object.
|
||||
///
|
||||
/// Requires `feature = "serialize"`
|
||||
///
|
||||
/// [`Value`]: enum.Value.html
|
||||
/// [`Value`]: crate::Value
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@@ -157,13 +158,14 @@ 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.
|
||||
/// Deserializes a [`Value`] into any serde deserializable object with options.
|
||||
///
|
||||
/// Requires `feature = "serialize"`
|
||||
///
|
||||
/// [`Value`]: enum.Value.html
|
||||
/// [`Value`]: crate::Value
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@@ -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>,
|
||||
@@ -240,10 +243,10 @@ impl<'lua> LuaSerdeExt<'lua> for Lua {
|
||||
}
|
||||
}
|
||||
|
||||
// Uses 6 stack spaces and calls checkstack.
|
||||
// Uses 2 stack spaces and calls checkstack.
|
||||
pub(crate) unsafe fn init_metatables(state: *mut ffi::lua_State) -> Result<()> {
|
||||
check_stack(state, 3)?;
|
||||
protect_lua(state, 0, 0, |state| {
|
||||
check_stack(state, 2)?;
|
||||
protect_lua!(state, 0, 0, fn(state) {
|
||||
ffi::lua_createtable(state, 0, 1);
|
||||
|
||||
ffi::lua_pushstring(state, cstr!("__metatable"));
|
||||
@@ -256,7 +259,7 @@ pub(crate) unsafe fn init_metatables(state: *mut ffi::lua_State) -> Result<()> {
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn push_array_metatable(state: *mut ffi::lua_State) {
|
||||
let array_metatable_key = &ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void;
|
||||
let array_metatable_key = &ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *const c_void;
|
||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, array_metatable_key);
|
||||
}
|
||||
|
||||
|
||||
+34
-22
@@ -9,7 +9,7 @@ use crate::lua::Lua;
|
||||
use crate::string::String;
|
||||
use crate::table::Table;
|
||||
use crate::types::Integer;
|
||||
use crate::util::{check_stack, protect_lua, StackGuard};
|
||||
use crate::util::{check_stack, StackGuard};
|
||||
use crate::value::{ToLua, Value};
|
||||
|
||||
/// A struct for serializing Rust values into Lua values.
|
||||
@@ -28,16 +28,16 @@ pub struct Options {
|
||||
///
|
||||
/// Default: **true**
|
||||
///
|
||||
/// [`array_metatable`]: ../trait.LuaSerdeExt.html#tymethod.array_metatable
|
||||
/// [`array_metatable`]: crate::LuaSerdeExt::array_metatable
|
||||
pub set_array_metatable: bool,
|
||||
|
||||
/// If true, serialize `None` (part of `Option` type) to [`null`].
|
||||
/// If true, serialize `None` (part of the `Option` type) to [`null`].
|
||||
/// Otherwise it will be set to Lua [`Nil`].
|
||||
///
|
||||
/// Default: **true**
|
||||
///
|
||||
/// [`null`]: ../trait.LuaSerdeExt.html#tymethod.null
|
||||
/// [`Nil`]: ../../enum.Value.html#variant.Nil
|
||||
/// [`null`]: crate::LuaSerdeExt::null
|
||||
/// [`Nil`]: crate::Value::Nil
|
||||
pub serialize_none_to_null: bool,
|
||||
|
||||
/// If true, serialize `Unit` (type of `()` in Rust) and Unit structs to [`null`].
|
||||
@@ -45,31 +45,32 @@ pub struct Options {
|
||||
///
|
||||
/// Default: **true**
|
||||
///
|
||||
/// [`null`]: ../trait.LuaSerdeExt.html#tymethod.null
|
||||
/// [`Nil`]: ../../enum.Value.html#variant.Nil
|
||||
/// [`null`]: crate::LuaSerdeExt::null
|
||||
/// [`Nil`]: crate::Value::Nil
|
||||
pub serialize_unit_to_null: bool,
|
||||
}
|
||||
|
||||
impl Default for Options {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Options {
|
||||
/// Returns a new instance of [`Options`] with default parameters.
|
||||
pub const fn new() -> Self {
|
||||
Options {
|
||||
set_array_metatable: true,
|
||||
serialize_none_to_null: true,
|
||||
serialize_unit_to_null: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Options {
|
||||
/// Returns a new instance of `Options` with default parameters.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Sets [`set_array_metatable`] option.
|
||||
///
|
||||
/// [`set_array_metatable`]: #structfield.set_array_metatable
|
||||
pub fn set_array_metatable(mut self, enabled: bool) -> Self {
|
||||
#[must_use]
|
||||
pub const fn set_array_metatable(mut self, enabled: bool) -> Self {
|
||||
self.set_array_metatable = enabled;
|
||||
self
|
||||
}
|
||||
@@ -77,7 +78,8 @@ impl Options {
|
||||
/// Sets [`serialize_none_to_null`] option.
|
||||
///
|
||||
/// [`serialize_none_to_null`]: #structfield.serialize_none_to_null
|
||||
pub fn serialize_none_to_null(mut self, enabled: bool) -> Self {
|
||||
#[must_use]
|
||||
pub const fn serialize_none_to_null(mut self, enabled: bool) -> Self {
|
||||
self.serialize_none_to_null = enabled;
|
||||
self
|
||||
}
|
||||
@@ -85,7 +87,8 @@ impl Options {
|
||||
/// Sets [`serialize_unit_to_null`] option.
|
||||
///
|
||||
/// [`serialize_unit_to_null`]: #structfield.serialize_unit_to_null
|
||||
pub fn serialize_unit_to_null(mut self, enabled: bool) -> Self {
|
||||
#[must_use]
|
||||
pub const fn serialize_unit_to_null(mut self, enabled: bool) -> Self {
|
||||
self.serialize_unit_to_null = enabled;
|
||||
self
|
||||
}
|
||||
@@ -139,6 +142,8 @@ impl<'lua> ser::Serializer for Serializer<'lua> {
|
||||
lua_serialize_number!(serialize_u32, u32);
|
||||
lua_serialize_number!(serialize_i64, i64);
|
||||
lua_serialize_number!(serialize_u64, u64);
|
||||
lua_serialize_number!(serialize_i128, i128);
|
||||
lua_serialize_number!(serialize_u128, u128);
|
||||
|
||||
lua_serialize_number!(serialize_f32, f32);
|
||||
lua_serialize_number!(serialize_f64, f64);
|
||||
@@ -318,14 +323,21 @@ impl<'lua> ser::SerializeSeq for SerializeVec<'lua> {
|
||||
let value = lua.to_value_with(value, self.options)?;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 5)?;
|
||||
check_stack(lua.state, 4)?;
|
||||
|
||||
lua.push_ref(&self.table.0);
|
||||
lua.push_value(value)?;
|
||||
let len = ffi::lua_rawlen(lua.state, -2) as Integer;
|
||||
protect_lua(lua.state, 2, 0, |state| {
|
||||
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);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+29
-15
@@ -6,45 +6,56 @@ use std::u32;
|
||||
pub struct StdLib(u32);
|
||||
|
||||
impl StdLib {
|
||||
/// [`coroutine`](https://www.lua.org/manual/5.3/manual.html#6.2) library
|
||||
/// [`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", doc))]
|
||||
/// 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.3/manual.html#6.6) library
|
||||
/// [`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.3/manual.html#6.8) library
|
||||
/// [`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.3/manual.html#6.9) library
|
||||
/// [`os`](https://www.lua.org/manual/5.4/manual.html#6.9) library
|
||||
pub const OS: StdLib = StdLib(1 << 3);
|
||||
/// [`string`](https://www.lua.org/manual/5.3/manual.html#6.4) library
|
||||
/// [`string`](https://www.lua.org/manual/5.4/manual.html#6.4) library
|
||||
pub const STRING: StdLib = StdLib(1 << 4);
|
||||
/// [`utf8`](https://www.lua.org/manual/5.3/manual.html#6.5) library
|
||||
/// [`utf8`](https://www.lua.org/manual/5.4/manual.html#6.5) library
|
||||
///
|
||||
/// Requires `feature = "lua54/lua53"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||
/// 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.3/manual.html#6.7) library
|
||||
/// [`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.3/manual.html#6.3) library
|
||||
/// [`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.3/manual.html#6.10) library
|
||||
/// (**unsafe**) [`debug`](https://www.lua.org/manual/5.4/manual.html#6.10) library
|
||||
pub const DEBUG: StdLib = StdLib(1 << 31);
|
||||
|
||||
/// No libraries
|
||||
@@ -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
|
||||
|
||||
+28
-1
@@ -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};
|
||||
|
||||
@@ -111,6 +113,17 @@ impl<'lua> String<'lua> {
|
||||
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 lua = self.0.lua;
|
||||
unsafe { lua.ref_thread_exec(|refthr| ffi::lua_topointer(refthr, self.0.index)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> AsRef<[u8]> for String<'lua> {
|
||||
@@ -119,6 +132,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 +155,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>
|
||||
|
||||
+143
-39
@@ -1,16 +1,18 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_void;
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
use {
|
||||
serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer},
|
||||
std::result::Result as StdResult,
|
||||
rustc_hash::FxHashSet,
|
||||
serde::ser::{self, Serialize, SerializeMap, SerializeSeq, Serializer},
|
||||
std::{cell::RefCell, result::Result as StdResult},
|
||||
};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::function::Function;
|
||||
use crate::types::{Integer, LuaRef};
|
||||
use crate::util::{assert_stack, check_stack, protect_lua, StackGuard};
|
||||
use crate::util::{assert_stack, check_stack, StackGuard};
|
||||
use crate::value::{FromLua, FromLuaMulti, Nil, ToLua, ToLuaMulti, Value};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
@@ -62,12 +64,12 @@ impl<'lua> Table<'lua> {
|
||||
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 6)?;
|
||||
check_stack(lua.state, 5)?;
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
lua.push_value(key)?;
|
||||
lua.push_value(value)?;
|
||||
protect_lua(lua.state, 3, 0, |state| ffi::lua_settable(state, -3))
|
||||
protect_lua!(lua.state, 3, 0, fn(state) ffi::lua_settable(state, -3))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,11 +103,11 @@ impl<'lua> Table<'lua> {
|
||||
|
||||
let value = unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 5)?;
|
||||
check_stack(lua.state, 4)?;
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
lua.push_value(key)?;
|
||||
protect_lua(lua.state, 2, 1, |state| ffi::lua_gettable(state, -2))?;
|
||||
protect_lua!(lua.state, 2, 1, fn(state) ffi::lua_gettable(state, -2))?;
|
||||
|
||||
lua.pop_value()
|
||||
};
|
||||
@@ -119,13 +121,12 @@ impl<'lua> Table<'lua> {
|
||||
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 5)?;
|
||||
check_stack(lua.state, 4)?;
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
lua.push_value(key)?;
|
||||
protect_lua(lua.state, 2, 1, |state| {
|
||||
ffi::lua_gettable(state, -2) != ffi::LUA_TNIL
|
||||
})
|
||||
protect_lua!(lua.state, 2, 1, fn(state) ffi::lua_gettable(state, -2))?;
|
||||
Ok(ffi::lua_isnil(lua.state, -1) == 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,12 +194,18 @@ impl<'lua> Table<'lua> {
|
||||
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 6)?;
|
||||
check_stack(lua.state, 5)?;
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
lua.push_value(key)?;
|
||||
lua.push_value(value)?;
|
||||
protect_lua(lua.state, 3, 0, |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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,7 +243,7 @@ impl<'lua> Table<'lua> {
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
lua.push_value(value)?;
|
||||
protect_lua(lua.state, 2, 0, |state| {
|
||||
protect_lua!(lua.state, 2, 0, |state| {
|
||||
for i in (idx..=size).rev() {
|
||||
// table[i+1] = table[i]
|
||||
ffi::lua_rawgeti(state, -2, i);
|
||||
@@ -268,7 +275,7 @@ impl<'lua> Table<'lua> {
|
||||
check_stack(lua.state, 4)?;
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
protect_lua(lua.state, 1, 0, |state| {
|
||||
protect_lua!(lua.state, 1, 0, |state| {
|
||||
for i in idx..size {
|
||||
ffi::lua_rawgeti(state, -1, i + 1);
|
||||
ffi::lua_rawseti(state, -2, i);
|
||||
@@ -294,7 +301,7 @@ impl<'lua> Table<'lua> {
|
||||
check_stack(lua.state, 4)?;
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
protect_lua(lua.state, 1, 0, |state| ffi::luaL_len(state, -1))
|
||||
protect_lua!(lua.state, 1, 0, |state| ffi::luaL_len(state, -1))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,6 +355,46 @@ impl<'lua> Table<'lua> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 lua = self.0.lua;
|
||||
unsafe {
|
||||
lua.ref_thread_exec(|refthr| {
|
||||
ffi::lua_setreadonly(refthr, self.0.index, enabled as _);
|
||||
if !enabled {
|
||||
// Reset "safeenv" flag
|
||||
ffi::lua_setsafeenv(refthr, 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 lua = self.0.lua;
|
||||
unsafe { lua.ref_thread_exec(|refthr| ffi::lua_getreadonly(refthr, 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 lua = self.0.lua;
|
||||
unsafe { lua.ref_thread_exec(|refthr| ffi::lua_topointer(refthr, 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.
|
||||
@@ -379,8 +426,8 @@ impl<'lua> Table<'lua> {
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`Result`]: type.Result.html
|
||||
/// [Lua manual]: http://www.lua.org/manual/5.3/manual.html#pdf-next
|
||||
/// [`Result`]: crate::Result
|
||||
/// [Lua manual]: http://www.lua.org/manual/5.4/manual.html#pdf-next
|
||||
pub fn pairs<K: FromLua<'lua>, V: FromLua<'lua>>(self) -> TablePairs<'lua, K, V> {
|
||||
TablePairs {
|
||||
table: self.0,
|
||||
@@ -428,8 +475,8 @@ impl<'lua> Table<'lua> {
|
||||
/// ```
|
||||
///
|
||||
/// [`pairs`]: #method.pairs
|
||||
/// [`Result`]: type.Result.html
|
||||
/// [Lua manual]: http://www.lua.org/manual/5.3/manual.html#pdf-next
|
||||
/// [`Result`]: crate::Result
|
||||
/// [Lua manual]: http://www.lua.org/manual/5.4/manual.html#pdf-next
|
||||
pub fn sequence_values<V: FromLua<'lua>>(self) -> TableSequence<'lua, V> {
|
||||
TableSequence {
|
||||
table: self.0,
|
||||
@@ -455,7 +502,7 @@ impl<'lua> Table<'lua> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "async", feature = "serialize"))]
|
||||
#[cfg(any(feature = "serialize"))]
|
||||
pub(crate) fn raw_sequence_values_by_len<V: FromLua<'lua>>(
|
||||
self,
|
||||
len: Option<Integer>,
|
||||
@@ -502,6 +549,25 @@ impl<'lua> AsRef<Table<'lua>> for Table<'lua> {
|
||||
|
||||
/// An extension trait for `Table`s that provides a variety of convenient functionality.
|
||||
pub trait TableExt<'lua> {
|
||||
/// Calls the table as function assuming it has `__call` metamethod.
|
||||
///
|
||||
/// The metamethod is called with the table as its first argument, followed by the passed arguments.
|
||||
fn call<A, R>(&self, args: A) -> Result<R>
|
||||
where
|
||||
A: ToLuaMulti<'lua>,
|
||||
R: FromLuaMulti<'lua>;
|
||||
|
||||
/// Asynchronously calls the table as function assuming it has `__call` metamethod.
|
||||
///
|
||||
/// The metamethod is called with the table as its first argument, followed by the passed arguments.
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
fn call_async<'fut, A, R>(&self, args: A) -> LocalBoxFuture<'fut, Result<R>>
|
||||
where
|
||||
'lua: 'fut,
|
||||
A: ToLuaMulti<'lua>,
|
||||
R: FromLuaMulti<'lua> + 'fut;
|
||||
|
||||
/// Gets the function associated to `key` from the table and executes it,
|
||||
/// passing the table itself along with `args` as function arguments.
|
||||
///
|
||||
@@ -564,6 +630,25 @@ pub trait TableExt<'lua> {
|
||||
}
|
||||
|
||||
impl<'lua> TableExt<'lua> for Table<'lua> {
|
||||
fn call<A, R>(&self, args: A) -> Result<R>
|
||||
where
|
||||
A: ToLuaMulti<'lua>,
|
||||
R: FromLuaMulti<'lua>,
|
||||
{
|
||||
// Convert table to a function and call via pcall that respects the `__call` metamethod.
|
||||
Function(self.0.clone()).call(args)
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
fn call_async<'fut, A, R>(&self, args: A) -> LocalBoxFuture<'fut, Result<R>>
|
||||
where
|
||||
'lua: 'fut,
|
||||
A: ToLuaMulti<'lua>,
|
||||
R: FromLuaMulti<'lua> + 'fut,
|
||||
{
|
||||
Function(self.0.clone()).call_async(args)
|
||||
}
|
||||
|
||||
fn call_method<K, A, R>(&self, key: K, args: A) -> Result<R>
|
||||
where
|
||||
K: ToLua<'lua>,
|
||||
@@ -623,22 +708,41 @@ impl<'lua> Serialize for Table<'lua> {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let len = self.raw_len() as usize;
|
||||
if len > 0 || self.is_array() {
|
||||
let mut seq = serializer.serialize_seq(Some(len))?;
|
||||
for v in self.clone().raw_sequence_values_by_len::<Value>(None) {
|
||||
let v = v.map_err(serde::ser::Error::custom)?;
|
||||
seq.serialize_element(&v)?;
|
||||
}
|
||||
return seq.end();
|
||||
thread_local! {
|
||||
static VISITED: RefCell<FxHashSet<*const c_void>> = RefCell::new(FxHashSet::default());
|
||||
}
|
||||
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
for kv in self.clone().pairs::<Value, Value>() {
|
||||
let (k, v) = kv.map_err(serde::ser::Error::custom)?;
|
||||
map.serialize_entry(&k, &v)?;
|
||||
}
|
||||
map.end()
|
||||
let ptr = self.to_pointer();
|
||||
let res = VISITED.with(|visited| {
|
||||
{
|
||||
let mut visited = visited.borrow_mut();
|
||||
if visited.contains(&ptr) {
|
||||
return Err(ser::Error::custom("recursive table detected"));
|
||||
}
|
||||
visited.insert(ptr);
|
||||
}
|
||||
|
||||
let len = self.raw_len() as usize;
|
||||
if len > 0 || self.is_array() {
|
||||
let mut seq = serializer.serialize_seq(Some(len))?;
|
||||
for v in self.clone().raw_sequence_values_by_len::<Value>(None) {
|
||||
let v = v.map_err(serde::ser::Error::custom)?;
|
||||
seq.serialize_element(&v)?;
|
||||
}
|
||||
return seq.end();
|
||||
}
|
||||
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
for kv in self.clone().pairs::<Value, Value>() {
|
||||
let (k, v) = kv.map_err(serde::ser::Error::custom)?;
|
||||
map.serialize_entry(&k, &v)?;
|
||||
}
|
||||
map.end()
|
||||
});
|
||||
VISITED.with(|visited| {
|
||||
visited.borrow_mut().remove(&ptr);
|
||||
});
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,7 +750,7 @@ impl<'lua> Serialize for Table<'lua> {
|
||||
///
|
||||
/// This struct is created by the [`Table::pairs`] method.
|
||||
///
|
||||
/// [`Table::pairs`]: struct.Table.html#method.pairs
|
||||
/// [`Table::pairs`]: crate::Table::pairs
|
||||
pub struct TablePairs<'lua, K, V> {
|
||||
table: LuaRef<'lua>,
|
||||
key: Option<Value<'lua>>,
|
||||
@@ -671,7 +775,7 @@ where
|
||||
lua.push_ref(&self.table);
|
||||
lua.push_value(prev_key)?;
|
||||
|
||||
let next = protect_lua(lua.state, 2, ffi::LUA_MULTRET, |state| {
|
||||
let next = protect_lua!(lua.state, 2, ffi::LUA_MULTRET, |state| {
|
||||
ffi::lua_next(state, -2)
|
||||
})?;
|
||||
if next != 0 {
|
||||
@@ -705,7 +809,7 @@ where
|
||||
///
|
||||
/// This struct is created by the [`Table::sequence_values`] method.
|
||||
///
|
||||
/// [`Table::sequence_values`]: struct.Table.html#method.sequence_values
|
||||
/// [`Table::sequence_values`]: crate::Table::sequence_values
|
||||
pub struct TableSequence<'lua, V> {
|
||||
table: LuaRef<'lua>,
|
||||
index: Option<Integer>,
|
||||
@@ -732,7 +836,7 @@ where
|
||||
let res = if self.raw {
|
||||
ffi::lua_rawgeti(lua.state, -1, index)
|
||||
} else {
|
||||
protect_lua(lua.state, 1, 1, |state| ffi::lua_geti(state, -1, index))?
|
||||
protect_lua!(lua.state, 1, 1, |state| ffi::lua_geti(state, -1, index))?
|
||||
};
|
||||
match res {
|
||||
ffi::LUA_TNIL if index > self.len.unwrap_or(0) => Ok(None),
|
||||
|
||||
+153
-59
@@ -4,25 +4,26 @@ use std::os::raw::c_int;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
use crate::types::LuaRef;
|
||||
use crate::util::{assert_stack, check_stack, error_traceback, pop_error, protect_lua, StackGuard};
|
||||
use crate::value::{FromLuaMulti, MultiValue, ToLuaMulti};
|
||||
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"), doc))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
all(feature = "luajit", feature = "vendored"),
|
||||
feature = "luau",
|
||||
))]
|
||||
use crate::function::Function;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
use {
|
||||
crate::{
|
||||
lua::{ASYNC_POLL_PENDING, WAKER_REGISTRY_KEY},
|
||||
util::get_gc_userdata,
|
||||
value::Value,
|
||||
lua::{Lua, ASYNC_POLL_PENDING},
|
||||
value::{MultiValue, Value},
|
||||
},
|
||||
futures_core::{future::Future, stream::Stream},
|
||||
std::{
|
||||
cell::RefCell,
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
os::raw::c_void,
|
||||
pin::Pin,
|
||||
task::{Context, Poll, Waker},
|
||||
},
|
||||
@@ -35,7 +36,7 @@ pub enum ThreadStatus {
|
||||
///
|
||||
/// If a thread is in this state, it can be resumed by calling [`Thread::resume`].
|
||||
///
|
||||
/// [`Thread::resume`]: struct.Thread.html#method.resume
|
||||
/// [`Thread::resume`]: crate::Thread::resume
|
||||
Resumable,
|
||||
/// Either the thread has finished executing, or the thread is currently running.
|
||||
Unresumable,
|
||||
@@ -51,8 +52,8 @@ pub struct Thread<'lua>(pub(crate) LuaRef<'lua>);
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`Future`]: ../futures_core/future/trait.Future.html
|
||||
/// [`Stream`]: ../futures_core/stream/trait.Stream.html
|
||||
/// [`Future`]: futures_core::future::Future
|
||||
/// [`Stream`]: futures_core::stream::Stream
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
||||
#[derive(Debug)]
|
||||
@@ -60,6 +61,7 @@ pub struct AsyncThread<'lua, R> {
|
||||
thread: Thread<'lua>,
|
||||
args0: RefCell<Option<Result<MultiValue<'lua>>>>,
|
||||
ret: PhantomData<R>,
|
||||
recycle: bool,
|
||||
}
|
||||
|
||||
impl<'lua> Thread<'lua> {
|
||||
@@ -110,15 +112,14 @@ impl<'lua> Thread<'lua> {
|
||||
R: FromLuaMulti<'lua>,
|
||||
{
|
||||
let lua = self.0.lua;
|
||||
let args = args.to_lua_multi(lua)?;
|
||||
let mut args = args.to_lua_multi(lua)?;
|
||||
let nargs = args.len() as c_int;
|
||||
let results = unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, cmp::min(nargs + 1, 3))?;
|
||||
check_stack(lua.state, cmp::max(nargs + 1, 3))?;
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
let thread_state = ffi::lua_tothread(lua.state, -1);
|
||||
ffi::lua_pop(lua.state, 1);
|
||||
let thread_state =
|
||||
lua.ref_thread_exec(|ref_thread| ffi::lua_tothread(ref_thread, self.0.index));
|
||||
|
||||
let status = ffi::lua_status(thread_state);
|
||||
if status != ffi::LUA_YIELD && ffi::lua_gettop(thread_state) == 0 {
|
||||
@@ -126,7 +127,7 @@ impl<'lua> Thread<'lua> {
|
||||
}
|
||||
|
||||
check_stack(thread_state, nargs)?;
|
||||
for arg in args {
|
||||
for arg in args.drain_all() {
|
||||
lua.push_value(arg)?;
|
||||
}
|
||||
ffi::lua_xmove(lua.state, thread_state, nargs);
|
||||
@@ -135,11 +136,15 @@ 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 = MultiValue::new();
|
||||
let mut results = args; // Reuse MultiValue container
|
||||
check_stack(lua.state, nresults + 2)?; // 2 is extra for `lua.pop_value()` below
|
||||
ffi::lua_xmove(thread_state, lua.state, nresults);
|
||||
|
||||
@@ -155,12 +160,8 @@ impl<'lua> Thread<'lua> {
|
||||
pub fn status(&self) -> ThreadStatus {
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
assert_stack(lua.state, 1);
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
let thread_state = ffi::lua_tothread(lua.state, -1);
|
||||
ffi::lua_pop(lua.state, 1);
|
||||
let thread_state =
|
||||
lua.ref_thread_exec(|ref_thread| ffi::lua_tothread(ref_thread, self.0.index));
|
||||
|
||||
let status = ffi::lua_status(thread_state);
|
||||
if status != ffi::LUA_OK && status != ffi::LUA_YIELD {
|
||||
@@ -179,16 +180,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"), doc))]
|
||||
#[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 {
|
||||
@@ -198,22 +203,35 @@ 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(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts Thread to an AsyncThread which implements Future and Stream traits.
|
||||
/// Converts Thread to an AsyncThread which implements [`Future`] and [`Stream`] traits.
|
||||
///
|
||||
/// `args` are passed as arguments to the thread function for first call.
|
||||
/// The object call `resume()` while polling and also allows to run rust futures
|
||||
/// The object calls [`resume()`] while polling and also allows to run rust futures
|
||||
/// to completion using an executor.
|
||||
///
|
||||
/// Using AsyncThread as a Stream allows to iterate through `coroutine.yield()`
|
||||
@@ -222,6 +240,10 @@ impl<'lua> Thread<'lua> {
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`Future`]: futures_core::future::Future
|
||||
/// [`Stream`]: futures_core::stream::Stream
|
||||
/// [`resume()`]: https://www.lua.org/manual/5.4/manual.html#lua_resume
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@@ -263,6 +285,54 @@ impl<'lua> Thread<'lua> {
|
||||
thread: self,
|
||||
args0: RefCell::new(Some(args)),
|
||||
ret: PhantomData,
|
||||
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 = lua.ref_thread_exec(|t| ffi::lua_tothread(t, 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -273,6 +343,39 @@ impl<'lua> PartialEq for Thread<'lua> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
impl<'lua, R> AsyncThread<'lua, R> {
|
||||
#[inline]
|
||||
pub(crate) fn set_recyclable(&mut self, recyclable: bool) {
|
||||
self.recycle = recyclable;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[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 {
|
||||
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 =
|
||||
lua.ref_thread_exec(|t| ffi::lua_tothread(t, self.thread.0.index));
|
||||
ffi::lua_resetthread(thread_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
impl<'lua, R> Stream for AsyncThread<'lua, R>
|
||||
where
|
||||
@@ -288,7 +391,7 @@ where
|
||||
_ => return Poll::Ready(None),
|
||||
};
|
||||
|
||||
let _wg = WakerGuard::new(lua.state, cx.waker().clone());
|
||||
let _wg = WakerGuard::new(lua, cx.waker().clone());
|
||||
let ret: MultiValue = if let Some(args) = self.args0.borrow_mut().take() {
|
||||
self.thread.resume(args?)?
|
||||
} else {
|
||||
@@ -319,7 +422,7 @@ where
|
||||
_ => return Poll::Ready(Err(Error::CoroutineInactive)),
|
||||
};
|
||||
|
||||
let _wg = WakerGuard::new(lua.state, cx.waker().clone());
|
||||
let _wg = WakerGuard::new(lua, cx.waker().clone());
|
||||
let ret: MultiValue = if let Some(args) = self.args0.borrow_mut().take() {
|
||||
self.thread.resume(args?)?
|
||||
} else {
|
||||
@@ -341,47 +444,38 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[inline(always)]
|
||||
fn is_poll_pending(val: &MultiValue) -> bool {
|
||||
match val.iter().enumerate().last() {
|
||||
Some((1, Value::LightUserData(ud))) => {
|
||||
ud.0 == &ASYNC_POLL_PENDING as *const u8 as *mut c_void
|
||||
Some((0, Value::LightUserData(ud))) => {
|
||||
std::ptr::eq(ud.0 as *const u8, &ASYNC_POLL_PENDING as *const u8)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
struct WakerGuard(*mut ffi::lua_State, Option<Waker>);
|
||||
struct WakerGuard<'lua> {
|
||||
lua: &'lua Lua,
|
||||
prev: Option<Waker>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
impl WakerGuard {
|
||||
pub fn new(state: *mut ffi::lua_State, waker: Waker) -> Result<WakerGuard> {
|
||||
impl<'lua> WakerGuard<'lua> {
|
||||
#[inline]
|
||||
pub fn new(lua: &Lua, waker: Waker) -> Result<WakerGuard> {
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(state);
|
||||
check_stack(state, 3)?;
|
||||
|
||||
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
|
||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
|
||||
let waker_slot = get_gc_userdata::<Option<Waker>>(state, -1).as_mut();
|
||||
let old = mlua_expect!(waker_slot, "Waker is destroyed").replace(waker);
|
||||
|
||||
Ok(WakerGuard(state, old))
|
||||
let prev = lua.set_waker(Some(waker));
|
||||
Ok(WakerGuard { lua, prev })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
impl Drop for WakerGuard {
|
||||
impl<'lua> Drop for WakerGuard<'lua> {
|
||||
fn drop(&mut self) {
|
||||
let state = self.0;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(state);
|
||||
assert_stack(state, 3);
|
||||
|
||||
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
|
||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
|
||||
let waker_slot = get_gc_userdata::<Option<Waker>>(state, -1).as_mut();
|
||||
mem::swap(mlua_expect!(waker_slot, "Waker is destroyed"), &mut self.1);
|
||||
self.lua.set_waker(self.prev.take());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+51
-21
@@ -1,16 +1,20 @@
|
||||
use std::cell::RefCell;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{fmt, mem, ptr};
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
use std::ffi::CStr;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
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;
|
||||
|
||||
@@ -26,28 +30,48 @@ 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,
|
||||
}
|
||||
|
||||
pub(crate) type HookCallback = Arc<RefCell<dyn FnMut(&Lua, Debug) -> Result<()>>>;
|
||||
#[cfg(all(feature = "send", not(feature = "luau")))]
|
||||
pub(crate) type HookCallback = Arc<dyn Fn(&Lua, Debug) -> Result<()> + Send>;
|
||||
|
||||
#[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>;
|
||||
|
||||
#[cfg(all(not(feature = "send"), feature = "lua54"))]
|
||||
pub(crate) type WarnCallback = Box<dyn Fn(&Lua, &CStr, bool) -> Result<()>>;
|
||||
|
||||
#[cfg(feature = "send")]
|
||||
pub trait MaybeSend: Send {}
|
||||
@@ -59,21 +83,25 @@ pub trait MaybeSend {}
|
||||
#[cfg(not(feature = "send"))]
|
||||
impl<T> MaybeSend for T {}
|
||||
|
||||
pub(crate) struct DestructedUserdata;
|
||||
|
||||
/// An auto generated key into the Lua registry.
|
||||
///
|
||||
/// This is a handle to a value stored inside the Lua registry. It is not automatically
|
||||
/// garbage collected on Drop, but it can be removed with [`Lua::remove_registry_value`],
|
||||
/// and instances not manually removed can be garbage collected with [`Lua::expire_registry_values`].
|
||||
///
|
||||
/// Be warned, If you place this into Lua via a `UserData` type or a rust callback, it is *very
|
||||
/// Be warned, If you place this into Lua via a [`UserData`] type or a rust callback, it is *very
|
||||
/// easy* to accidentally cause reference cycles that the Lua garbage collector cannot resolve.
|
||||
/// Instead of placing a `RegistryKey` into a `UserData` type, prefer instead to use
|
||||
/// [`UserData::set_user_value`] / [`UserData::get_user_value`].
|
||||
/// Instead of placing a [`RegistryKey`] into a [`UserData`] type, prefer instead to use
|
||||
/// [`AnyUserData::set_user_value`] / [`AnyUserData::get_user_value`].
|
||||
///
|
||||
/// [`Lua::remove_registry_value`]: struct.Lua.html#method.remove_registry_value
|
||||
/// [`Lua::expire_registry_values`]: struct.Lua.html#method.expire_registry_values
|
||||
/// [`UserData::set_user_value`]: struct.UserData.html#method.set_user_value
|
||||
/// [`UserData::get_user_value`]: struct.UserData.html#method.get_user_value
|
||||
/// [`UserData`]: crate::UserData
|
||||
/// [`RegistryKey`]: crate::RegistryKey
|
||||
/// [`Lua::remove_registry_value`]: crate::Lua::remove_registry_value
|
||||
/// [`Lua::expire_registry_values`]: crate::Lua::expire_registry_values
|
||||
/// [`AnyUserData::set_user_value`]: crate::AnyUserData::set_user_value
|
||||
/// [`AnyUserData::get_user_value`]: crate::AnyUserData::get_user_value
|
||||
pub struct RegistryKey {
|
||||
pub(crate) registry_id: c_int,
|
||||
pub(crate) unref_list: Arc<Mutex<Option<Vec<c_int>>>>,
|
||||
@@ -139,7 +167,9 @@ impl<'lua> Clone for LuaRef<'lua> {
|
||||
|
||||
impl<'lua> Drop for LuaRef<'lua> {
|
||||
fn drop(&mut self) {
|
||||
self.lua.drop_ref(self)
|
||||
if self.index > 0 {
|
||||
self.lua.drop_ref(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+383
-135
@@ -3,6 +3,7 @@ use std::cell::{Ref, RefCell, RefMut};
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::raw::{c_char, c_int};
|
||||
use std::string::String as StdString;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
@@ -11,7 +12,6 @@ use std::future::Future;
|
||||
#[cfg(feature = "serialize")]
|
||||
use {
|
||||
serde::ser::{self, Serialize, Serializer},
|
||||
std::os::raw::c_void,
|
||||
std::result::Result as StdResult,
|
||||
};
|
||||
|
||||
@@ -21,23 +21,21 @@ use crate::function::Function;
|
||||
use crate::lua::Lua;
|
||||
use crate::table::{Table, TablePairs};
|
||||
use crate::types::{Callback, LuaRef, MaybeSend};
|
||||
use crate::util::{
|
||||
check_stack, get_destructed_userdata_metatable, get_userdata, push_string, StackGuard,
|
||||
};
|
||||
use crate::util::{check_stack, get_userdata, take_userdata, StackGuard};
|
||||
use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti};
|
||||
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
use crate::value::Value;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
use crate::types::AsyncCallback;
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
pub(crate) const USER_VALUE_MAXSLOT: usize = 8;
|
||||
|
||||
/// Kinds of metamethods that can be overridden.
|
||||
///
|
||||
/// Currently, this mechanism does not allow overriding the `__gc` metamethod, since there is
|
||||
/// generally no need to do so: [`UserData`] implementors can instead just implement `Drop`.
|
||||
///
|
||||
/// [`UserData`]: trait.UserData.html
|
||||
/// [`UserData`]: crate::UserData
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum MetaMethod {
|
||||
/// The `+` operator.
|
||||
@@ -56,29 +54,29 @@ pub enum MetaMethod {
|
||||
Unm,
|
||||
/// The floor division (//) operator.
|
||||
/// Requires `feature = "lua54/lua53"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
IDiv,
|
||||
/// The bitwise AND (&) operator.
|
||||
/// Requires `feature = "lua54/lua53"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
BAnd,
|
||||
/// The bitwise OR (|) operator.
|
||||
/// Requires `feature = "lua54/lua53"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
BOr,
|
||||
/// The bitwise XOR (binary ~) operator.
|
||||
/// Requires `feature = "lua54/lua53"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
BXor,
|
||||
/// The bitwise NOT (unary ~) operator.
|
||||
/// Requires `feature = "lua54/lua53"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
BNot,
|
||||
/// The bitwise left shift (<<) operator.
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
Shl,
|
||||
/// The bitwise right shift (>>) operator.
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
Shr,
|
||||
/// The string concatenation operator `..`.
|
||||
Concat,
|
||||
@@ -105,7 +103,12 @@ pub enum MetaMethod {
|
||||
/// This is not an operator, but it will be called by the built-in `pairs` function.
|
||||
///
|
||||
/// Requires `feature = "lua54/lua53/lua52"`
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", doc))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luajit52",
|
||||
))]
|
||||
Pairs,
|
||||
/// The `__ipairs` metamethod.
|
||||
///
|
||||
@@ -114,8 +117,18 @@ pub enum MetaMethod {
|
||||
/// Requires `feature = "lua52"`
|
||||
///
|
||||
/// [`ipairs`]: https://www.lua.org/manual/5.2/manual.html#pdf-ipairs
|
||||
#[cfg(any(feature = "lua52", doc))]
|
||||
#[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.
|
||||
@@ -126,7 +139,7 @@ pub enum MetaMethod {
|
||||
/// Requires `feature = "lua54"`
|
||||
///
|
||||
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#3.3.8
|
||||
#[cfg(any(feature = "lua54", doc))]
|
||||
#[cfg(any(feature = "lua54"))]
|
||||
Close,
|
||||
/// A custom metamethod.
|
||||
///
|
||||
@@ -191,10 +204,17 @@ impl MetaMethod {
|
||||
MetaMethod::Call => "__call",
|
||||
MetaMethod::ToString => "__tostring",
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luajit52"
|
||||
))]
|
||||
MetaMethod::Pairs => "__pairs",
|
||||
#[cfg(feature = "lua52")]
|
||||
#[cfg(any(feature = "lua52", feature = "luajit52"))]
|
||||
MetaMethod::IPairs => "__ipairs",
|
||||
#[cfg(feature = "luau")]
|
||||
MetaMethod::Iter => "__iter",
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
MetaMethod::Close => "__close",
|
||||
@@ -253,10 +273,17 @@ impl From<StdString> for MetaMethod {
|
||||
"__call" => MetaMethod::Call,
|
||||
"__tostring" => MetaMethod::ToString,
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luajit52"
|
||||
))]
|
||||
"__pairs" => MetaMethod::Pairs,
|
||||
#[cfg(feature = "lua52")]
|
||||
#[cfg(any(feature = "lua52", feature = "luajit52"))]
|
||||
"__ipairs" => MetaMethod::IPairs,
|
||||
#[cfg(feature = "luau")]
|
||||
"__iter" => MetaMethod::Iter,
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
"__close" => MetaMethod::Close,
|
||||
@@ -274,7 +301,7 @@ impl From<&str> for MetaMethod {
|
||||
|
||||
/// Method registry for [`UserData`] implementors.
|
||||
///
|
||||
/// [`UserData`]: trait.UserData.html
|
||||
/// [`UserData`]: crate::UserData
|
||||
pub trait UserDataMethods<'lua, T: UserData> {
|
||||
/// Add a regular method which accepts a `&T` as the first parameter.
|
||||
///
|
||||
@@ -328,7 +355,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
||||
///
|
||||
/// Prefer to use [`add_method`] or [`add_method_mut`] as they are easier to use.
|
||||
///
|
||||
/// [`AnyUserData`]: struct.AnyUserData.html
|
||||
/// [`AnyUserData`]: crate::AnyUserData
|
||||
/// [`add_method`]: #method.add_method
|
||||
/// [`add_method_mut`]: #method.add_method_mut
|
||||
fn add_function<S, A, R, F>(&mut self, name: &S, function: F)
|
||||
@@ -398,6 +425,25 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
||||
R: ToLuaMulti<'lua>,
|
||||
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
|
||||
|
||||
/// Add an async metamethod which accepts a `T` as the first parameter and returns Future.
|
||||
/// The passed `T` is cloned from the original value.
|
||||
///
|
||||
/// This is an async version of [`add_meta_method`].
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`add_meta_method`]: #method.add_meta_method
|
||||
#[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
|
||||
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>>;
|
||||
|
||||
/// Add a metamethod which accepts generic arguments.
|
||||
///
|
||||
/// Metamethods for binary operators can be triggered if either the left or right argument to
|
||||
@@ -422,6 +468,23 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>;
|
||||
|
||||
/// Add a metamethod which accepts generic arguments and returns Future.
|
||||
///
|
||||
/// This is an async version of [`add_meta_function`].
|
||||
///
|
||||
/// Requires `feature = "async"`
|
||||
///
|
||||
/// [`add_meta_function`]: #method.add_meta_function
|
||||
#[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
|
||||
S: Into<MetaMethod>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
|
||||
FR: 'lua + Future<Output = Result<R>>;
|
||||
|
||||
//
|
||||
// Below are internal methods used in generated code
|
||||
//
|
||||
@@ -435,11 +498,20 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
||||
|
||||
#[doc(hidden)]
|
||||
fn add_meta_callback(&mut self, _meta: MetaMethod, _callback: Callback<'lua, 'static>) {}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "async")]
|
||||
fn add_async_meta_callback(
|
||||
&mut self,
|
||||
_meta: MetaMethod,
|
||||
_callback: AsyncCallback<'lua, 'static>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Field registry for [`UserData`] implementors.
|
||||
///
|
||||
/// [`UserData`]: trait.UserData.html
|
||||
/// [`UserData`]: crate::UserData
|
||||
pub trait UserDataFields<'lua, T: UserData> {
|
||||
/// Add a regular field getter as a method which accepts a `&T` as the parameter.
|
||||
///
|
||||
@@ -472,7 +544,7 @@ pub trait UserDataFields<'lua, T: UserData> {
|
||||
///
|
||||
/// Prefer to use [`add_field_method_get`] as it is easier to use.
|
||||
///
|
||||
/// [`AnyUserData`]: struct.AnyUserData.html
|
||||
/// [`AnyUserData`]: crate::AnyUserData
|
||||
/// [`add_field_method_get`]: #method.add_field_method_get
|
||||
fn add_field_function_get<S, R, F>(&mut self, name: &S, function: F)
|
||||
where
|
||||
@@ -485,7 +557,7 @@ pub trait UserDataFields<'lua, T: UserData> {
|
||||
///
|
||||
/// Prefer to use [`add_field_method_set`] as it is easier to use.
|
||||
///
|
||||
/// [`AnyUserData`]: struct.AnyUserData.html
|
||||
/// [`AnyUserData`]: crate::AnyUserData
|
||||
/// [`add_field_method_set`]: #method.add_field_method_set
|
||||
fn add_field_function_set<S, A, F>(&mut self, name: &S, function: F)
|
||||
where
|
||||
@@ -581,10 +653,10 @@ pub trait UserDataFields<'lua, T: UserData> {
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`ToLua`]: trait.ToLua.html
|
||||
/// [`FromLua`]: trait.FromLua.html
|
||||
/// [`UserDataFields`]: trait.UserDataFields.html
|
||||
/// [`UserDataMethods`]: trait.UserDataMethods.html
|
||||
/// [`ToLua`]: crate::ToLua
|
||||
/// [`FromLua`]: crate::FromLua
|
||||
/// [`UserDataFields`]: crate::UserDataFields
|
||||
/// [`UserDataMethods`]: crate::UserDataMethods
|
||||
pub trait UserData: Sized {
|
||||
/// Adds custom fields specific to this userdata.
|
||||
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(_fields: &mut F) {}
|
||||
@@ -597,11 +669,13 @@ pub trait UserData: Sized {
|
||||
pub(crate) struct UserDataCell<T>(RefCell<UserDataWrapped<T>>);
|
||||
|
||||
impl<T> UserDataCell<T> {
|
||||
#[inline]
|
||||
pub(crate) fn new(data: T) -> Self {
|
||||
UserDataCell(RefCell::new(UserDataWrapped::new(data)))
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
#[inline]
|
||||
pub(crate) fn new_ser(data: T) -> Self
|
||||
where
|
||||
T: 'static + Serialize,
|
||||
@@ -610,7 +684,8 @@ impl<T> UserDataCell<T> {
|
||||
}
|
||||
|
||||
// Immutably borrows the wrapped value.
|
||||
fn try_borrow(&self) -> Result<Ref<T>> {
|
||||
#[inline]
|
||||
pub(crate) fn try_borrow(&self) -> Result<Ref<T>> {
|
||||
self.0
|
||||
.try_borrow()
|
||||
.map(|r| Ref::map(r, |r| r.deref()))
|
||||
@@ -618,40 +693,48 @@ impl<T> UserDataCell<T> {
|
||||
}
|
||||
|
||||
// Mutably borrows the wrapped value.
|
||||
fn try_borrow_mut(&self) -> Result<RefMut<T>> {
|
||||
#[inline]
|
||||
pub(crate) fn try_borrow_mut(&self) -> Result<RefMut<T>> {
|
||||
self.0
|
||||
.try_borrow_mut()
|
||||
.map(|r| RefMut::map(r, |r| r.deref_mut()))
|
||||
.map_err(|_| Error::UserDataBorrowMutError)
|
||||
}
|
||||
|
||||
// Consumes this `UserDataCell`, returning the wrapped value.
|
||||
#[inline]
|
||||
fn into_inner(self) -> T {
|
||||
self.0.into_inner().into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum UserDataWrapped<T> {
|
||||
Default(T),
|
||||
Default(Box<T>),
|
||||
#[cfg(feature = "serialize")]
|
||||
Serializable(*mut T, *const dyn erased_serde::Serialize),
|
||||
Serializable(Box<dyn erased_serde::Serialize>),
|
||||
}
|
||||
|
||||
impl<T> UserDataWrapped<T> {
|
||||
#[inline]
|
||||
fn new(data: T) -> Self {
|
||||
UserDataWrapped::Default(data)
|
||||
UserDataWrapped::Default(Box::new(data))
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
#[inline]
|
||||
fn new_ser(data: T) -> Self
|
||||
where
|
||||
T: 'static + Serialize,
|
||||
{
|
||||
let data_raw = Box::into_raw(Box::new(data));
|
||||
UserDataWrapped::Serializable(data_raw, data_raw)
|
||||
UserDataWrapped::Serializable(Box::new(data))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
impl<T> Drop for UserDataWrapped<T> {
|
||||
fn drop(&mut self) {
|
||||
if let UserDataWrapped::Serializable(data, _) = *self {
|
||||
drop(unsafe { Box::from_raw(data) });
|
||||
#[inline]
|
||||
fn into_inner(self) -> T {
|
||||
match self {
|
||||
Self::Default(data) => *data,
|
||||
#[cfg(feature = "serialize")]
|
||||
Self::Serializable(data) => unsafe { *Box::from_raw(Box::into_raw(data) as *mut T) },
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -659,21 +742,27 @@ impl<T> Drop for UserDataWrapped<T> {
|
||||
impl<T> Deref for UserDataWrapped<T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
Self::Default(data) => data,
|
||||
#[cfg(feature = "serialize")]
|
||||
Self::Serializable(data, _) => unsafe { &**data },
|
||||
Self::Serializable(data) => unsafe {
|
||||
&*(data.as_ref() as *const _ as *const Self::Target)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for UserDataWrapped<T> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
match self {
|
||||
Self::Default(data) => data,
|
||||
#[cfg(feature = "serialize")]
|
||||
Self::Serializable(data, _) => unsafe { &mut **data },
|
||||
Self::Serializable(data) => unsafe {
|
||||
&mut *(data.as_mut() as *mut _ as *mut Self::Target)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -704,9 +793,9 @@ impl Serialize for UserDataSerializeError {
|
||||
/// This API should only be used when necessary. Implementing [`UserData`] already allows defining
|
||||
/// methods which check the type and acquire a borrow behind the scenes.
|
||||
///
|
||||
/// [`UserData`]: trait.UserData.html
|
||||
/// [`is`]: #method.is
|
||||
/// [`borrow`]: #method.borrow
|
||||
/// [`UserData`]: crate::UserData
|
||||
/// [`is`]: crate::AnyUserData::is
|
||||
/// [`borrow`]: crate::AnyUserData::borrow
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AnyUserData<'lua>(pub(crate) LuaRef<'lua>);
|
||||
|
||||
@@ -726,6 +815,7 @@ impl<'lua> AnyUserData<'lua> {
|
||||
///
|
||||
/// Returns a `UserDataBorrowError` if the userdata is already mutably borrowed. Returns a
|
||||
/// `UserDataTypeMismatch` if the userdata is not of type `T`.
|
||||
#[inline]
|
||||
pub fn borrow<T: 'static + UserData>(&self) -> Result<Ref<T>> {
|
||||
self.inspect(|cell| cell.try_borrow())
|
||||
}
|
||||
@@ -736,61 +826,244 @@ impl<'lua> AnyUserData<'lua> {
|
||||
///
|
||||
/// Returns a `UserDataBorrowMutError` if the userdata cannot be mutably borrowed.
|
||||
/// Returns a `UserDataTypeMismatch` if the userdata is not of type `T`.
|
||||
#[inline]
|
||||
pub fn borrow_mut<T: 'static + UserData>(&self) -> Result<RefMut<T>> {
|
||||
self.inspect(|cell| cell.try_borrow_mut())
|
||||
}
|
||||
|
||||
/// Takes out the value of `UserData` and sets the special "destructed" metatable that prevents
|
||||
/// any further operations with this userdata.
|
||||
///
|
||||
/// All associated user values will be also cleared.
|
||||
pub fn take<T: 'static + UserData>(&self) -> Result<T> {
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 3)?;
|
||||
|
||||
let type_id = lua.push_userdata_ref(&self.0)?;
|
||||
match type_id {
|
||||
Some(type_id) if type_id == TypeId::of::<T>() => {
|
||||
// Try to borrow userdata exclusively
|
||||
let _ = (*get_userdata::<UserDataCell<T>>(lua.state, -1)).try_borrow_mut()?;
|
||||
|
||||
// Clear associated user values
|
||||
#[cfg(feature = "lua54")]
|
||||
for i in 1..=USER_VALUE_MAXSLOT {
|
||||
ffi::lua_pushnil(lua.state);
|
||||
ffi::lua_setiuservalue(lua.state, -2, i as c_int);
|
||||
}
|
||||
#[cfg(any(feature = "lua53", feature = "lua52", feature = "luau"))]
|
||||
{
|
||||
ffi::lua_pushnil(lua.state);
|
||||
ffi::lua_setuservalue(lua.state, -2);
|
||||
}
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
protect_lua!(lua.state, 1, 1, fn(state) {
|
||||
ffi::lua_newtable(state);
|
||||
ffi::lua_setuservalue(state, -2);
|
||||
})?;
|
||||
|
||||
Ok(take_userdata::<UserDataCell<T>>(lua.state).into_inner())
|
||||
}
|
||||
_ => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets an associated value to this `AnyUserData`.
|
||||
///
|
||||
/// The value may be any Lua value whatsoever, and can be retrieved with [`get_user_value`].
|
||||
/// As Lua < 5.3 allows to store only tables, the value will be stored in a table at index 1.
|
||||
///
|
||||
/// This is the same as calling [`set_nth_user_value`] with `n` set to 1.
|
||||
///
|
||||
/// [`get_user_value`]: #method.get_user_value
|
||||
/// [`set_nth_user_value`]: #method.set_nth_user_value
|
||||
#[inline]
|
||||
pub fn set_user_value<V: ToLua<'lua>>(&self, v: V) -> Result<()> {
|
||||
self.set_nth_user_value(1, v)
|
||||
}
|
||||
|
||||
/// Returns an associated value set by [`set_user_value`].
|
||||
///
|
||||
/// This is the same as calling [`get_nth_user_value`] with `n` set to 1.
|
||||
///
|
||||
/// [`set_user_value`]: #method.set_user_value
|
||||
/// [`get_nth_user_value`]: #method.get_nth_user_value
|
||||
#[inline]
|
||||
pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> {
|
||||
self.get_nth_user_value(1)
|
||||
}
|
||||
|
||||
/// Sets an associated `n`th value to this `AnyUserData`.
|
||||
///
|
||||
/// The value may be any Lua value whatsoever, and can be retrieved with [`get_nth_user_value`].
|
||||
/// `n` starts from 1 and can be up to 65535.
|
||||
///
|
||||
/// This is supported for all Lua versions.
|
||||
/// In Lua 5.4 first 7 elements are stored in a most efficient way.
|
||||
/// For other Lua versions this functionality is provided using a wrapping table.
|
||||
///
|
||||
/// [`get_nth_user_value`]: #method.get_nth_user_value
|
||||
pub fn set_nth_user_value<V: ToLua<'lua>>(&self, n: usize, v: V) -> Result<()> {
|
||||
if n < 1 || n > u16::MAX as usize {
|
||||
return Err(Error::RuntimeError(
|
||||
"user value index out of bounds".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let lua = self.0.lua;
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
let v = {
|
||||
// Lua <= 5.2 allows to store only a table. Then we will wrap the value.
|
||||
let t = lua.create_table_with_capacity(1, 0)?;
|
||||
t.raw_set(1, v)?;
|
||||
Value::Table(t)
|
||||
};
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
let v = v.to_lua(lua)?;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 3)?;
|
||||
check_stack(lua.state, 5)?;
|
||||
|
||||
lua.push_userdata_ref(&self.0, false)?;
|
||||
lua.push_value(v)?;
|
||||
ffi::lua_setuservalue(lua.state, -2);
|
||||
lua.push_userdata_ref(&self.0)?;
|
||||
lua.push_value(v.to_lua(lua)?)?;
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
if n < USER_VALUE_MAXSLOT {
|
||||
ffi::lua_setiuservalue(lua.state, -2, n as c_int);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Multiple (extra) user values are emulated by storing them in a table
|
||||
protect_lua!(lua.state, 2, 0, |state| {
|
||||
if getuservalue_table(state, -2) != ffi::LUA_TTABLE {
|
||||
// Create a new table to use as uservalue
|
||||
ffi::lua_pop(state, 1);
|
||||
ffi::lua_newtable(state);
|
||||
ffi::lua_pushvalue(state, -1);
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
ffi::lua_setiuservalue(state, -4, USER_VALUE_MAXSLOT as c_int);
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
ffi::lua_setuservalue(state, -4);
|
||||
}
|
||||
ffi::lua_pushvalue(state, -2);
|
||||
#[cfg(feature = "lua54")]
|
||||
ffi::lua_rawseti(state, -2, (n - USER_VALUE_MAXSLOT + 1) as ffi::lua_Integer);
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
ffi::lua_rawseti(state, -2, n as ffi::lua_Integer);
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an associated value set by [`set_user_value`].
|
||||
/// Returns an associated `n`th value set by [`set_nth_user_value`].
|
||||
///
|
||||
/// For Lua < 5.3 the value will be automatically extracted from the table wrapper from index 1.
|
||||
/// `n` starts from 1 and can be up to 65535.
|
||||
///
|
||||
/// [`set_user_value`]: #method.set_user_value
|
||||
pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> {
|
||||
let lua = self.0.lua;
|
||||
let res = unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 3)?;
|
||||
/// This is supported for all Lua versions.
|
||||
/// In Lua 5.4 first 7 elements are stored in a most efficient way.
|
||||
/// For other Lua versions this functionality is provided using a wrapping table.
|
||||
///
|
||||
/// [`set_nth_user_value`]: #method.set_nth_user_value
|
||||
pub fn get_nth_user_value<V: FromLua<'lua>>(&self, n: usize) -> Result<V> {
|
||||
if n < 1 || n > u16::MAX as usize {
|
||||
return Err(Error::RuntimeError(
|
||||
"user value index out of bounds".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
lua.push_userdata_ref(&self.0, false)?;
|
||||
ffi::lua_getuservalue(lua.state, -1);
|
||||
lua.pop_value()
|
||||
};
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
return match <Option<Table>>::from_lua(res, lua)? {
|
||||
Some(t) => t.get(1),
|
||||
None => V::from_lua(Value::Nil, lua),
|
||||
};
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
V::from_lua(res, lua)
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 4)?;
|
||||
|
||||
lua.push_userdata_ref(&self.0)?;
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
if n < USER_VALUE_MAXSLOT {
|
||||
ffi::lua_getiuservalue(lua.state, -1, n as c_int);
|
||||
return V::from_lua(lua.pop_value(), lua);
|
||||
}
|
||||
|
||||
// Multiple (extra) user values are emulated by storing them in a table
|
||||
protect_lua!(lua.state, 1, 1, |state| {
|
||||
if getuservalue_table(state, -1) != ffi::LUA_TTABLE {
|
||||
ffi::lua_pushnil(state);
|
||||
return;
|
||||
}
|
||||
#[cfg(feature = "lua54")]
|
||||
ffi::lua_rawgeti(state, -1, (n - USER_VALUE_MAXSLOT + 1) as ffi::lua_Integer);
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
ffi::lua_rawgeti(state, -1, n as ffi::lua_Integer);
|
||||
})?;
|
||||
|
||||
V::from_lua(lua.pop_value(), lua)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets an associated value to this `AnyUserData` by name.
|
||||
///
|
||||
/// The value can be retrieved with [`get_named_user_value`].
|
||||
///
|
||||
/// [`get_named_user_value`]: #method.get_named_user_value
|
||||
pub fn set_named_user_value<S, V>(&self, name: &S, v: V) -> Result<()>
|
||||
where
|
||||
S: AsRef<[u8]> + ?Sized,
|
||||
V: ToLua<'lua>,
|
||||
{
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 5)?;
|
||||
|
||||
lua.push_userdata_ref(&self.0)?;
|
||||
lua.push_value(v.to_lua(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(state, -2) != ffi::LUA_TTABLE {
|
||||
// Create a new table to use as uservalue
|
||||
ffi::lua_pop(state, 1);
|
||||
ffi::lua_newtable(state);
|
||||
ffi::lua_pushvalue(state, -1);
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
ffi::lua_setiuservalue(state, -4, USER_VALUE_MAXSLOT as c_int);
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
ffi::lua_setuservalue(state, -4);
|
||||
}
|
||||
ffi::lua_pushlstring(state, name.as_ptr() as *const c_char, name.len());
|
||||
ffi::lua_pushvalue(state, -3);
|
||||
ffi::lua_rawset(state, -3);
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an associated value by name set by [`set_named_user_value`].
|
||||
///
|
||||
/// [`set_named_user_value`]: #method.set_named_user_value
|
||||
pub fn get_named_user_value<S, V>(&self, name: &S) -> Result<V>
|
||||
where
|
||||
S: AsRef<[u8]> + ?Sized,
|
||||
V: FromLua<'lua>,
|
||||
{
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 4)?;
|
||||
|
||||
lua.push_userdata_ref(&self.0)?;
|
||||
|
||||
// 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(state, -1) != ffi::LUA_TTABLE {
|
||||
ffi::lua_pushnil(state);
|
||||
return;
|
||||
}
|
||||
ffi::lua_pushlstring(state, name.as_ptr() as *const c_char, name.len());
|
||||
ffi::lua_rawget(state, -2);
|
||||
})?;
|
||||
|
||||
V::from_lua(lua.pop_value(), lua)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a metatable of this `UserData`.
|
||||
@@ -800,7 +1073,7 @@ impl<'lua> AnyUserData<'lua> {
|
||||
///
|
||||
/// For `T: UserData + 'static` returned metatable is shared among all instances of type `T`.
|
||||
///
|
||||
/// [`UserDataMetatable`]: struct.UserDataMetatable.html
|
||||
/// [`UserDataMetatable`]: crate::UserDataMetatable
|
||||
pub fn get_metatable(&self) -> Result<UserDataMetatable<'lua>> {
|
||||
self.get_raw_metatable().map(UserDataMetatable)
|
||||
}
|
||||
@@ -811,7 +1084,7 @@ impl<'lua> AnyUserData<'lua> {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 3)?;
|
||||
|
||||
lua.push_userdata_ref(&self.0, false)?;
|
||||
lua.push_userdata_ref(&self.0)?;
|
||||
ffi::lua_getmetatable(lua.state, -1); // Checked that non-empty on the previous call
|
||||
Ok(Table(lua.pop_ref()))
|
||||
}
|
||||
@@ -838,25 +1111,6 @@ impl<'lua> AnyUserData<'lua> {
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
pub(crate) fn type_id(&self) -> Result<TypeId> {
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 5)?;
|
||||
|
||||
// Push userdata with metatable
|
||||
lua.push_userdata_ref(&self.0, true)?;
|
||||
|
||||
// Get the special `__mlua_type_id`
|
||||
push_string(lua.state, "__mlua_type_id")?;
|
||||
if ffi::lua_rawget(lua.state, -2) != ffi::LUA_TUSERDATA {
|
||||
return Err(Error::UserDataTypeMismatch);
|
||||
}
|
||||
|
||||
Ok(*(ffi::lua_touserdata(lua.state, -1) as *const TypeId))
|
||||
}
|
||||
}
|
||||
|
||||
fn inspect<'a, T, R, F>(&'a self, func: F) -> Result<R>
|
||||
where
|
||||
T: 'static + UserData,
|
||||
@@ -865,25 +1119,14 @@ impl<'lua> AnyUserData<'lua> {
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 3)?;
|
||||
check_stack(lua.state, 2)?;
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
if ffi::lua_getmetatable(lua.state, -1) == 0 {
|
||||
return Err(Error::UserDataTypeMismatch);
|
||||
}
|
||||
lua.push_userdata_metatable::<T>()?;
|
||||
|
||||
if ffi::lua_rawequal(lua.state, -1, -2) == 0 {
|
||||
// Maybe UserData destructed?
|
||||
ffi::lua_pop(lua.state, 1);
|
||||
get_destructed_userdata_metatable(lua.state);
|
||||
if ffi::lua_rawequal(lua.state, -1, -2) == 1 {
|
||||
Err(Error::UserDataDestructed)
|
||||
} else {
|
||||
Err(Error::UserDataTypeMismatch)
|
||||
let type_id = lua.push_userdata_ref(&self.0)?;
|
||||
match type_id {
|
||||
Some(type_id) if type_id == TypeId::of::<T>() => {
|
||||
func(&*get_userdata::<UserDataCell<T>>(lua.state, -1))
|
||||
}
|
||||
} else {
|
||||
func(&*get_userdata::<UserDataCell<T>>(lua.state, -3))
|
||||
_ => Err(Error::UserDataTypeMismatch),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -902,6 +1145,13 @@ impl<'lua> AsRef<AnyUserData<'lua>> for AnyUserData<'lua> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn getuservalue_table(state: *mut ffi::lua_State, idx: c_int) -> c_int {
|
||||
#[cfg(feature = "lua54")]
|
||||
return ffi::lua_getiuservalue(state, idx, USER_VALUE_MAXSLOT as c_int);
|
||||
#[cfg(not(feature = "lua54"))]
|
||||
return ffi::lua_getuservalue(state, idx);
|
||||
}
|
||||
|
||||
/// Handle to a `UserData` metatable.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UserDataMetatable<'lua>(pub(crate) Table<'lua>);
|
||||
@@ -939,7 +1189,7 @@ impl<'lua> UserDataMetatable<'lua> {
|
||||
///
|
||||
/// The pairs are wrapped in a [`Result`], since they are lazily converted to `V` type.
|
||||
///
|
||||
/// [`Result`]: type.Result.html
|
||||
/// [`Result`]: crate::Result
|
||||
pub fn pairs<V: FromLua<'lua>>(self) -> UserDataMetatablePairs<'lua, V> {
|
||||
UserDataMetatablePairs(self.0.pairs())
|
||||
}
|
||||
@@ -951,8 +1201,8 @@ impl<'lua> UserDataMetatable<'lua> {
|
||||
///
|
||||
/// This struct is created by the [`UserDataMetatable::pairs`] method.
|
||||
///
|
||||
/// [`UserData`]: trait.UserData.html
|
||||
/// [`UserDataMetatable::pairs`]: struct.UserDataMetatable.html#method.pairs
|
||||
/// [`UserData`]: crate::UserData
|
||||
/// [`UserDataMetatable::pairs`]: crate::UserDataMetatable::method.pairs
|
||||
pub struct UserDataMetatablePairs<'lua, V>(TablePairs<'lua, StdString, V>);
|
||||
|
||||
impl<'lua, V> Iterator for UserDataMetatablePairs<'lua, V>
|
||||
@@ -982,21 +1232,19 @@ impl<'lua> Serialize for AnyUserData<'lua> {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
unsafe {
|
||||
let lua = self.0.lua;
|
||||
let lua = self.0.lua;
|
||||
let data = unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 3).map_err(ser::Error::custom)?;
|
||||
|
||||
lua.push_userdata_ref(&self.0, false)
|
||||
.map_err(ser::Error::custom)?;
|
||||
let ud = &*get_userdata::<UserDataCell<c_void>>(lua.state, -1);
|
||||
let data =
|
||||
ud.0.try_borrow()
|
||||
.map_err(|_| ser::Error::custom(Error::UserDataBorrowError))?;
|
||||
match *data {
|
||||
UserDataWrapped::Default(_) => UserDataSerializeError.serialize(serializer),
|
||||
UserDataWrapped::Serializable(_, ser) => (&*ser).serialize(serializer),
|
||||
}
|
||||
lua.push_userdata_ref(&self.0).map_err(ser::Error::custom)?;
|
||||
let ud = &*get_userdata::<UserDataCell<()>>(lua.state, -1);
|
||||
ud.0.try_borrow()
|
||||
.map_err(|_| ser::Error::custom(Error::UserDataBorrowError))?
|
||||
};
|
||||
match &*data {
|
||||
UserDataWrapped::Default(_) => UserDataSerializeError.serialize(serializer),
|
||||
UserDataWrapped::Serializable(ser) => ser.serialize(serializer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>);
|
||||
+382
-206
@@ -1,24 +1,29 @@
|
||||
use std::any::{Any, TypeId};
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error as StdError;
|
||||
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, Mutex};
|
||||
use std::sync::Arc;
|
||||
use std::{mem, ptr, slice};
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
|
||||
static METATABLE_CACHE: Lazy<Mutex<HashMap<TypeId, u8>>> = Lazy::new(|| {
|
||||
// The capacity must(!) be greater than number of stored keys
|
||||
Mutex::new(HashMap::with_capacity(32))
|
||||
static METATABLE_CACHE: Lazy<FxHashMap<TypeId, u8>> = Lazy::new(|| {
|
||||
let mut map = FxHashMap::with_capacity_and_hasher(32, Default::default());
|
||||
crate::lua::init_metatable_cache(&mut map);
|
||||
map.insert(TypeId::of::<WrappedFailure>(), 0);
|
||||
map.insert(TypeId::of::<String>(), 0);
|
||||
map
|
||||
});
|
||||
|
||||
// Checks that Lua has enough free stack space for future stack operations. On failure, this will
|
||||
// panic with an internal error message.
|
||||
#[inline]
|
||||
pub unsafe fn assert_stack(state: *mut ffi::lua_State, amount: c_int) {
|
||||
// TODO: This should only be triggered when there is a logic error in `mlua`. In the future,
|
||||
// when there is a way to be confident about stack safety and test it, this could be enabled
|
||||
@@ -30,6 +35,7 @@ pub unsafe fn assert_stack(state: *mut ffi::lua_State, amount: c_int) {
|
||||
}
|
||||
|
||||
// Checks that Lua has enough free stack space and returns `Error::StackError` on failure.
|
||||
#[inline]
|
||||
pub unsafe fn check_stack(state: *mut ffi::lua_State, amount: c_int) -> Result<()> {
|
||||
if ffi::lua_checkstack(state, amount) == 0 {
|
||||
Err(Error::StackError)
|
||||
@@ -48,6 +54,7 @@ impl StackGuard {
|
||||
// Creates a StackGuard instance with record of the stack size, and on Drop will check the
|
||||
// stack size and drop any extra elements. If the stack size at the end is *smaller* than at
|
||||
// the beginning, this is considered a fatal logic error and will result in a panic.
|
||||
#[inline]
|
||||
pub unsafe fn new(state: *mut ffi::lua_State) -> StackGuard {
|
||||
StackGuard {
|
||||
state,
|
||||
@@ -57,6 +64,7 @@ impl StackGuard {
|
||||
}
|
||||
|
||||
// Similar to `new`, but checks and keeps `extra` elements from top of the stack on Drop.
|
||||
#[inline]
|
||||
pub unsafe fn new_extra(state: *mut ffi::lua_State, extra: c_int) -> StackGuard {
|
||||
StackGuard {
|
||||
state,
|
||||
@@ -83,6 +91,35 @@ impl Drop for StackGuard {
|
||||
}
|
||||
}
|
||||
|
||||
// Call a function that calls into the Lua API and may trigger a Lua error (longjmp) in a safe way.
|
||||
// Wraps the inner function in a call to `lua_pcall`, so the inner function only has access to a
|
||||
// limited lua stack. `nargs` is the same as the the parameter to `lua_pcall`, and `nresults` is
|
||||
// always `LUA_MULTRET`. Provided function must *not* panic, and since it will generally be lonjmping,
|
||||
// should not contain any values that implements Drop.
|
||||
// Internally uses 2 extra stack spaces, and does not call checkstack.
|
||||
pub unsafe fn protect_lua_call(
|
||||
state: *mut ffi::lua_State,
|
||||
nargs: c_int,
|
||||
f: unsafe extern "C" fn(*mut ffi::lua_State) -> c_int,
|
||||
) -> Result<()> {
|
||||
let stack_start = ffi::lua_gettop(state) - nargs;
|
||||
|
||||
ffi::lua_pushcfunction(state, error_traceback);
|
||||
ffi::lua_pushcfunction(state, f);
|
||||
if nargs > 0 {
|
||||
ffi::lua_rotate(state, stack_start + 1, 2);
|
||||
}
|
||||
|
||||
let ret = ffi::lua_pcall(state, nargs, ffi::LUA_MULTRET, stack_start + 1);
|
||||
ffi::lua_remove(state, stack_start + 1);
|
||||
|
||||
if ret == ffi::LUA_OK {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(pop_error(state, ret))
|
||||
}
|
||||
}
|
||||
|
||||
// Call a function that calls into the Lua API and may trigger a Lua error (longjmp) in a safe way.
|
||||
// Wraps the inner function in a call to `lua_pcall`, so the inner function only has access to a
|
||||
// limited lua stack. `nargs` and `nresults` are similar to the parameters of `lua_pcall`, but the
|
||||
@@ -90,7 +127,7 @@ impl Drop for StackGuard {
|
||||
// values are assumed to match the `nresults` param. Provided function must *not* panic, and since it
|
||||
// will generally be lonjmping, should not contain any values that implements Drop.
|
||||
// Internally uses 3 extra stack spaces, and does not call checkstack.
|
||||
pub unsafe fn protect_lua<F, R>(
|
||||
pub unsafe fn protect_lua_closure<F, R>(
|
||||
state: *mut ffi::lua_State,
|
||||
nargs: c_int,
|
||||
nresults: c_int,
|
||||
@@ -100,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)
|
||||
@@ -138,7 +170,7 @@ where
|
||||
|
||||
let mut params = Params {
|
||||
function: f,
|
||||
result: URes { uninit: () },
|
||||
result: MaybeUninit::uninit(),
|
||||
nresults,
|
||||
};
|
||||
|
||||
@@ -149,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))
|
||||
}
|
||||
@@ -167,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()
|
||||
@@ -210,30 +242,48 @@ pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error {
|
||||
}
|
||||
}
|
||||
|
||||
// Uses 3 stack spaces
|
||||
// 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,
|
||||
protect: bool,
|
||||
) -> Result<()> {
|
||||
let s = s.as_ref();
|
||||
protect_lua(state, 0, 1, |state| {
|
||||
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
|
||||
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))
|
||||
// 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,
|
||||
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
|
||||
// Uses 4 stack spaces, does not call checkstack.
|
||||
pub unsafe fn rawset_field<S>(state: *mut ffi::lua_State, table: c_int, field: &S) -> Result<()>
|
||||
where
|
||||
S: AsRef<[u8]> + ?Sized,
|
||||
{
|
||||
let field = field.as_ref();
|
||||
ffi::lua_pushvalue(state, table);
|
||||
protect_lua(state, 2, 0, |state| {
|
||||
protect_lua!(state, 2, 0, |state| {
|
||||
ffi::lua_pushlstring(state, field.as_ptr() as *const c_char, field.len());
|
||||
ffi::lua_rotate(state, -3, 2);
|
||||
ffi::lua_rawset(state, -3);
|
||||
@@ -241,14 +291,62 @@ where
|
||||
}
|
||||
|
||||
// Internally uses 3 stack spaces, does not call checkstack.
|
||||
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> {
|
||||
let ud = protect_lua(state, 0, 1, |state| {
|
||||
#[cfg(not(feature = "luau"))]
|
||||
#[inline]
|
||||
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,
|
||||
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(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_userdata<T>(state: *mut ffi::lua_State, index: c_int) -> *mut T {
|
||||
let ud = ffi::lua_touserdata(state, index) as *mut T;
|
||||
mlua_debug_assert!(!ud.is_null(), "userdata pointer is null");
|
||||
@@ -266,35 +364,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.
|
||||
@@ -310,99 +542,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, "__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] {
|
||||
@@ -412,9 +559,9 @@ pub unsafe fn init_userdata_metatable<T>(
|
||||
ffi::lua_pushnil(state);
|
||||
}
|
||||
}
|
||||
protect_lua(state, 3, 1, |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),
|
||||
}
|
||||
@@ -423,14 +570,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, "__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, |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),
|
||||
}
|
||||
@@ -438,8 +587,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")?;
|
||||
@@ -449,6 +601,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
|
||||
@@ -483,7 +636,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))) {
|
||||
@@ -495,11 +648,8 @@ where
|
||||
ffi::lua_settop(state, 1);
|
||||
|
||||
let wrapped_error = ud as *mut WrappedFailure;
|
||||
ptr::write(wrapped_error, WrappedFailure::Error(err));
|
||||
get_gc_metatable::<WrappedFailure>(state);
|
||||
ffi::lua_setmetatable(state, -2);
|
||||
|
||||
// Convert to CallbackError and attach traceback
|
||||
// Build `CallbackError` with traceback
|
||||
let traceback = if ffi::lua_checkstack(state, ffi::LUA_TRACEBACK_STACK) != 0 {
|
||||
ffi::luaL_traceback(state, state, ptr::null(), 0);
|
||||
let traceback = to_string(state, -1);
|
||||
@@ -508,10 +658,13 @@ where
|
||||
} else {
|
||||
"<not enough stack space for traceback>".to_string()
|
||||
};
|
||||
if let WrappedFailure::Error(ref mut err) = *wrapped_error {
|
||||
let cause = Arc::new(err.clone());
|
||||
*err = Error::CallbackError { traceback, cause };
|
||||
}
|
||||
let cause = Arc::new(err);
|
||||
ptr::write(
|
||||
wrapped_error,
|
||||
WrappedFailure::Error(Error::CallbackError { traceback, cause }),
|
||||
);
|
||||
get_gc_metatable::<WrappedFailure>(state);
|
||||
ffi::lua_setmetatable(state, -2);
|
||||
|
||||
ffi::lua_error(state)
|
||||
}
|
||||
@@ -532,10 +685,10 @@ 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, 1);
|
||||
ffi::luaL_traceback(state, state, s, 0);
|
||||
ffi::lua_remove(state, -2);
|
||||
}
|
||||
}
|
||||
@@ -543,6 +696,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());
|
||||
@@ -559,7 +726,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);
|
||||
}
|
||||
@@ -575,7 +742,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 {
|
||||
@@ -605,7 +772,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);
|
||||
}
|
||||
@@ -636,6 +803,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.
|
||||
@@ -646,21 +815,13 @@ pub unsafe fn init_gc_metatable<T: Any>(
|
||||
) -> Result<()> {
|
||||
check_stack(state, 6)?;
|
||||
|
||||
let type_id = TypeId::of::<T>();
|
||||
let ref_addr = {
|
||||
let mut mt_cache = mlua_expect!(METATABLE_CACHE.lock(), "cannot lock metatable cache");
|
||||
mlua_assert!(
|
||||
mt_cache.capacity() - mt_cache.len() > 0,
|
||||
"out of metatable cache capacity"
|
||||
);
|
||||
mt_cache.insert(type_id, 0);
|
||||
&mt_cache[&type_id] as *const u8
|
||||
};
|
||||
push_table(state, 0, 3, true)?;
|
||||
|
||||
push_table(state, 0, 3)?;
|
||||
|
||||
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")?;
|
||||
@@ -669,8 +830,10 @@ pub unsafe fn init_gc_metatable<T: Any>(
|
||||
f(state)?;
|
||||
}
|
||||
|
||||
protect_lua(state, 1, 0, |state| {
|
||||
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, ref_addr as *mut c_void);
|
||||
let type_id = TypeId::of::<T>();
|
||||
let ref_addr = &METATABLE_CACHE[&type_id] as *const u8;
|
||||
protect_lua!(state, 1, 0, |state| {
|
||||
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, ref_addr as *const c_void);
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
@@ -678,10 +841,8 @@ pub unsafe fn init_gc_metatable<T: Any>(
|
||||
|
||||
pub unsafe fn get_gc_metatable<T: Any>(state: *mut ffi::lua_State) {
|
||||
let type_id = TypeId::of::<T>();
|
||||
let ref_addr = {
|
||||
let mt_cache = mlua_expect!(METATABLE_CACHE.lock(), "cannot lock metatable cache");
|
||||
mlua_expect!(mt_cache.get(&type_id), "gc metatable does not exist") as *const u8
|
||||
};
|
||||
let ref_addr =
|
||||
mlua_expect!(METATABLE_CACHE.get(&type_id), "gc metatable does not exist") as *const u8;
|
||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, ref_addr as *const c_void);
|
||||
}
|
||||
|
||||
@@ -695,7 +856,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);
|
||||
@@ -707,32 +868,6 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
||||
// be possible to make this consume arbitrary amounts of memory (for example, some
|
||||
// kind of recursive error structure?)
|
||||
let _ = write!(&mut (*err_buf), "{}", error);
|
||||
// Find first two sources that caused the error
|
||||
let mut source1 = error.source();
|
||||
let mut source0 = source1.and_then(|s| s.source());
|
||||
while let Some(source) = source0.and_then(|s| s.source()) {
|
||||
source1 = source0;
|
||||
source0 = Some(source);
|
||||
}
|
||||
match (source1, source0) {
|
||||
(_, Some(error0))
|
||||
if error0.to_string().contains("\nstack traceback:\n") =>
|
||||
{
|
||||
let _ = write!(&mut (*err_buf), "\ncaused by: {}", error0);
|
||||
}
|
||||
(Some(error1), Some(error0)) => {
|
||||
let _ = write!(&mut (*err_buf), "\ncaused by: {}", error0);
|
||||
let s = error1.to_string();
|
||||
if let Some(traceback) = s.splitn(2, "\nstack traceback:\n").nth(1) {
|
||||
let _ =
|
||||
write!(&mut (*err_buf), "\nstack traceback:\n{}", traceback);
|
||||
}
|
||||
}
|
||||
(Some(error1), None) => {
|
||||
let _ = write!(&mut (*err_buf), "\ncaused by: {}", error1);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(err_buf)
|
||||
}
|
||||
Some(WrappedFailure::Panic(Some(ref panic))) => {
|
||||
@@ -758,7 +893,7 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
||||
}
|
||||
}?;
|
||||
|
||||
push_string(state, &*err_buf)?;
|
||||
push_string(state, &*err_buf, true)?;
|
||||
(*err_buf).clear();
|
||||
|
||||
Ok(1)
|
||||
@@ -779,7 +914,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",
|
||||
@@ -812,10 +947,17 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
||||
"__newindex",
|
||||
"__call",
|
||||
"__tostring",
|
||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
#[cfg(any(
|
||||
feature = "lua54",
|
||||
feature = "lua53",
|
||||
feature = "lua52",
|
||||
feature = "luajit52"
|
||||
))]
|
||||
"__pairs",
|
||||
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||
#[cfg(any(feature = "lua53", feature = "lua52", feature = "luajit52"))]
|
||||
"__ipairs",
|
||||
#[cfg(feature = "luau")]
|
||||
"__iter",
|
||||
#[cfg(feature = "lua54")]
|
||||
"__close",
|
||||
] {
|
||||
@@ -824,15 +966,15 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
||||
}
|
||||
ffi::lua_pop(state, 1);
|
||||
|
||||
protect_lua(state, 1, 0, |state| {
|
||||
protect_lua!(state, 1, 0, fn(state) {
|
||||
let destructed_mt_key = &DESTRUCTED_USERDATA_METATABLE as *const u8 as *const c_void;
|
||||
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, destructed_mt_key);
|
||||
})?;
|
||||
|
||||
// Create error print buffer
|
||||
init_gc_metatable::<String>(state, None)?;
|
||||
push_gc_userdata(state, String::new())?;
|
||||
protect_lua(state, 1, 0, |state| {
|
||||
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);
|
||||
})?;
|
||||
@@ -841,10 +983,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 {
|
||||
@@ -864,6 +1024,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
|
||||
@@ -884,5 +1051,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;
|
||||
|
||||
+116
-12
@@ -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.
|
||||
@@ -49,16 +57,19 @@ pub enum Value<'lua> {
|
||||
/// `Error` is a special builtin userdata type. When received from Lua it is implicitly cloned.
|
||||
Error(Error),
|
||||
}
|
||||
|
||||
pub use self::Value::Nil;
|
||||
|
||||
impl<'lua> Value<'lua> {
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
pub const fn type_name(&self) -> &'static str {
|
||||
match *self {
|
||||
Value::Nil => "nil",
|
||||
Value::Boolean(_) => "boolean",
|
||||
Value::LightUserData(_) => "lightuserdata",
|
||||
Value::Integer(_) => "integer",
|
||||
Value::Number(_) => "number",
|
||||
#[cfg(feature = "luau")]
|
||||
Value::Vector(_, _, _) => "vector",
|
||||
Value::String(_) => "string",
|
||||
Value::Table(_) => "table",
|
||||
Value::Function(_) => "function",
|
||||
@@ -85,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(v))
|
||||
| Value::Thread(Thread(v))
|
||||
| Value::UserData(AnyUserData(v)) => v
|
||||
.lua
|
||||
.ref_thread_exec(|refthr| ffi::lua_topointer(refthr, v.index)),
|
||||
_ => ptr::null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> PartialEq for Value<'lua> {
|
||||
@@ -97,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,
|
||||
@@ -124,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),
|
||||
@@ -157,18 +197,27 @@ pub struct MultiValue<'lua>(Vec<Value<'lua>>);
|
||||
|
||||
impl<'lua> MultiValue<'lua> {
|
||||
/// Creates an empty `MultiValue` containing no values.
|
||||
pub fn new() -> MultiValue<'lua> {
|
||||
#[inline]
|
||||
pub const fn new() -> MultiValue<'lua> {
|
||||
MultiValue(Vec::new())
|
||||
}
|
||||
|
||||
/// Similar to `new` but can return previously used container with allocated capacity.
|
||||
#[inline]
|
||||
pub(crate) fn new_or_cached(lua: &'lua Lua) -> MultiValue<'lua> {
|
||||
lua.new_or_cached_multivalue()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> Default for MultiValue<'lua> {
|
||||
#[inline]
|
||||
fn default() -> MultiValue<'lua> {
|
||||
MultiValue::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromIterator<Value<'lua>> for MultiValue<'lua> {
|
||||
#[inline]
|
||||
fn from_iter<I: IntoIterator<Item = Value<'lua>>>(iter: I) -> Self {
|
||||
MultiValue::from_vec(Vec::from_iter(iter))
|
||||
}
|
||||
@@ -178,6 +227,7 @@ impl<'lua> IntoIterator for MultiValue<'lua> {
|
||||
type Item = Value<'lua>;
|
||||
type IntoIter = iter::Rev<vec::IntoIter<Value<'lua>>>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter().rev()
|
||||
}
|
||||
@@ -187,46 +237,100 @@ impl<'a, 'lua> IntoIterator for &'a MultiValue<'lua> {
|
||||
type Item = &'a Value<'lua>;
|
||||
type IntoIter = iter::Rev<slice::Iter<'a, Value<'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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> MultiValue<'lua> {
|
||||
#[inline]
|
||||
pub fn from_vec(mut v: Vec<Value<'lua>>) -> MultiValue<'lua> {
|
||||
v.reverse();
|
||||
MultiValue(v)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_vec(self) -> Vec<Value<'lua>> {
|
||||
let mut v = self.0;
|
||||
v.reverse();
|
||||
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);
|
||||
}
|
||||
|
||||
pub(crate) fn push_front(&mut self, value: Value<'lua>) {
|
||||
self.0.push(value);
|
||||
}
|
||||
|
||||
pub(crate) fn pop_front(&mut self) -> Option<Value<'lua>> {
|
||||
#[inline]
|
||||
pub fn pop_front(&mut self) -> Option<Value<'lua>> {
|
||||
self.0.pop()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn push_front(&mut self, value: Value<'lua>) {
|
||||
self.0.push(value);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn clear(&mut self) {
|
||||
self.0.clear();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.len() == 0
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn iter(&self) -> iter::Rev<slice::Iter<Value<'lua>>> {
|
||||
self.0.iter().rev()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn drain_all(&mut self) -> iter::Rev<vec::Drain<Value<'lua>>> {
|
||||
self.0.drain(..).rev()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn refill(
|
||||
&mut self,
|
||||
iter: impl IntoIterator<Item = Result<Value<'lua>>>,
|
||||
) -> Result<()> {
|
||||
self.0.clear();
|
||||
for value in iter {
|
||||
self.0.push(value?);
|
||||
}
|
||||
self.0.reverse();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for types convertible to any number of Lua values.
|
||||
|
||||
+138
-6
@@ -3,7 +3,7 @@
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{
|
||||
atomic::{AtomicI64, Ordering},
|
||||
atomic::{AtomicI64, AtomicU64, Ordering},
|
||||
Arc,
|
||||
};
|
||||
use std::time::Duration;
|
||||
@@ -12,7 +12,8 @@ use futures_timer::Delay;
|
||||
use futures_util::stream::TryStreamExt;
|
||||
|
||||
use mlua::{
|
||||
Error, Function, Lua, Result, Table, TableExt, Thread, UserData, UserDataMethods, Value,
|
||||
Error, Function, Lua, LuaOptions, Result, StdLib, Table, TableExt, Thread, UserData,
|
||||
UserDataMethods, Value,
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
@@ -74,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)?;
|
||||
@@ -170,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();
|
||||
@@ -227,7 +263,8 @@ async fn test_async_thread() -> Result<()> {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_async_table() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
let options = LuaOptions::new().thread_cache_size(4);
|
||||
let lua = Lua::new_with(StdLib::ALL_SAFE, options)?;
|
||||
|
||||
let table = lua.create_table()?;
|
||||
table.set("val", 10)?;
|
||||
@@ -273,10 +310,32 @@ 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)]
|
||||
struct MyUserData(Arc<AtomicI64>);
|
||||
struct MyUserData(Arc<AtomicU64>);
|
||||
|
||||
impl UserData for MyUserData {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
@@ -295,13 +354,46 @@ async fn test_async_userdata() -> Result<()> {
|
||||
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::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))),
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let lua = Lua::new();
|
||||
let globals = lua.globals();
|
||||
|
||||
let userdata = lua.create_userdata(MyUserData(Arc::new(AtomicI64::new(11))))?;
|
||||
let userdata = lua.create_userdata(MyUserData(Arc::new(AtomicU64::new(11))))?;
|
||||
globals.set("userdata", userdata.clone())?;
|
||||
|
||||
lua.load(
|
||||
@@ -315,6 +407,46 @@ async fn test_async_userdata() -> Result<()> {
|
||||
.exec_async()
|
||||
.await?;
|
||||
|
||||
#[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()
|
||||
.await?;
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
|
||||
@@ -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,20 +1,20 @@
|
||||
error[E0373]: closure may outlive the current function, but it borrows `test`, which is owned by the current function
|
||||
--> $DIR/function_borrow.rs:9:33
|
||||
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`
|
||||
--> $DIR/function_borrow.rs:9:13
|
||||
--> tests/compile/function_borrow.rs:9:13
|
||||
|
|
||||
9 | let _ = lua.create_function(|_, ()| -> Result<i32> {
|
||||
| _____________^
|
||||
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,35 +1,22 @@
|
||||
error[E0277]: the type `UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> $DIR/lua_norefunwindsafe.rs:7:5
|
||||
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
|
||||
|
|
||||
::: $RUST/std/src/panic.rs
|
||||
|
|
||||
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
| ---------- required by this bound in `catch_unwind`
|
||||
|
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<()>`
|
||||
= note: required because it appears within the type `PhantomData<UnsafeCell<()>>`
|
||||
= 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]`
|
||||
|
||||
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
|
||||
--> $DIR/lua_norefunwindsafe.rs:7:5
|
||||
note: required because it's used within this closure
|
||||
--> tests/compile/lua_norefunwindsafe.rs:7:18
|
||||
|
|
||||
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
|
||||
|
|
||||
::: $RUST/std/src/panic.rs
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
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`
|
||||
|
|
||||
= 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]`
|
||||
| ^^^^^^^^^^ required by this bound in `catch_unwind`
|
||||
|
||||
@@ -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,39 +1,24 @@
|
||||
error[E0277]: the type `UnsafeCell<()>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
--> $DIR/ref_nounwindsafe.rs:8:5
|
||||
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
|
||||
|
|
||||
::: $RUST/std/src/panic.rs
|
||||
|
|
||||
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
| ---------- required by this bound in `catch_unwind`
|
||||
|
|
||||
= help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<()>`
|
||||
= note: required because it appears within the type `PhantomData<UnsafeCell<()>>`
|
||||
= 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]`
|
||||
|
||||
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
|
||||
--> $DIR/ref_nounwindsafe.rs:8:5
|
||||
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());
|
||||
| ^^^^^^^^^^^^ `UnsafeCell<mlua::lua::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
||||
|
|
||||
::: $RUST/std/src/panic.rs
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
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`
|
||||
|
|
||||
= 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]`
|
||||
| ^^^^^^^^^^ required by this bound in `catch_unwind`
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error[E0521]: borrowed data escapes outside of closure
|
||||
--> $DIR/scope_callback_inner.rs:7:17
|
||||
--> tests/compile/scope_callback_inner.rs:7:17
|
||||
|
|
||||
5 | lua.scope(|scope| {
|
||||
| -----
|
||||
@@ -16,10 +16,10 @@ error[E0521]: borrowed data escapes outside of closure
|
||||
| |______________^ `scope` escapes the closure body here
|
||||
|
||||
error[E0373]: closure may outlive the current function, but it borrows `inner`, which is owned by the current function
|
||||
--> $DIR/scope_callback_inner.rs:8:34
|
||||
--> 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`
|
||||
@@ -27,7 +27,7 @@ error[E0373]: closure may outlive the current function, but it borrows `inner`,
|
||||
| ----- `inner` is borrowed here
|
||||
|
|
||||
note: function requires argument type to outlive `'2`
|
||||
--> $DIR/scope_callback_inner.rs:7:17
|
||||
--> tests/compile/scope_callback_inner.rs:7:17
|
||||
|
|
||||
7 | let f = scope
|
||||
| _________________^
|
||||
@@ -39,4 +39,4 @@ note: function requires argument type to outlive `'2`
|
||||
help: to force the closure to take ownership of `inner` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
8 | .create_function_mut(move |_, t: Table| {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
| ++++
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
error[E0373]: closure may outlive the current function, but it borrows `test`, which is owned by the current function
|
||||
--> $DIR/scope_invariance.rs:14:38
|
||||
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`
|
||||
--> $DIR/scope_invariance.rs:13:13
|
||||
--> tests/compile/scope_invariance.rs:13:13
|
||||
|
|
||||
13 | / scope
|
||||
14 | | .create_function_mut(|_, ()| {
|
||||
@@ -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
|
||||
|
||||
+16
-1
@@ -3,7 +3,7 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
use maplit::{btreemap, btreeset, hashmap, hashset};
|
||||
use mlua::{Lua, Result};
|
||||
use mlua::{Error, Lua, Result};
|
||||
|
||||
#[test]
|
||||
fn test_conv_vec() -> Result<()> {
|
||||
@@ -123,3 +123,18 @@ fn test_conv_boxed_slice() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conv_array() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let v = [1, 2, 3];
|
||||
lua.globals().set("v", v)?;
|
||||
let v2: [i32; 3] = lua.globals().get("v")?;
|
||||
assert_eq!(v, v2);
|
||||
|
||||
let v2 = lua.globals().get::<_, [i32; 4]>("v");
|
||||
assert!(matches!(v2, Err(Error::FromLuaConversionError { .. })));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
+6
-4
@@ -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(())
|
||||
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
#![cfg(feature = "luau")]
|
||||
|
||||
use std::env;
|
||||
use std::fs;
|
||||
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_table()?;
|
||||
assert!(!t.is_readonly());
|
||||
t.set_readonly(true);
|
||||
assert!(t.is_readonly());
|
||||
|
||||
match t.set("key", "value") {
|
||||
Err(Error::RuntimeError(err)) if err.contains("attempt to modify a readonly table") => {}
|
||||
r => panic!(
|
||||
"expected RuntimeError(...) with a specific message, got {:?}",
|
||||
r
|
||||
),
|
||||
};
|
||||
|
||||
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_coverate() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
lua.set_compiler(Compiler::default().set_coverage_level(1));
|
||||
|
||||
let f = lua
|
||||
.load(
|
||||
r#"local v = vector(1, 2, 3)
|
||||
assert(v.x == 1 and v.y == 2 and v.z == 3)
|
||||
|
||||
function abc(i)
|
||||
if i < 5 then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
(function()
|
||||
(function() abc(10) end)()
|
||||
end)()
|
||||
"#,
|
||||
)
|
||||
.into_function()?;
|
||||
|
||||
f.call(())?;
|
||||
|
||||
let mut report = Vec::new();
|
||||
f.coverage(|cov| {
|
||||
report.push(cov);
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
report[0],
|
||||
CoverageInfo {
|
||||
function: None,
|
||||
line_defined: 1,
|
||||
depth: 0,
|
||||
hits: vec![-1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1],
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
report[1],
|
||||
CoverageInfo {
|
||||
function: Some("abc".into()),
|
||||
line_defined: 4,
|
||||
depth: 1,
|
||||
hits: vec![-1, -1, -1, -1, -1, 1, 0, -1, 1, -1, -1, -1, -1, -1, -1, -1],
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
report[2],
|
||||
CoverageInfo {
|
||||
function: None,
|
||||
line_defined: 12,
|
||||
depth: 1,
|
||||
hits: vec![-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1],
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
report[3],
|
||||
CoverageInfo {
|
||||
function: None,
|
||||
line_defined: 13,
|
||||
depth: 2,
|
||||
hits: vec![-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1],
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#![cfg(feature = "macros")]
|
||||
|
||||
use mlua::{chunk, Lua, Result};
|
||||
|
||||
#[test]
|
||||
fn test_chunk_macro() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
let name = "Rustacean";
|
||||
let table = vec![1];
|
||||
|
||||
let data = lua.create_table()?;
|
||||
data.raw_set("num", 1)?;
|
||||
|
||||
lua.globals().set("g", 123)?;
|
||||
|
||||
lua.load(chunk! {
|
||||
assert($name == "Rustacean")
|
||||
assert($table[1] == 1)
|
||||
assert($data.num == 1)
|
||||
assert(g == 123)
|
||||
s = 321
|
||||
})
|
||||
.exec()?;
|
||||
|
||||
assert_eq!(lua.globals().get::<_, i32>("s")?, 321);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
+13
-6
@@ -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,5 +1,11 @@
|
||||
[target.x86_64-apple-darwin]
|
||||
rustflags = ["-C", "link-args=-rdynamic"]
|
||||
rustflags = [
|
||||
"-C", "link-arg=-undefined",
|
||||
"-C", "link-arg=dynamic_lookup",
|
||||
]
|
||||
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
rustflags = ["-C", "link-args=-rdynamic"]
|
||||
[target.aarch64-apple-darwin]
|
||||
rustflags = [
|
||||
"-C", "link-arg=-undefined",
|
||||
"-C", "link-arg=dynamic_lookup",
|
||||
]
|
||||
|
||||
+10
-3
@@ -1,16 +1,23 @@
|
||||
[package]
|
||||
name = "module_runner"
|
||||
name = "rust_module"
|
||||
version = "0.0.0"
|
||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"loader",
|
||||
]
|
||||
|
||||
[features]
|
||||
lua54 = ["mlua/lua54"]
|
||||
lua53 = ["mlua/lua53"]
|
||||
lua52 = ["mlua/lua52"]
|
||||
lua51 = ["mlua/lua51"]
|
||||
luajit = ["mlua/luajit"]
|
||||
vendored = ["mlua/vendored"]
|
||||
|
||||
[dependencies]
|
||||
mlua = { path = "../.." }
|
||||
mlua = { path = "../..", features = ["module"] }
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
[target.x86_64-apple-darwin]
|
||||
rustflags = ["-C", "link-args=-rdynamic"]
|
||||
|
||||
[target.aarch64-apple-darwin]
|
||||
rustflags = ["-C", "link-args=-rdynamic"]
|
||||
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
rustflags = ["-C", "link-args=-rdynamic"]
|
||||
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "module_loader"
|
||||
version = "0.0.0"
|
||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
lua54 = ["mlua/lua54"]
|
||||
lua53 = ["mlua/lua53"]
|
||||
lua52 = ["mlua/lua52"]
|
||||
lua51 = ["mlua/lua51"]
|
||||
luajit = ["mlua/luajit"]
|
||||
vendored = ["mlua/vendored"]
|
||||
|
||||
[dependencies]
|
||||
mlua = { path = "../../.." }
|
||||
@@ -0,0 +1,39 @@
|
||||
use mlua::prelude::*;
|
||||
|
||||
fn sum(_: &Lua, (a, b): (i64, i64)) -> LuaResult<i64> {
|
||||
Ok(a + b)
|
||||
}
|
||||
|
||||
fn used_memory(lua: &Lua, _: ()) -> LuaResult<usize> {
|
||||
Ok(lua.used_memory())
|
||||
}
|
||||
|
||||
fn check_userdata(_: &Lua, ud: MyUserData) -> LuaResult<i32> {
|
||||
Ok(ud.0)
|
||||
}
|
||||
|
||||
#[mlua::lua_module]
|
||||
fn rust_module(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let exports = lua.create_table()?;
|
||||
exports.set("sum", lua.create_function(sum)?)?;
|
||||
exports.set("used_memory", lua.create_function(used_memory)?)?;
|
||||
exports.set("check_userdata", lua.create_function(check_userdata)?)?;
|
||||
Ok(exports)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct MyUserData(i32);
|
||||
|
||||
impl LuaUserData for MyUserData {}
|
||||
|
||||
#[mlua::lua_module]
|
||||
fn rust_module_second(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let exports = lua.create_table()?;
|
||||
exports.set("userdata", lua.create_userdata(MyUserData(123))?)?;
|
||||
Ok(exports)
|
||||
}
|
||||
|
||||
#[mlua::lua_module]
|
||||
fn rust_module_error(_: &Lua) -> LuaResult<LuaTable> {
|
||||
Err("custom module error".to_lua_err())
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user