Compare commits

..

46 Commits

Author SHA1 Message Date
Alex Orlenko 497d84828a Add CI to build dev docs 2026-02-03 22:40:29 +00:00
Alex Orlenko 0e489901a5 Update debug module
Move debug types from root to new new module.
2026-02-03 22:39:33 +00:00
Alex Orlenko 88063e756f Make table module public 2026-01-30 13:18:46 +00:00
Alex Orlenko c8436e2b80 Make function module public
Reduce number of function-specific types exported to the mlua root and keep
them inside the module.
2026-01-30 13:18:05 +00:00
Alex Orlenko 613748ec16 Use Error::from_lua_conversion helper 2026-01-29 23:09:52 +00:00
Alex Orlenko 2fbd266da6 Remove Error::ToLuaConversionError
This variant used only once and not practically useful.
2026-01-29 23:04:30 +00:00
Alex Orlenko c79b5e9cdb cargo fmt 2026-01-29 23:03:56 +00:00
Alex Orlenko 2ace892613 Rename string::String to LuaString 2026-01-29 18:45:41 +00:00
Alex Orlenko c1ffd4e790 Replace get_or_insert_with with get_or_insert_default 2026-01-29 10:46:58 +00:00
Alex Orlenko d9c139b55f Rust 2024 2026-01-29 10:33:28 +00:00
Alex Orlenko 0c4206c97d Bump min Rust version to 1.88 2026-01-29 10:13:04 +00:00
Alex Orlenko a985dc7a37 Start 0.12.0-dev.1 2026-01-29 10:07:05 +00:00
Alex Orlenko e7fa8d75bb v0.11.6 2026-01-27 16:06:24 +00:00
Alex Orlenko c10718ed2f Update CHANGELOG 2026-01-27 16:04:33 +00:00
Alex Orlenko ec2ce3620f Some final Lua 5.5 updates 2026-01-27 16:00:49 +00:00
Alex Orlenko 71757003c7 mlua-sys: v0.10.0 2026-01-27 15:56:53 +00:00
Alex Orlenko 6bb7f09927 Don't use luaL_typename to get a static type name in Luau.
In Luau this function returns heap-allocated string rather than static string,
so accessing this value when Lua state is destroyed is UB.
Fixes #674
2026-01-27 14:10:43 +00:00
Alex Orlenko e67ae7f0de Make RawLua::{push,push_value,pop_value} public 2026-01-27 12:17:58 +00:00
Alex Orlenko 8c1535c27b cargo fmt 2026-01-27 12:14:50 +00:00
WASDetchan fd245daa6f Expose RawLua via Lua::exec_raw_lua (#670) 2026-01-23 16:19:10 +00:00
Alex Orlenko 7fb7e8685f Update spelling check 2026-01-23 15:37:18 +00:00
Alex Orlenko 93617eef4e Update trybuild (compile) messages 2026-01-23 15:16:35 +00:00
Alex Orlenko 171cdf1758 Some fixes and more tests for Function::info 2026-01-23 12:44:22 +00:00
psentee 3f8f016daa Add num_params, is_vararg, nups to FunctionInfo (#665) 2026-01-23 11:59:59 +00:00
Alex Orlenko 86d0c9bddb More multi borrow "send" test fixes due to regression in Rust 1.93+ 2026-01-22 23:08:17 +00:00
Alex Orlenko 86d63ef27b Fix missing BUFSIZ for wasm32 in libc 2026-01-22 15:46:31 +00:00
Alex Orlenko e33bcf7938 Add Lua 5.5 external string null byte test 2026-01-22 15:32:14 +00:00
Alex Orlenko c80a97b526 Ignore userdata_multithread_access_sync test 2026-01-22 15:25:18 +00:00
Alex Orlenko 3c40cfe199 mlua-sys: Use 2024 edition 2026-01-22 14:09:14 +00:00
Alex Orlenko e9efb73125 Update Luau FFI bindings (added some missing functions) 2026-01-22 14:05:57 +00:00
Alex Orlenko 386c6d8ed8 Update Lua 5.5 FFI bindings (add buffer manipulation, etc) 2026-01-22 12:54:55 +00:00
Alex Orlenko 8f086bf837 Update Lua 5.4 FFI bindings (add buffer manipulation, etc) 2026-01-22 12:50:56 +00:00
Alex Orlenko ad167612dc Update Lua 5.3 FFI bindings (add buffer manipulation, etc) 2026-01-20 15:36:36 +00:00
Alex Orlenko 3366f47d40 Minor Lua 5.2 fixes 2026-01-20 15:28:33 +00:00
Alex Orlenko 0b5ef91f44 Update Lua 5.2 FFI bindings (add buffer manipulation, etc) 2026-01-20 14:29:35 +00:00
Alex Orlenko a162b0ceca Update Lua 5.1 FFI bindings (add buffer manipulation, etc) 2026-01-20 14:29:15 +00:00
Alex Orlenko 8e6d652a21 Bump luau-src to 0.18.0 (Luau 0.705) 2026-01-20 13:05:00 +00:00
Alex Orlenko 1be9e6ce2d Add Lua 5.5 external strings support 2026-01-18 00:03:43 +00:00
Alex Orlenko b1f99aa852 Update tests 2026-01-17 13:26:13 +00:00
Alex Orlenko 4c5465229e Update CI 2026-01-14 21:44:25 +00:00
Alex Orlenko 9b24bb2319 Add Lua 5.5 to CI 2026-01-14 16:01:04 +00:00
Alex Orlenko e1701b6b56 cargo fmt 2026-01-14 15:57:52 +00:00
Alex Orlenko 77d7d5d6bd Add initial Lua 5.5 support 2026-01-13 23:43:31 +00:00
psentee ee9232eda1 AnyUserData::is_proxy (#666) 2026-01-13 15:08:38 +00:00
Alex Orlenko da526595bb mlua-sys: Add Lua 5.5 support 2026-01-13 00:05:01 +00:00
Alex Orlenko 39a7d3b862 Update SYS_MIN_ALIGN 2025-12-31 19:26:38 +02:00
106 changed files with 2998 additions and 1172 deletions
+68
View File
@@ -0,0 +1,68 @@
name: Documentation (dev)
on:
push:
branches: [dev]
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment
concurrency:
group: pages
cancel-in-progress: true
jobs:
build:
name: Build Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
- uses: dtolnay/rust-toolchain@nightly
- uses: Swatinem/rust-cache@v2
- name: Build documentation
env:
RUSTDOCFLAGS: "--cfg docsrs"
run: |
cargo +nightly doc --no-deps \
--features "lua55,vendored,async,send,serde,macros,anyhow,userdata-wrappers"
- name: Create index redirect
run: |
echo '<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Redirecting to mlua documentation</title>
<meta http-equiv="refresh" content="0; URL=mlua/index.html">
<link rel="canonical" href="mlua/index.html">
</head>
<body>
<p>Redirecting to <a href="mlua/index.html">mlua documentation</a>...</p>
</body>
</html>' > target/doc/index.html
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact
uses: actions/upload-pages-artifact@v4
with:
path: target/doc
deploy:
name: Deploy to GitHub Pages
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
+14 -30
View File
@@ -9,7 +9,7 @@ jobs:
matrix: matrix:
os: [ubuntu-latest, macos-latest, windows-latest] os: [ubuntu-latest, macos-latest, windows-latest]
rust: [stable] rust: [stable]
lua: [lua54, lua53, lua52, lua51, luajit, luau, luau-jit, luau-vector4] lua: [lua55, lua54, lua53, lua52, lua51, luajit, luau, luau-jit, luau-vector4]
include: include:
- os: ubuntu-latest - os: ubuntu-latest
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
@@ -31,35 +31,19 @@ jobs:
cargo build --features "${{ matrix.lua }},vendored,async,serde,macros,anyhow,userdata-wrappers,send" cargo build --features "${{ matrix.lua }},vendored,async,serde,macros,anyhow,userdata-wrappers,send"
shell: bash shell: bash
- name: Build ${{ matrix.lua }} pkg-config - name: Build ${{ matrix.lua }} pkg-config
if: ${{ matrix.os == 'ubuntu-latest' }} if: ${{ matrix.os == 'ubuntu-latest' && matrix.lua != 'lua55' }}
run: | run: |
sudo apt-get update 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 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 }}" cargo build --features "${{ matrix.lua }}"
build_aarch64_cross_macos:
name: Cross-compile to aarch64-apple-darwin
runs-on: macos-latest
needs: build
strategy:
matrix:
lua: [lua54, lua53, lua52, lua51, luajit]
steps:
- uses: actions/checkout@main
- 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,serde,macros,anyhow,userdata-wrappers"
build_aarch64_cross_ubuntu: build_aarch64_cross_ubuntu:
name: Cross-compile to aarch64-unknown-linux-gnu name: Cross-compile to aarch64-unknown-linux-gnu
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build needs: build
strategy: strategy:
matrix: matrix:
lua: [lua54, lua53, lua52, lua51, luajit] lua: [lua55, lua54, lua53, lua52, lua51, luajit]
steps: steps:
- uses: actions/checkout@main - uses: actions/checkout@main
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@stable
@@ -81,7 +65,7 @@ jobs:
needs: build needs: build
strategy: strategy:
matrix: matrix:
lua: [lua54, lua53, lua52, lua51] lua: [lua55, lua54, lua53, lua52, lua51]
steps: steps:
- uses: actions/checkout@main - uses: actions/checkout@main
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@stable
@@ -105,7 +89,7 @@ jobs:
matrix: matrix:
os: [ubuntu-latest, macos-latest, windows-latest] os: [ubuntu-latest, macos-latest, windows-latest]
rust: [stable, nightly] rust: [stable, nightly]
lua: [lua54, lua53, lua52, lua51, luajit, luajit52, luau, luau-jit, luau-vector4] lua: [lua55, lua54, lua53, lua52, lua51, luajit, luajit52, luau, luau-jit, luau-vector4]
include: include:
- os: ubuntu-latest - os: ubuntu-latest
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
@@ -126,8 +110,8 @@ jobs:
cargo test --features "${{ matrix.lua }},vendored,async,serde,macros,anyhow,userdata-wrappers" cargo test --features "${{ matrix.lua }},vendored,async,serde,macros,anyhow,userdata-wrappers"
cargo test --features "${{ matrix.lua }},vendored,async,serde,macros,anyhow,userdata-wrappers,send" cargo test --features "${{ matrix.lua }},vendored,async,serde,macros,anyhow,userdata-wrappers,send"
shell: bash shell: bash
- name: Run compile tests (macos lua54) - name: Run compile tests (macos lua55)
if: ${{ matrix.os == 'macos-latest' && matrix.lua == 'lua54' }} if: ${{ matrix.os == 'macos-latest' && matrix.lua == 'lua55' }}
run: | run: |
TRYBUILD=overwrite cargo test --features "${{ matrix.lua }},vendored" --tests -- --ignored TRYBUILD=overwrite cargo test --features "${{ matrix.lua }},vendored" --tests -- --ignored
TRYBUILD=overwrite cargo test --features "${{ matrix.lua }},vendored,async,send,serde,macros" --tests -- --ignored TRYBUILD=overwrite cargo test --features "${{ matrix.lua }},vendored,async,send,serde,macros" --tests -- --ignored
@@ -141,7 +125,7 @@ jobs:
matrix: matrix:
os: [ubuntu-latest] os: [ubuntu-latest]
rust: [nightly] rust: [nightly]
lua: [lua54, lua53, lua52, lua51, luajit, luau, luau-jit, luau-vector4] lua: [lua55, lua54, lua53, lua52, lua51, luajit, luau, luau-jit, luau-vector4]
include: include:
- os: ubuntu-latest - os: ubuntu-latest
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
@@ -168,7 +152,7 @@ jobs:
matrix: matrix:
os: [ubuntu-latest] os: [ubuntu-latest]
rust: [nightly] rust: [nightly]
lua: [lua54, lua53, lua52, lua51, luajit, luau, luau-jit, luau-vector4] lua: [lua55, lua54, lua53, lua52, lua51, luajit, luau, luau-jit, luau-vector4]
include: include:
- os: ubuntu-latest - os: ubuntu-latest
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
@@ -194,7 +178,7 @@ jobs:
matrix: matrix:
os: [ubuntu-latest, macos-latest] os: [ubuntu-latest, macos-latest]
rust: [stable] rust: [stable]
lua: [lua54, lua53, lua52, lua51, luajit] lua: [lua55, lua54, lua53, lua52, lua51, luajit]
include: include:
- os: ubuntu-latest - os: ubuntu-latest
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
@@ -240,7 +224,7 @@ jobs:
needs: build needs: build
strategy: strategy:
matrix: matrix:
lua: [lua54, lua53, lua52, lua51, luau] lua: [lua55, lua54, lua53, lua52, lua51, luau]
steps: steps:
- uses: actions/checkout@main - uses: actions/checkout@main
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@stable
@@ -262,7 +246,7 @@ jobs:
needs: build needs: build
strategy: strategy:
matrix: matrix:
lua: [lua54, lua53, lua52, lua51] lua: [lua55, lua54, lua53, lua52, lua51]
steps: steps:
- uses: actions/checkout@main - uses: actions/checkout@main
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@stable
@@ -273,7 +257,7 @@ jobs:
working-directory: ${{ runner.tool_cache }} working-directory: ${{ runner.tool_cache }}
run: | run: |
wasi_sdk=29 wasi_sdk=29
wasmtime=v39.0.0 wasmtime=v40.0.1
curl -LO https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$wasi_sdk/wasi-sdk-$wasi_sdk.0-x86_64-linux.tar.gz curl -LO https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$wasi_sdk/wasi-sdk-$wasi_sdk.0-x86_64-linux.tar.gz
tar xf wasi-sdk-$wasi_sdk.0-x86_64-linux.tar.gz tar xf wasi-sdk-$wasi_sdk.0-x86_64-linux.tar.gz
@@ -306,7 +290,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
lua: [lua54, lua53, lua52, lua51, luajit, luau, luau-jit, luau-vector4] lua: [lua55, lua54, lua53, lua52, lua51, luajit, luau, luau-jit, luau-vector4]
steps: steps:
- uses: actions/checkout@main - uses: actions/checkout@main
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@stable
+10 -5
View File
@@ -1,17 +1,22 @@
name: Typos Check name: Spelling Check
on: on:
pull_request: pull_request:
workflow_dispatch: workflow_dispatch:
permissions:
contents: read
env:
CLICOLOR: 1
jobs: jobs:
run: spelling:
name: Spell Check with Typos name: Spell Check with Typos
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Actions Repository - name: Checkout Actions Repository
uses: actions/checkout@v4 uses: actions/checkout@main
- name: Check spelling - name: Check spelling
uses: crate-ci/typos@master uses: crate-ci/typos@v1.42.1
with: with:
config: ./typos.toml config: ./typos.toml
+7
View File
@@ -1,3 +1,10 @@
## v0.11.6 (Jan 27, 2026)
- Added Lua 5.5 support (`lua55` feature flag)
- Luau updated to 0.705+
- Added `AnyUserData::is_proxy` method to check if userdata is a proxy
- Added `num_params`, `num_upvalues`, `is_vararg` to `FunctionInfo`
## v0.11.5 (Nov 22, 2025) ## v0.11.5 (Nov 22, 2025)
- Luau updated to 0.701 - Luau updated to 0.701
+7 -7
View File
@@ -1,9 +1,9 @@
[package] [package]
name = "mlua" name = "mlua"
version = "0.11.5" # remember to update mlua_derive version = "0.12.0-dev.1" # remember to update mlua_derive
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@kyju.org>"] authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@kyju.org>"]
rust-version = "1.80.0" rust-version = "1.88"
edition = "2021" edition = "2024"
repository = "https://github.com/mlua-rs/mlua" repository = "https://github.com/mlua-rs/mlua"
documentation = "https://docs.rs/mlua" documentation = "https://docs.rs/mlua"
readme = "README.md" readme = "README.md"
@@ -11,12 +11,12 @@ keywords = ["lua", "luajit", "luau", "async", "scripting"]
categories = ["api-bindings", "asynchronous"] categories = ["api-bindings", "asynchronous"]
license = "MIT" license = "MIT"
description = """ description = """
High level bindings to Lua 5.4/5.3/5.2/5.1 (including LuaJIT) and Luau High level bindings to Lua 5.5/5.4/5.3/5.2/5.1 (including LuaJIT) and Luau
with async/await features and support of writing native Lua modules in Rust. with async/await features and support of writing native Lua modules in Rust.
""" """
[package.metadata.docs.rs] [package.metadata.docs.rs]
features = ["lua54", "vendored", "async", "send", "serde", "macros"] features = ["lua55", "vendored", "async", "send", "serde", "macros"]
rustdoc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs"]
[workspace] [workspace]
@@ -26,6 +26,7 @@ members = [
] ]
[features] [features]
lua55 = ["ffi/lua55"]
lua54 = ["ffi/lua54"] lua54 = ["ffi/lua54"]
lua53 = ["ffi/lua53"] lua53 = ["ffi/lua53"]
lua52 = ["ffi/lua52"] lua52 = ["ffi/lua52"]
@@ -60,10 +61,9 @@ erased-serde = { version = "0.4", optional = true }
serde-value = { version = "0.7", optional = true } serde-value = { version = "0.7", optional = true }
parking_lot = { version = "0.12", features = ["arc_lock"] } parking_lot = { version = "0.12", features = ["arc_lock"] }
anyhow = { version = "1.0", optional = true } anyhow = { version = "1.0", optional = true }
rustversion = "1.0"
libc = "0.2" libc = "0.2"
ffi = { package = "mlua-sys", version = "0.9.0", path = "mlua-sys" } ffi = { package = "mlua-sys", version = "0.10.0", path = "mlua-sys" }
[dev-dependencies] [dev-dependencies]
trybuild = "1.0" trybuild = "1.0"
+3 -1
View File
@@ -20,7 +20,7 @@
`mlua` is a set of bindings to the [Lua](https://www.lua.org) programming language for Rust with a goal of providing a `mlua` is a set of bindings to the [Lua](https://www.lua.org) programming language for Rust with a goal of providing a
_safe_ (as much as possible), high level, easy to use, practical and flexible API. _safe_ (as much as possible), high level, easy to use, practical and flexible API.
Started as an `rlua` fork, `mlua` supports Lua 5.4, 5.3, 5.2, 5.1 (including LuaJIT) and [Luau] and allows writing native Lua modules in Rust as well as using Lua in a standalone mode. Started as an `rlua` fork, `mlua` supports Lua 5.5, 5.4, 5.3, 5.2, 5.1 (including LuaJIT) and [Luau] and allows writing native Lua modules in Rust as well as using Lua in a standalone mode.
`mlua` is tested on Windows/macOS/Linux including module mode in [GitHub Actions] on `x86_64` platforms and cross-compilation to `aarch64` (other targets are also supported). `mlua` is tested on Windows/macOS/Linux including module mode in [GitHub Actions] on `x86_64` platforms and cross-compilation to `aarch64` (other targets are also supported).
@@ -36,6 +36,7 @@ WebAssembly (WASM) is supported through the `wasm32-unknown-emscripten` target f
`mlua` uses feature flags to reduce the number of dependencies and compiled code, and allow choosing only the required set of features. `mlua` uses feature flags to reduce the number of dependencies and compiled code, and allow choosing only the required set of features.
Below is a list of the available feature flags. By default `mlua` does not enable any features. Below is a list of the available feature flags. By default `mlua` does not enable any features.
* `lua55`: enable Lua [5.5] support
* `lua54`: enable Lua [5.4] support * `lua54`: enable Lua [5.4] support
* `lua53`: enable Lua [5.3] support * `lua53`: enable Lua [5.3] support
* `lua52`: enable Lua [5.2] support * `lua52`: enable Lua [5.2] support
@@ -55,6 +56,7 @@ Below is a list of the available feature flags. By default `mlua` does not enabl
* `anyhow`: enable `anyhow::Error` conversion into Lua * `anyhow`: enable `anyhow::Error` conversion into Lua
* `userdata-wrappers`: opt into `impl UserData` for `Rc<T>`/`Arc<T>`/`Rc<RefCell<T>>`/`Arc<Mutex<T>>` where `T: UserData` * `userdata-wrappers`: opt into `impl UserData` for `Rc<T>`/`Arc<T>`/`Rc<RefCell<T>>`/`Arc<Mutex<T>>` where `T: UserData`
[5.5]: https://www.lua.org/manual/5.5/manual.html
[5.4]: https://www.lua.org/manual/5.4/manual.html [5.4]: https://www.lua.org/manual/5.4/manual.html
[5.3]: https://www.lua.org/manual/5.3/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.2]: https://www.lua.org/manual/5.2/manual.html
+1 -1
View File
@@ -1,7 +1,7 @@
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration; use std::time::Duration;
use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; use criterion::{BatchSize, Criterion, criterion_group, criterion_main};
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
use tokio::task; use tokio::task;
+1 -1
View File
@@ -1,6 +1,6 @@
use std::time::Duration; use std::time::Duration;
use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; use criterion::{BatchSize, Criterion, criterion_group, criterion_main};
use mlua::prelude::*; use mlua::prelude::*;
+1 -1
View File
@@ -336,7 +336,7 @@ In previous mlua versions, building a Lua module for Windows requires having Lua
In contrast, on Linux and macOS, modules can be built without any external dependencies using the `-undefined=dynamic_lookup` linker flag. In contrast, on Linux and macOS, modules can be built without any external dependencies using the `-undefined=dynamic_lookup` linker flag.
With Rust 1.71+ it's now possible to lift this restriction for Windows as well. You can build modules normally and they will be linked with With Rust 1.71+ it's now possible to lift this restriction for Windows as well. You can build modules normally and they will be linked with
`lua54.dll`/`lua53.dll`/`lua52.dll`/`lua51.dll` depending on the enabled Lua version. `lua5x.dll` depending on the enabled Lua version.
You still need to have the dll although, linked to application where the module will be loaded. You still need to have the dll although, linked to application where the module will be loaded.
+1 -1
View File
@@ -5,7 +5,7 @@ use hyper::body::Incoming;
use hyper_util::client::legacy::Client as HyperClient; use hyper_util::client::legacy::Client as HyperClient;
use hyper_util::rt::TokioExecutor; use hyper_util::rt::TokioExecutor;
use mlua::{chunk, ExternalResult, Lua, Result, UserData, UserDataMethods}; use mlua::{ExternalResult, Lua, Result, UserData, UserDataMethods, chunk};
struct BodyReader(Incoming); struct BodyReader(Incoming);
+1 -1
View File
@@ -1,4 +1,4 @@
use mlua::{chunk, ExternalResult, Lua, LuaSerdeExt, Result, Value}; use mlua::{ExternalResult, Lua, LuaSerdeExt, Result, Value, chunk};
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() -> Result<()> { async fn main() -> Result<()> {
+1 -1
View File
@@ -11,7 +11,7 @@ use hyper::{Request, Response};
use hyper_util::rt::TokioIo; use hyper_util::rt::TokioIo;
use tokio::net::TcpListener; use tokio::net::TcpListener;
use mlua::{chunk, Error as LuaError, Function, Lua, String as LuaString, Table, UserData, UserDataMethods}; use mlua::{Error as LuaError, Function, Lua, String as LuaString, Table, UserData, UserDataMethods, chunk};
/// Wrapper around incoming request that implements UserData /// Wrapper around incoming request that implements UserData
struct LuaRequest(SocketAddr, Request<Incoming>); struct LuaRequest(SocketAddr, Request<Incoming>);
+1 -1
View File
@@ -4,7 +4,7 @@ use std::net::SocketAddr;
use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream}; use tokio::net::{TcpListener, TcpStream};
use mlua::{chunk, BString, Function, Lua, UserData, UserDataMethods}; use mlua::{BString, Function, Lua, UserData, UserDataMethods, chunk};
struct LuaTcpStream(TcpStream); struct LuaTcpStream(TcpStream);
+1 -1
View File
@@ -1,7 +1,7 @@
use std::f32; use std::f32;
use std::iter::FromIterator; use std::iter::FromIterator;
use mlua::{chunk, FromLua, Function, Lua, MetaMethod, Result, UserData, UserDataMethods, Value, Variadic}; use mlua::{FromLua, Function, Lua, MetaMethod, Result, UserData, UserDataMethods, Value, Variadic, chunk};
fn main() -> Result<()> { fn main() -> Result<()> {
// You can create a new Lua state with `Lua::new()`. This loads the default Lua std library // You can create a new Lua state with `Lua::new()`. This loads the default Lua std library
+1
View File
@@ -10,6 +10,7 @@ crate-type = ["cdylib"]
[workspace] [workspace]
[features] [features]
lua55 = ["mlua/lua55"]
lua54 = ["mlua/lua54"] lua54 = ["mlua/lua54"]
lua53 = ["mlua/lua53"] lua53 = ["mlua/lua53"]
lua52 = ["mlua/lua52"] lua52 = ["mlua/lua52"]
+1 -1
View File
@@ -1,4 +1,4 @@
use mlua::{chunk, Lua, MetaMethod, Result, UserData}; use mlua::{Lua, MetaMethod, Result, UserData, chunk};
#[derive(Default)] #[derive(Default)]
struct Rectangle { struct Rectangle {
+9 -7
View File
@@ -1,9 +1,9 @@
[package] [package]
name = "mlua-sys" name = "mlua-sys"
version = "0.9.0" version = "0.10.0"
authors = ["Aleksandr Orlenko <zxteam@pm.me>"] authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
rust-version = "1.71" rust-version = "1.88"
edition = "2021" edition = "2024"
repository = "https://github.com/mlua-rs/mlua" repository = "https://github.com/mlua-rs/mlua"
documentation = "https://docs.rs/mlua-sys" documentation = "https://docs.rs/mlua-sys"
readme = "README.md" readme = "README.md"
@@ -12,14 +12,15 @@ license = "MIT"
links = "lua" links = "lua"
build = "build/main.rs" build = "build/main.rs"
description = """ description = """
Low level (FFI) bindings to Lua 5.4/5.3/5.2/5.1 (including LuaJIT) and Luau Low level (FFI) bindings to Lua 5.5/5.4/5.3/5.2/5.1 (including LuaJIT) and Luau
""" """
[package.metadata.docs.rs] [package.metadata.docs.rs]
features = ["lua54", "vendored"] features = ["lua55", "vendored"]
rustdoc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs"]
[features] [features]
lua55 = []
lua54 = [] lua54 = []
lua53 = [] lua53 = []
lua52 = [] lua52 = []
@@ -34,14 +35,15 @@ external = []
module = [] module = []
[dependencies] [dependencies]
libc = "0.2"
[build-dependencies] [build-dependencies]
cc = "1.0" cc = "1.0"
cfg-if = "1.0" cfg-if = "1.0"
pkg-config = "0.3.17" pkg-config = "0.3.17"
lua-src = { version = ">= 548.1.0, < 548.2.0", optional = true } lua-src = { version = ">= 550.0.0, < 550.1.0", optional = true }
luajit-src = { version = ">= 210.6.0, < 210.7.0", optional = true } luajit-src = { version = ">= 210.6.0, < 210.7.0", optional = true }
luau0-src = { version = "0.17.0", optional = true } luau0-src = { version = "0.18.0", optional = true }
[lints.rust] [lints.rust]
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(raw_dylib)'] } unexpected_cfgs = { level = "allow", check-cfg = ['cfg(raw_dylib)'] }
+2 -1
View File
@@ -1,8 +1,9 @@
# mlua-sys # mlua-sys
Low level (FFI) bindings to Lua 5.4/5.3/5.2/5.1 (including LuaJIT) and [Luau]. Low level (FFI) bindings to Lua 5.5/5.4/5.3/5.2/5.1 (including [LuaJIT]) and [Luau].
Intended to be consumed by the [mlua] crate. Intended to be consumed by the [mlua] crate.
[LuaJIT]: https://github.com/LuaJIT/LuaJIT
[Luau]: https://github.com/luau-lang/luau [Luau]: https://github.com/luau-lang/luau
[mlua]: https://crates.io/crates/mlua [mlua]: https://crates.io/crates/mlua
+7 -11
View File
@@ -31,18 +31,16 @@ pub fn probe_lua() {
// Find using `pkg-config` // Find using `pkg-config`
#[cfg(feature = "lua55")]
let (incl_bound, excl_bound, alt_probe, ver) = ("5.5", "5.6", ["lua5.5", "lua-5.5", "lua55"], "5.5");
#[cfg(feature = "lua54")] #[cfg(feature = "lua54")]
let (incl_bound, excl_bound, alt_probe, ver) = let (incl_bound, excl_bound, alt_probe, ver) = ("5.4", "5.5", ["lua5.4", "lua-5.4", "lua54"], "5.4");
("5.4", "5.5", ["lua5.4", "lua-5.4", "lua54"], "5.4");
#[cfg(feature = "lua53")] #[cfg(feature = "lua53")]
let (incl_bound, excl_bound, alt_probe, ver) = let (incl_bound, excl_bound, alt_probe, ver) = ("5.3", "5.4", ["lua5.3", "lua-5.3", "lua53"], "5.3");
("5.3", "5.4", ["lua5.3", "lua-5.3", "lua53"], "5.3");
#[cfg(feature = "lua52")] #[cfg(feature = "lua52")]
let (incl_bound, excl_bound, alt_probe, ver) = let (incl_bound, excl_bound, alt_probe, ver) = ("5.2", "5.3", ["lua5.2", "lua-5.2", "lua52"], "5.2");
("5.2", "5.3", ["lua5.2", "lua-5.2", "lua52"], "5.2");
#[cfg(feature = "lua51")] #[cfg(feature = "lua51")]
let (incl_bound, excl_bound, alt_probe, ver) = let (incl_bound, excl_bound, alt_probe, ver) = ("5.1", "5.2", ["lua5.1", "lua-5.1", "lua51"], "5.1");
("5.1", "5.2", ["lua5.1", "lua-5.1", "lua51"], "5.1");
#[cfg(feature = "luajit")] #[cfg(feature = "luajit")]
let (incl_bound, excl_bound, alt_probe, ver) = ("2.0.4", "2.2", [], "JIT"); let (incl_bound, excl_bound, alt_probe, ver) = ("2.0.4", "2.2", [], "JIT");
@@ -54,9 +52,7 @@ pub fn probe_lua() {
if lua.is_err() { if lua.is_err() {
for pkg in alt_probe { for pkg in alt_probe {
lua = pkg_config::Config::new() lua = pkg_config::Config::new().cargo_metadata(true).probe(pkg);
.cargo_metadata(true)
.probe(pkg);
if lua.is_ok() { if lua.is_ok() {
break; break;
+3
View File
@@ -1,6 +1,9 @@
#![allow(dead_code)] #![allow(dead_code)]
pub fn probe_lua() { pub fn probe_lua() {
#[cfg(feature = "lua55")]
let artifacts = lua_src::Build::new().build(lua_src::Lua55);
#[cfg(feature = "lua54")] #[cfg(feature = "lua54")]
let artifacts = lua_src::Build::new().build(lua_src::Lua54); let artifacts = lua_src::Build::new().build(lua_src::Lua54);
+9 -7
View File
@@ -1,19 +1,21 @@
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(all(feature = "lua54", not(any(feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit", feature = "luau"))))] { if #[cfg(all(feature = "lua55", not(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit", feature = "luau"))))] {
include!("main_inner.rs"); include!("main_inner.rs");
} else if #[cfg(all(feature = "lua53", not(any(feature = "lua54", feature = "lua52", feature = "lua51", feature = "luajit", feature = "luau"))))] { } else if #[cfg(all(feature = "lua54", not(any(feature = "lua55", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit", feature = "luau"))))] {
include!("main_inner.rs"); include!("main_inner.rs");
} else if #[cfg(all(feature = "lua52", not(any(feature = "lua54", feature = "lua53", feature = "lua51", feature = "luajit", feature = "luau"))))] { } else if #[cfg(all(feature = "lua53", not(any(feature = "lua55", feature = "lua54", feature = "lua52", feature = "lua51", feature = "luajit", feature = "luau"))))] {
include!("main_inner.rs"); include!("main_inner.rs");
} else if #[cfg(all(feature = "lua51", not(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luajit", feature = "luau"))))] { } else if #[cfg(all(feature = "lua52", not(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua51", feature = "luajit", feature = "luau"))))] {
include!("main_inner.rs"); include!("main_inner.rs");
} else if #[cfg(all(feature = "luajit", not(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luau"))))] { } else if #[cfg(all(feature = "lua51", not(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52", feature = "luajit", feature = "luau"))))] {
include!("main_inner.rs"); include!("main_inner.rs");
} else if #[cfg(all(feature = "luau", not(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit"))))] { } else if #[cfg(all(feature = "luajit", not(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luau"))))] {
include!("main_inner.rs");
} else if #[cfg(all(feature = "luau", not(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit"))))] {
include!("main_inner.rs"); include!("main_inner.rs");
} else { } else {
fn main() { fn main() {
compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau"); compile_error!("You can enable only one of the features: lua55, lua54, lua53, lua52, lua51, luajit, luajit52, luau");
} }
} }
} }
+31 -22
View File
@@ -1,4 +1,4 @@
//! Low level bindings to Lua 5.4/5.3/5.2/5.1 (including LuaJIT) and Luau. //! Low level bindings to Lua 5.5/5.4/5.3/5.2/5.1 (including LuaJIT) and Luau.
#![allow(non_camel_case_types, non_snake_case)] #![allow(non_camel_case_types, non_snake_case)]
#![allow(clippy::missing_safety_doc)] #![allow(clippy::missing_safety_doc)]
@@ -8,6 +8,9 @@
use std::os::raw::c_int; use std::os::raw::c_int;
#[cfg(any(feature = "lua55", doc))]
pub use lua55::*;
#[cfg(any(feature = "lua54", doc))] #[cfg(any(feature = "lua54", doc))]
pub use lua54::*; pub use lua54::*;
@@ -23,7 +26,7 @@ pub use lua51::*;
#[cfg(any(feature = "luau", doc))] #[cfg(any(feature = "luau", doc))]
pub use luau::*; pub use luau::*;
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
#[doc(hidden)] #[doc(hidden)]
pub const LUA_MAX_UPVALUES: c_int = 255; pub const LUA_MAX_UPVALUES: c_int = 255;
@@ -40,14 +43,22 @@ pub const LUA_MAX_UPVALUES: c_int = 200;
#[doc(hidden)] #[doc(hidden)]
pub const LUA_TRACEBACK_STACK: c_int = 11; pub const LUA_TRACEBACK_STACK: c_int = 11;
// Copied from https://github.com/rust-lang/rust/blob/master/library/std/src/sys/pal/common/alloc.rs // The minimum alignment guaranteed by the architecture.
// The minimum alignment guaranteed by the architecture. This value is used to // Copied from https://github.com/rust-lang/rust/blob/main/library/std/src/sys/alloc/mod.rs
// add fast paths for low alignment values. #[doc(hidden)]
#[cfg(any( #[rustfmt::skip]
pub const SYS_MIN_ALIGN: usize = if cfg!(any(
all(target_arch = "riscv32", any(target_os = "espidf", target_os = "zkvm")),
all(target_arch = "xtensa", target_os = "espidf"),
)) {
// The allocator on the esp-idf and zkvm platforms guarantees 4 byte alignment.
4
} else if cfg!(any(
target_arch = "x86", target_arch = "x86",
target_arch = "arm", target_arch = "arm",
target_arch = "m68k", target_arch = "m68k",
target_arch = "csky", target_arch = "csky",
target_arch = "loongarch32",
target_arch = "mips", target_arch = "mips",
target_arch = "mips32r6", target_arch = "mips32r6",
target_arch = "powerpc", target_arch = "powerpc",
@@ -55,12 +66,11 @@ pub const LUA_TRACEBACK_STACK: c_int = 11;
target_arch = "sparc", target_arch = "sparc",
target_arch = "wasm32", target_arch = "wasm32",
target_arch = "hexagon", target_arch = "hexagon",
all(target_arch = "riscv32", not(any(target_os = "espidf", target_os = "zkvm"))), target_arch = "riscv32",
all(target_arch = "xtensa", not(target_os = "espidf")), target_arch = "xtensa",
))] )) {
#[doc(hidden)] 8
pub const SYS_MIN_ALIGN: usize = 8; } else if cfg!(any(
#[cfg(any(
target_arch = "x86_64", target_arch = "x86_64",
target_arch = "aarch64", target_arch = "aarch64",
target_arch = "arm64ec", target_arch = "arm64ec",
@@ -71,20 +81,19 @@ pub const SYS_MIN_ALIGN: usize = 8;
target_arch = "sparc64", target_arch = "sparc64",
target_arch = "riscv64", target_arch = "riscv64",
target_arch = "wasm64", target_arch = "wasm64",
))] )) {
#[doc(hidden)] 16
pub const SYS_MIN_ALIGN: usize = 16; } else {
// The allocator on the esp-idf and zkvm platforms guarantee 4 byte alignment. panic!("no value for SYS_MIN_ALIGN")
#[cfg(any( };
all(target_arch = "riscv32", any(target_os = "espidf", target_os = "zkvm")),
all(target_arch = "xtensa", target_os = "espidf"),
))]
#[doc(hidden)]
pub const SYS_MIN_ALIGN: usize = 4;
#[macro_use] #[macro_use]
mod macros; mod macros;
#[cfg(any(feature = "lua55", doc))]
#[cfg_attr(docsrs, doc(cfg(feature = "lua55")))]
pub mod lua55;
#[cfg(any(feature = "lua54", doc))] #[cfg(any(feature = "lua54", doc))]
#[cfg_attr(docsrs, doc(cfg(feature = "lua54")))] #[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
pub mod lua54; pub mod lua54;
+1 -5
View File
@@ -55,11 +55,7 @@ unsafe fn compat53_checkmode(
while *st != 0 && *st != c { while *st != 0 && *st != c {
st = st.offset(1); st = st.offset(1);
} }
if *st == c { if *st == c { st } else { ptr::null() }
st
} else {
ptr::null()
}
} }
if !mode.is_null() && strchr(mode, *modename).is_null() { if !mode.is_null() && strchr(mode, *modename).is_null() {
+56 -4
View File
@@ -107,8 +107,6 @@ pub unsafe fn luaL_optstring(L: *mut lua_State, n: c_int, d: *const c_char) -> *
luaL_optlstring(L, n, d, ptr::null_mut()) luaL_optlstring(L, n, d, ptr::null_mut())
} }
// Deprecated from 5.3: luaL_checkint, luaL_optint, luaL_checklong, luaL_optlong
#[inline(always)] #[inline(always)]
pub unsafe fn luaL_typename(L: *mut lua_State, i: c_int) -> *const c_char { pub unsafe fn luaL_typename(L: *mut lua_State, i: c_int) -> *const c_char {
lua::lua_typename(L, lua::lua_type(L, i)) lua::lua_typename(L, lua::lua_type(L, i))
@@ -138,8 +136,62 @@ pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
lua::lua_getfield_(L, lua::LUA_REGISTRYINDEX, n); lua::lua_getfield_(L, lua::LUA_REGISTRYINDEX, n);
} }
// TODO: luaL_opt #[inline(always)]
pub unsafe fn luaL_opt<T>(
L: *mut lua_State,
f: unsafe extern "C-unwind" fn(*mut lua_State, c_int) -> T,
n: c_int,
d: T,
) -> T {
if lua::lua_isnoneornil(L, n) != 0 {
d
} else {
f(L, n)
}
}
// //
// TODO: Generic Buffer Manipulation // Generic Buffer Manipulation
// //
#[cfg(target_arch = "wasm32")]
const BUFSIZ: usize = 1024; // WASI libc's BUFSIZ is 1024
#[cfg(not(target_arch = "wasm32"))]
const BUFSIZ: usize = libc::BUFSIZ as usize;
// The buffer size used by the lauxlib buffer system.
// The "16384" workaround is taken from the LuaJIT source code.
pub const LUAL_BUFFERSIZE: usize = if BUFSIZ > 16384 { 8192 } else { BUFSIZ };
#[repr(C)]
pub struct luaL_Buffer {
pub p: *mut c_char, // current position in buffer
pub lvl: c_int, // number of strings in the stack
pub L: *mut lua_State,
pub buffer: [c_char; LUAL_BUFFERSIZE],
}
#[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
pub fn luaL_buffinit(L: *mut lua_State, B: *mut luaL_Buffer);
pub fn luaL_prepbuffer(B: *mut luaL_Buffer) -> *mut c_char;
pub fn luaL_addlstring(B: *mut luaL_Buffer, s: *const c_char, l: usize);
pub fn luaL_addstring(B: *mut luaL_Buffer, s: *const c_char);
pub fn luaL_addvalue(B: *mut luaL_Buffer);
pub fn luaL_pushresult(B: *mut luaL_Buffer);
}
#[inline(always)]
pub unsafe fn luaL_addchar(B: *mut luaL_Buffer, c: c_char) {
let buffer_end = (*B).buffer.as_mut_ptr().add(LUAL_BUFFERSIZE);
if (*B).p >= buffer_end {
luaL_prepbuffer(B);
}
*(*B).p = c;
(*B).p = (*B).p.add(1);
}
#[inline(always)]
pub unsafe fn luaL_addsize(B: *mut luaL_Buffer, n: usize) {
(*B).p = (*B).p.add(n);
}
+4 -1
View File
@@ -270,7 +270,10 @@ pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) {
lua_pushcclosure(L, f, 0) lua_pushcclosure(L, f, 0)
} }
// TODO: lua_strlen #[inline(always)]
pub unsafe fn lua_strlen(L: *mut lua_State, i: c_int) -> usize {
lua_objlen(L, i)
}
#[inline(always)] #[inline(always)]
pub unsafe fn lua_isfunction(L: *mut lua_State, n: c_int) -> c_int { pub unsafe fn lua_isfunction(L: *mut lua_State, n: c_int) -> c_int {
+2 -2
View File
@@ -125,7 +125,7 @@ pub unsafe fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int {
#[inline(always)] #[inline(always)]
pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int { 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"); let n = n.try_into().expect("cannot convert index to c_int");
lua_rawgeti_(L, idx, n); lua_rawgeti_(L, idx, n);
lua_type(L, -1) lua_type(L, -1)
} }
@@ -153,7 +153,7 @@ pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
#[inline(always)] #[inline(always)]
pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) { 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"); let n = n.try_into().expect("cannot convert index to c_int");
lua_rawseti_(L, idx, n) lua_rawseti_(L, idx, n)
} }
+67 -4
View File
@@ -32,7 +32,7 @@ unsafe extern "C-unwind" {
pub fn luaL_argerror(L: *mut lua_State, arg: c_int, extramsg: *const c_char) -> c_int; 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_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) pub fn luaL_optlstring(L: *mut lua_State, arg: c_int, def: *const c_char, l: *mut usize)
-> *const c_char; -> *const c_char;
pub fn luaL_checknumber(L: *mut lua_State, arg: c_int) -> lua_Number; 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_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_checkinteger(L: *mut lua_State, arg: c_int) -> lua_Integer;
@@ -166,13 +166,76 @@ pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
lua::lua_getfield_(L, lua::LUA_REGISTRYINDEX, n); lua::lua_getfield_(L, lua::LUA_REGISTRYINDEX, n);
} }
// luaL_opt would be implemented here but it is undocumented, so it's omitted
#[inline(always)] #[inline(always)]
pub unsafe fn luaL_loadbuffer(L: *mut lua_State, s: *const c_char, sz: usize, n: *const c_char) -> c_int { 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()) luaL_loadbufferx(L, s, sz, n, ptr::null())
} }
#[inline(always)]
pub unsafe fn luaL_opt<T>(
L: *mut lua_State,
f: unsafe extern "C-unwind" fn(*mut lua_State, c_int) -> T,
n: c_int,
d: T,
) -> T {
if lua::lua_isnoneornil(L, n) != 0 {
d
} else {
f(L, n)
}
}
// //
// TODO: Generic Buffer Manipulation // Generic Buffer Manipulation
// //
#[cfg(target_arch = "wasm32")]
const BUFSIZ: usize = 1024; // WASI libc's BUFSIZ is 1024
#[cfg(not(target_arch = "wasm32"))]
const BUFSIZ: usize = libc::BUFSIZ as usize;
// The buffer size used by the lauxlib buffer system.
// The "16384" workaround is taken from the LuaJIT source code.
pub const LUAL_BUFFERSIZE: usize = if BUFSIZ > 16384 { 8192 } else { BUFSIZ };
#[repr(C)]
pub struct luaL_Buffer {
pub b: *mut c_char, // buffer address
pub size: usize, // buffer size
pub n: usize, // number of characters in buffer
pub L: *mut lua_State,
pub initb: [c_char; LUAL_BUFFERSIZE], // initial buffer space
}
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
pub fn luaL_buffinit(L: *mut lua_State, B: *mut luaL_Buffer);
pub fn luaL_prepbuffsize(B: *mut luaL_Buffer, sz: usize) -> *mut c_char;
pub fn luaL_addlstring(B: *mut luaL_Buffer, s: *const c_char, l: usize);
pub fn luaL_addstring(B: *mut luaL_Buffer, s: *const c_char);
pub fn luaL_addvalue(B: *mut luaL_Buffer);
pub fn luaL_pushresult(B: *mut luaL_Buffer);
pub fn luaL_pushresultsize(B: *mut luaL_Buffer, sz: usize);
pub fn luaL_buffinitsize(L: *mut lua_State, B: *mut luaL_Buffer, sz: usize) -> *mut c_char;
}
// Macro implementations as inline functions
#[inline(always)]
pub unsafe fn luaL_prepbuffer(B: *mut luaL_Buffer) -> *mut c_char {
luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
}
#[inline(always)]
pub unsafe fn luaL_addchar(B: *mut luaL_Buffer, c: c_char) {
if (*B).n >= (*B).size {
luaL_prepbuffsize(B, 1);
}
*(*B).b.add((*B).n) = c;
(*B).n += 1;
}
#[inline(always)]
pub unsafe fn luaL_addsize(B: *mut luaL_Buffer, n: usize) {
(*B).n += n;
}
+64 -5
View File
@@ -1,7 +1,7 @@
//! Contains definitions from `lauxlib.h`. //! Contains definitions from `lauxlib.h`.
use std::os::raw::{c_char, c_int, c_void}; use std::os::raw::{c_char, c_int, c_void};
use std::ptr; use std::{mem, ptr};
use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State}; use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State};
@@ -31,7 +31,7 @@ unsafe extern "C-unwind" {
pub fn luaL_argerror(L: *mut lua_State, arg: c_int, extramsg: *const c_char) -> c_int; 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_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) pub fn luaL_optlstring(L: *mut lua_State, arg: c_int, def: *const c_char, l: *mut usize)
-> *const c_char; -> *const c_char;
pub fn luaL_checknumber(L: *mut lua_State, arg: c_int) -> lua_Number; 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_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_checkinteger(L: *mut lua_State, arg: c_int) -> lua_Integer;
@@ -166,13 +166,72 @@ pub unsafe fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) ->
luaL_tolstring_(L, lua::lua_absindex(L, idx), len) luaL_tolstring_(L, lua::lua_absindex(L, idx), len)
} }
// luaL_opt would be implemented here but it is undocumented, so it's omitted
#[inline(always)] #[inline(always)]
pub unsafe fn luaL_loadbuffer(L: *mut lua_State, s: *const c_char, sz: usize, n: *const c_char) -> c_int { 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()) luaL_loadbufferx(L, s, sz, n, ptr::null())
} }
#[inline(always)]
pub unsafe fn luaL_opt<T>(
L: *mut lua_State,
f: unsafe extern "C-unwind" fn(*mut lua_State, c_int) -> T,
n: c_int,
d: T,
) -> T {
if lua::lua_isnoneornil(L, n) != 0 {
d
} else {
f(L, n)
}
}
// //
// TODO: Generic Buffer Manipulation // Generic Buffer Manipulation
// //
// The buffer size used by the lauxlib buffer system.
// In Lua 5.3: LUAL_BUFFERSIZE = (int)(0x80 * sizeof(void*) * sizeof(lua_Integer))
#[rustfmt::skip]
pub const LUAL_BUFFERSIZE: usize = 0x80 * mem::size_of::<*const ()>() * mem::size_of::<lua_Integer>();
#[repr(C)]
pub struct luaL_Buffer {
pub b: *mut c_char, // buffer address
pub size: usize, // buffer size
pub n: usize, // number of characters in buffer
pub L: *mut lua_State,
pub initb: [c_char; LUAL_BUFFERSIZE], // initial buffer space
}
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
pub fn luaL_buffinit(L: *mut lua_State, B: *mut luaL_Buffer);
pub fn luaL_prepbuffsize(B: *mut luaL_Buffer, sz: usize) -> *mut c_char;
pub fn luaL_addlstring(B: *mut luaL_Buffer, s: *const c_char, l: usize);
pub fn luaL_addstring(B: *mut luaL_Buffer, s: *const c_char);
pub fn luaL_addvalue(B: *mut luaL_Buffer);
pub fn luaL_pushresult(B: *mut luaL_Buffer);
pub fn luaL_pushresultsize(B: *mut luaL_Buffer, sz: usize);
pub fn luaL_buffinitsize(L: *mut lua_State, B: *mut luaL_Buffer, sz: usize) -> *mut c_char;
}
// Macro implementations as inline functions
#[inline(always)]
pub unsafe fn luaL_prepbuffer(B: *mut luaL_Buffer) -> *mut c_char {
luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
}
#[inline(always)]
pub unsafe fn luaL_addchar(B: *mut luaL_Buffer, c: c_char) {
if (*B).n >= (*B).size {
luaL_prepbuffsize(B, 1);
}
*(*B).b.add((*B).n) = c;
(*B).n += 1;
}
#[inline(always)]
pub unsafe fn luaL_addsize(B: *mut luaL_Buffer, n: usize) {
(*B).n += n;
}
+95 -7
View File
@@ -1,7 +1,7 @@
//! Contains definitions from `lauxlib.h`. //! Contains definitions from `lauxlib.h`.
use std::os::raw::{c_char, c_int, c_void}; use std::os::raw::{c_char, c_double, c_int, c_long, c_void};
use std::ptr; use std::{mem, ptr};
use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State}; use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State};
@@ -30,7 +30,7 @@ unsafe extern "C-unwind" {
pub fn luaL_argerror(L: *mut lua_State, arg: c_int, extramsg: *const c_char) -> c_int; 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_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) pub fn luaL_optlstring(L: *mut lua_State, arg: c_int, def: *const c_char, l: *mut usize)
-> *const c_char; -> *const c_char;
pub fn luaL_checknumber(L: *mut lua_State, arg: c_int) -> lua_Number; 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_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_checkinteger(L: *mut lua_State, arg: c_int) -> lua_Integer;
@@ -91,7 +91,7 @@ unsafe extern "C-unwind" {
pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer; pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer;
// TODO: luaL_addgsub pub fn luaL_addgsub(B: *mut luaL_Buffer, s: *const c_char, p: *const c_char, r: *const c_char);
pub fn luaL_gsub( pub fn luaL_gsub(
L: *mut lua_State, L: *mut lua_State,
@@ -162,8 +162,6 @@ pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
lua::lua_getfield(L, lua::LUA_REGISTRYINDEX, n); lua::lua_getfield(L, lua::LUA_REGISTRYINDEX, n);
} }
// luaL_opt would be implemented here but it is undocumented, so it's omitted
#[inline(always)] #[inline(always)]
pub unsafe fn luaL_loadbuffer(L: *mut lua_State, s: *const c_char, sz: usize, n: *const c_char) -> c_int { 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()) luaL_loadbufferx(L, s, sz, n, ptr::null())
@@ -188,6 +186,96 @@ pub unsafe fn luaL_loadbufferenv(
status status
} }
#[inline(always)]
pub unsafe fn luaL_opt<T>(
L: *mut lua_State,
f: unsafe extern "C-unwind" fn(*mut lua_State, c_int) -> T,
n: c_int,
d: T,
) -> T {
if lua::lua_isnoneornil(L, n) != 0 {
d
} else {
f(L, n)
}
}
// //
// TODO: Generic Buffer Manipulation // Generic Buffer Manipulation
// //
// The buffer size used by the lauxlib buffer system.
// LUAL_BUFFERSIZE = (int)(16 * sizeof(void*) * sizeof(lua_Number))
#[rustfmt::skip]
pub const LUAL_BUFFERSIZE: usize = 16 * mem::size_of::<*const ()>() * mem::size_of::<lua_Number>();
// Union used for the initial buffer with maximum alignment.
// This ensures proper alignment for the buffer data.
#[repr(C)]
pub union luaL_BufferInit {
// Alignment matches LUAI_MAXALIGN
pub _align_n: lua_Number,
pub _align_u: c_double,
pub _align_s: *mut c_void,
pub _align_i: lua_Integer,
pub _align_l: c_long,
// Initial buffer space
pub b: [c_char; LUAL_BUFFERSIZE],
}
#[repr(C)]
pub struct luaL_Buffer {
pub b: *mut c_char, // buffer address
pub size: usize, // buffer size
pub n: usize, // number of characters in buffer
pub L: *mut lua_State,
pub init: luaL_BufferInit, // initial buffer (union with alignment)
}
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
pub fn luaL_buffinit(L: *mut lua_State, B: *mut luaL_Buffer);
pub fn luaL_prepbuffsize(B: *mut luaL_Buffer, sz: usize) -> *mut c_char;
pub fn luaL_addlstring(B: *mut luaL_Buffer, s: *const c_char, l: usize);
pub fn luaL_addstring(B: *mut luaL_Buffer, s: *const c_char);
pub fn luaL_addvalue(B: *mut luaL_Buffer);
pub fn luaL_pushresult(B: *mut luaL_Buffer);
pub fn luaL_pushresultsize(B: *mut luaL_Buffer, sz: usize);
pub fn luaL_buffinitsize(L: *mut lua_State, B: *mut luaL_Buffer, sz: usize) -> *mut c_char;
}
// Macro implementations as inline functions
#[inline(always)]
pub unsafe fn luaL_prepbuffer(B: *mut luaL_Buffer) -> *mut c_char {
luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
}
#[inline(always)]
pub unsafe fn luaL_addchar(B: *mut luaL_Buffer, c: c_char) {
if (*B).n >= (*B).size {
luaL_prepbuffsize(B, 1);
}
*(*B).b.add((*B).n) = c;
(*B).n += 1;
}
#[inline(always)]
pub unsafe fn luaL_addsize(B: *mut luaL_Buffer, n: usize) {
(*B).n += n;
}
#[inline(always)]
pub unsafe fn luaL_buffsub(B: *mut luaL_Buffer, n: usize) {
(*B).n -= n;
}
#[inline(always)]
pub unsafe fn luaL_bufflen(B: *mut luaL_Buffer) -> usize {
(*B).n
}
#[inline(always)]
pub unsafe fn luaL_buffaddr(B: *mut luaL_Buffer) -> *mut c_char {
(*B).b
}
+299
View File
@@ -0,0 +1,299 @@
//! Contains definitions from `lauxlib.h`.
use std::os::raw::{c_char, c_double, c_int, c_long, c_uint, c_void};
use std::{mem, 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: *const c_char = cstr!("_LOADED");
// Key, in the registry, for table of preloaded loaders
pub const LUA_PRELOAD_TABLE: *const c_char = cstr!("_PRELOAD");
#[repr(C)]
pub struct luaL_Reg {
pub name: *const c_char,
pub func: lua_CFunction,
}
#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
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, ...) -> c_int;
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;
pub fn luaL_alloc(L: *mut lua_State, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void;
}
// Pre-defined references
pub const LUA_NOREF: c_int = -2;
pub const LUA_REFNIL: c_int = -1;
#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
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())
}
#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
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;
#[link_name = "luaL_makeseed"]
pub fn luaL_makeseed_(L: *mut lua_State) -> c_uint;
pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer;
pub fn luaL_addgsub(B: *mut luaL_Buffer, s: *const c_char, p: *const c_char, r: *const c_char);
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);
}
#[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())
}
pub unsafe fn luaL_loadbufferenv(
L: *mut lua_State,
data: *const c_char,
size: usize,
name: *const c_char,
mode: *const c_char,
mut env: c_int,
) -> c_int {
if env != 0 {
env = lua::lua_absindex(L, env);
}
let status = luaL_loadbufferx(L, data, size, name, mode);
if status == lua::LUA_OK && env != 0 {
lua::lua_pushvalue(L, env);
lua::lua_setupvalue(L, -2, 1);
}
status
}
pub unsafe fn luaL_makeseed(L: *mut lua_State) -> c_uint {
#[cfg(macos)]
return libc::arc4random();
#[cfg(linux)]
{
let mut seed = 0u32;
let buf = &mut seed as *mut _ as *mut c_void;
if libc::getrandom(buf, 4, libc::GRND_NONBLOCK) == 4 {
return seed;
}
}
luaL_makeseed_(L)
}
#[inline(always)]
pub unsafe fn luaL_opt<T>(
L: *mut lua_State,
f: unsafe extern "C-unwind" fn(*mut lua_State, c_int) -> T,
n: c_int,
d: T,
) -> T {
if lua::lua_isnoneornil(L, n) != 0 {
d
} else {
f(L, n)
}
}
//
// Generic Buffer Manipulation
//
// The buffer size used by the lauxlib buffer system.
// LUAL_BUFFERSIZE = (int)(16 * sizeof(void*) * sizeof(lua_Number))
#[rustfmt::skip]
pub const LUAL_BUFFERSIZE: usize = 16 * mem::size_of::<*const ()>() * mem::size_of::<lua_Number>();
// Union used for the initial buffer with maximum alignment.
// This ensures proper alignment for the buffer data.
#[repr(C)]
pub union luaL_BufferInit {
// Alignment matches LUAI_MAXALIGN
pub _align_n: lua_Number,
pub _align_u: c_double,
pub _align_s: *mut c_void,
pub _align_i: lua_Integer,
pub _align_l: c_long,
// Initial buffer space
pub b: [c_char; LUAL_BUFFERSIZE],
}
#[repr(C)]
pub struct luaL_Buffer {
pub b: *mut c_char, // buffer address
pub size: usize, // buffer size
pub n: usize, // number of characters in buffer
pub L: *mut lua_State,
pub init: luaL_BufferInit, // initial buffer (union with alignment)
}
#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
pub fn luaL_buffinit(L: *mut lua_State, B: *mut luaL_Buffer);
pub fn luaL_prepbuffsize(B: *mut luaL_Buffer, sz: usize) -> *mut c_char;
pub fn luaL_addlstring(B: *mut luaL_Buffer, s: *const c_char, l: usize);
pub fn luaL_addstring(B: *mut luaL_Buffer, s: *const c_char);
pub fn luaL_addvalue(B: *mut luaL_Buffer);
pub fn luaL_pushresult(B: *mut luaL_Buffer);
pub fn luaL_pushresultsize(B: *mut luaL_Buffer, sz: usize);
pub fn luaL_buffinitsize(L: *mut lua_State, B: *mut luaL_Buffer, sz: usize) -> *mut c_char;
}
// Macro implementations as inline functions
#[inline(always)]
pub unsafe fn luaL_prepbuffer(B: *mut luaL_Buffer) -> *mut c_char {
luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
}
#[inline(always)]
pub unsafe fn luaL_addchar(B: *mut luaL_Buffer, c: c_char) {
if (*B).n >= (*B).size {
luaL_prepbuffsize(B, 1);
}
*(*B).b.add((*B).n) = c;
(*B).n += 1;
}
#[inline(always)]
pub unsafe fn luaL_addsize(B: *mut luaL_Buffer, n: usize) {
(*B).n += n;
}
#[inline(always)]
pub unsafe fn luaL_buffsub(B: *mut luaL_Buffer, n: usize) {
(*B).n -= n;
}
#[inline(always)]
pub unsafe fn luaL_bufflen(B: *mut luaL_Buffer) -> usize {
(*B).n
}
#[inline(always)]
pub unsafe fn luaL_buffaddr(B: *mut luaL_Buffer) -> *mut c_char {
(*B).b
}
+578
View File
@@ -0,0 +1,578 @@
//! Contains definitions from `lua.h`.
use std::ffi::CStr;
use std::marker::{PhantomData, PhantomPinned};
use std::os::raw::{c_char, c_double, c_int, c_uchar, c_uint, c_void};
use std::{mem, 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
#[doc(hidden)]
pub const LUAI_MAXSTACK: c_int = c_int::MAX;
// 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 = -(c_int::MAX / 2 + 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
// index 1 is reserved for the reference mechanism
pub const LUA_RIDX_GLOBALS: lua_Integer = 2;
pub const LUA_RIDX_MAINTHREAD: lua_Integer = 3;
pub const LUA_RIDX_LAST: lua_Integer = 3;
/// 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-unwind" fn(L: *mut lua_State) -> c_int;
/// Type for continuation functions
pub type lua_KFunction =
unsafe extern "C-unwind" 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
#[rustfmt::skip]
pub type lua_Reader =
unsafe extern "C-unwind" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char;
#[rustfmt::skip]
pub type lua_Writer =
unsafe extern "C-unwind" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int;
/// Type for memory-allocation functions (no unwinding)
#[rustfmt::skip]
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-unwind" fn(ud: *mut c_void, msg: *const c_char, tocont: c_int);
#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
//
// State manipulation
//
pub fn lua_newstate(f: lua_Alloc, ud: *mut c_void, seed: c_uint) -> *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_closethread(L: *mut lua_State, from: *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;
#[link_name = "lua_rawlen"]
fn lua_rawlen_(L: *mut lua_State, idx: c_int) -> lua_Unsigned;
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;
}
// lua_rawlen's return type changed from size_t to lua_Unsigned int in Lua 5.4.
// This adapts the crate API to the new Lua ABI.
#[inline(always)]
pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize {
lua_rawlen_(L, idx) as usize
}
//
// 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;
pub const LUA_OPEQ: c_int = 0;
pub const LUA_OPLT: c_int = 1;
pub const LUA_OPLE: c_int = 2;
#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
pub fn lua_arith(L: *mut lua_State, op: c_int);
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;
}
#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
//
// 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_pushexternalstring(
L: *mut lua_State,
s: *const c_char,
len: usize,
falloc: Option<lua_Alloc>,
ud: *mut c_void,
) -> *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)
}
#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
//
// 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
//
#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
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 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_GCISRUNNING: c_int = 6;
pub const LUA_GCGEN: c_int = 7;
pub const LUA_GCINC: c_int = 8;
pub const LUA_GCPARAM: c_int = 9;
// Parameters for GC generational mode
pub const LUA_GCPMINORMUL: c_int = 0; // control minor collections
pub const LUA_GCPMAJORMINOR: c_int = 1; // control shift major->minor
pub const LUA_GCPMINORMAJOR: c_int = 2; // control shift minor->major
// Parameters for GC incremental mode
pub const LUA_GCPPAUSE: c_int = 3; // size of pause between successive GCs
pub const LUA_GCPSTEPMUL: c_int = 4; // GC "speed"
pub const LUA_GCPSTEPSIZE: c_int = 5; // GC granularity
pub const LUA_GCPNUM: c_int = 6; // number of parameters
#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
pub fn lua_gc(L: *mut lua_State, what: c_int, ...) -> c_int;
}
#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
//
// Miscellaneous functions
//
#[link_name = "lua_error"]
fn lua_error_(L: *mut lua_State) -> c_int;
pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_concat(L: *mut lua_State, n: c_int);
pub fn lua_len(L: *mut lua_State, idx: c_int);
pub fn lua_numbertocstring(L: *mut lua_State, idx: c_int, buff: *mut c_char) -> c_uint;
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);
}
// lua_error does not return but is declared to return int, and Rust translates
// ! to void which can cause link-time errors if the platform linker is aware
// of return types and requires they match (for example: wasm does this).
#[inline(always)]
pub unsafe fn lua_error(L: *mut lua_State) -> ! {
lua_error_(L);
unreachable!();
}
//
// 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 CStr) {
lua_pushstring(L, s.as_ptr());
}
#[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_tolightuserdata(L: *mut lua_State, idx: c_int) -> *mut c_void {
if lua_islightuserdata(L, idx) != 0 {
return lua_touserdata(L, idx);
}
ptr::null_mut()
}
#[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-unwind" fn(L: *mut lua_State, ar: *mut lua_Debug);
#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
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, // (n)
pub namewhat: *const c_char, // (n) 'global', 'local', 'field', 'method'
pub what: *const c_char, // (S) 'Lua', 'C', 'main', 'tail'
pub source: *const c_char, // (S)
pub srclen: usize, // (S)
pub currentline: c_int, // (l)
pub linedefined: c_int, // (S)
pub lastlinedefined: c_int, // (S)
pub nups: c_uchar, // (u) number of upvalues
pub nparams: c_uchar, // (u) number of parameters
pub isvararg: c_char, // (u)
pub extraargs: c_uchar, // (t) number of extra arguments
pub istailcall: c_char, // (t)
pub ftransfer: c_int, // (r) index of first value transferred
pub ntransfer: c_int, // (r) number of transferred values
pub short_src: [c_char; LUA_IDSIZE], // (S)
// lua.h mentions this is for private use
i_ci: *mut c_void,
}
+55
View File
@@ -0,0 +1,55 @@
//! Contains definitions from `lualib.h`.
use std::os::raw::{c_char, c_int};
use super::lua::lua_State;
pub const LUA_GLIBK: c_int = 1;
pub const LUA_LOADLIBNAME: *const c_char = cstr!("package");
pub const LUA_LOADLIBK: c_int = LUA_GLIBK << 1;
pub const LUA_COLIBNAME: *const c_char = cstr!("coroutine");
pub const LUA_COLIBK: c_int = LUA_GLIBK << 2;
pub const LUA_DBLIBNAME: *const c_char = cstr!("debug");
pub const LUA_DBLIBK: c_int = LUA_GLIBK << 3;
pub const LUA_IOLIBNAME: *const c_char = cstr!("io");
pub const LUA_IOLIBK: c_int = LUA_GLIBK << 4;
pub const LUA_MATHLIBNAME: *const c_char = cstr!("math");
pub const LUA_MATHLIBK: c_int = LUA_GLIBK << 5;
pub const LUA_OSLIBNAME: *const c_char = cstr!("os");
pub const LUA_OSLIBK: c_int = LUA_GLIBK << 6;
pub const LUA_STRLIBNAME: *const c_char = cstr!("string");
pub const LUA_STRLIBK: c_int = LUA_GLIBK << 7;
pub const LUA_TABLIBNAME: *const c_char = cstr!("table");
pub const LUA_TABLIBK: c_int = LUA_GLIBK << 8;
pub const LUA_UTF8LIBNAME: *const c_char = cstr!("utf8");
pub const LUA_UTF8LIBK: c_int = LUA_GLIBK << 9;
#[cfg_attr(all(windows, raw_dylib), link(name = "lua55", kind = "raw-dylib"))]
unsafe extern "C-unwind" {
pub fn luaopen_base(L: *mut lua_State) -> c_int;
pub fn luaopen_package(L: *mut lua_State) -> c_int;
pub fn luaopen_coroutine(L: *mut lua_State) -> c_int;
pub fn luaopen_debug(L: *mut lua_State) -> c_int;
pub fn luaopen_io(L: *mut lua_State) -> c_int;
pub fn luaopen_math(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_table(L: *mut lua_State) -> c_int;
pub fn luaopen_utf8(L: *mut lua_State) -> c_int;
// open all builtin libraries
pub fn luaL_openselectedlibs(L: *mut lua_State, load: c_int, preload: c_int);
}
pub unsafe fn luaL_openlibs(L: *mut lua_State) {
luaL_openselectedlibs(L, !0, 0);
}
+9
View File
@@ -0,0 +1,9 @@
//! Low level bindings to Lua 5.5.
pub use lauxlib::*;
pub use lua::*;
pub use lualib::*;
pub mod lauxlib;
pub mod lua;
pub mod lualib;
+17 -2
View File
@@ -3,7 +3,7 @@
use std::os::raw::{c_char, c_float, c_int, c_void}; use std::os::raw::{c_char, c_float, c_int, c_void};
use std::ptr; use std::ptr;
use super::lua::{self, lua_CFunction, lua_Number, lua_State, lua_Unsigned, LUA_REGISTRYINDEX}; use super::lua::{self, LUA_REGISTRYINDEX, lua_CFunction, lua_Number, lua_State, lua_Unsigned};
// Key, in the registry, for table of loaded modules // Key, in the registry, for table of loaded modules
pub const LUA_LOADED_TABLE: *const c_char = cstr!("_LOADED"); pub const LUA_LOADED_TABLE: *const c_char = cstr!("_LOADED");
@@ -85,6 +85,9 @@ unsafe extern "C-unwind" {
pub fn luaL_callyieldable(L: *mut lua_State, nargs: c_int, nresults: c_int) -> c_int; pub fn luaL_callyieldable(L: *mut lua_State, nargs: c_int, nresults: c_int) -> c_int;
#[link_name = "luaL_traceback"]
pub fn luaL_traceback_(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, level: c_int);
// sandbox libraries and globals // sandbox libraries and globals
#[link_name = "luaL_sandbox"] #[link_name = "luaL_sandbox"]
pub fn luaL_sandbox_(L: *mut lua_State); pub fn luaL_sandbox_(L: *mut lua_State);
@@ -119,7 +122,19 @@ pub unsafe fn luaL_optstring(L: *mut lua_State, n: c_int, d: *const c_char) -> *
luaL_optlstring(L, n, d, ptr::null_mut()) luaL_optlstring(L, n, d, ptr::null_mut())
} }
// TODO: luaL_opt #[inline(always)]
pub unsafe fn luaL_opt<T>(
L: *mut lua_State,
f: unsafe extern "C-unwind" fn(*mut lua_State, c_int) -> T,
n: c_int,
d: T,
) -> T {
if lua::lua_isnoneornil(L, n) != 0 {
d
} else {
f(L, n)
}
}
#[inline(always)] #[inline(always)]
pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) -> c_int { pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) -> c_int {
+31 -3
View File
@@ -37,6 +37,16 @@ pub const LUA_ERRRUN: c_int = 2;
pub const LUA_ERRSYNTAX: c_int = 3; pub const LUA_ERRSYNTAX: c_int = 3;
pub const LUA_ERRMEM: c_int = 4; pub const LUA_ERRMEM: c_int = 4;
pub const LUA_ERRERR: c_int = 5; pub const LUA_ERRERR: c_int = 5;
pub const LUA_BREAK: c_int = 6; // yielded for a debug breakpoint
//
// Coroutine status
//
pub const LUA_CORUN: c_int = 0; // running
pub const LUA_COSUS: c_int = 1; // suspended
pub const LUA_CONOR: c_int = 2; // 'normal' (it resumed another coroutine)
pub const LUA_COFIN: c_int = 3; // finished
pub const LUA_COERR: c_int = 4; // finished with error
/// A raw Lua state associated with a thread. /// A raw Lua state associated with a thread.
#[repr(C)] #[repr(C)]
@@ -145,8 +155,15 @@ unsafe extern "C-unwind" {
pub fn lua_toboolean(L: *mut lua_State, idx: c_int) -> c_int; pub fn lua_toboolean(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char; pub fn lua_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char;
pub fn lua_tostringatom(L: *mut lua_State, idx: c_int, atom: *mut c_int) -> *const c_char; pub fn lua_tostringatom(L: *mut lua_State, idx: c_int, atom: *mut c_int) -> *const c_char;
pub fn lua_tolstringatom(
L: *mut lua_State,
idx: c_int,
len: *mut usize,
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_namecallatom(L: *mut lua_State, atom: *mut c_int) -> *const c_char;
pub fn lua_objlen(L: *mut lua_State, idx: c_int) -> usize; #[link_name = "lua_objlen"]
pub fn lua_objlen_(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_tocfunction(L: *mut lua_State, idx: c_int) -> Option<lua_CFunction>; 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_tolightuserdata(L: *mut lua_State, idx: c_int) -> *mut c_void;
pub fn lua_tolightuserdatatagged(L: *mut lua_State, idx: c_int, tag: c_int) -> *mut c_void; pub fn lua_tolightuserdatatagged(L: *mut lua_State, idx: c_int, tag: c_int) -> *mut c_void;
@@ -218,6 +235,7 @@ unsafe extern "C-unwind" {
// //
pub fn lua_settable(L: *mut lua_State, idx: c_int); pub fn lua_settable(L: *mut lua_State, idx: c_int);
pub fn lua_setfield(L: *mut lua_State, idx: c_int, k: *const c_char); pub fn lua_setfield(L: *mut lua_State, idx: c_int, k: *const c_char);
pub fn lua_rawsetfield(L: *mut lua_State, idx: c_int, k: *const c_char);
pub fn lua_rawset(L: *mut lua_State, idx: c_int); pub fn lua_rawset(L: *mut lua_State, idx: c_int);
#[link_name = "lua_rawseti"] #[link_name = "lua_rawseti"]
pub fn lua_rawseti_(L: *mut lua_State, idx: c_int, n: c_int); pub fn lua_rawseti_(L: *mut lua_State, idx: c_int, n: c_int);
@@ -251,6 +269,12 @@ unsafe extern "C-unwind" {
pub fn lua_isyieldable(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_getthreaddata(L: *mut lua_State) -> *mut c_void;
pub fn lua_setthreaddata(L: *mut lua_State, data: *mut c_void); pub fn lua_setthreaddata(L: *mut lua_State, data: *mut c_void);
pub fn lua_costatus(L: *mut lua_State, co: *mut lua_State) -> c_int;
}
#[inline(always)]
pub unsafe fn lua_objlen(L: *mut lua_State, idx: c_int) -> usize {
lua_objlen_(L, idx) as usize
} }
// //
@@ -287,7 +311,7 @@ unsafe extern "C-unwind" {
pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int; pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_rawiter(L: *mut lua_State, idx: c_int, iter: 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); pub fn lua_concat(L: *mut lua_State, n: c_int);
// TODO: lua_encodepointer pub fn lua_encodepointer(L: *mut lua_State, p: usize) -> usize;
pub fn lua_clock() -> c_double; pub fn lua_clock() -> c_double;
pub fn lua_setuserdatatag(L: *mut lua_State, idx: c_int, tag: c_int); 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<lua_Destructor>); pub fn lua_setuserdatadtor(L: *mut lua_State, tag: c_int, dtor: Option<lua_Destructor>);
@@ -298,6 +322,7 @@ unsafe extern "C-unwind" {
pub fn lua_getlightuserdataname(L: *mut lua_State, tag: c_int) -> *const c_char; pub fn lua_getlightuserdataname(L: *mut lua_State, tag: c_int) -> *const c_char;
pub fn lua_clonefunction(L: *mut lua_State, idx: c_int); pub fn lua_clonefunction(L: *mut lua_State, idx: c_int);
pub fn lua_cleartable(L: *mut lua_State, idx: c_int); pub fn lua_cleartable(L: *mut lua_State, idx: c_int);
pub fn lua_clonetable(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_getallocf(L: *mut lua_State, ud: *mut *mut c_void) -> lua_Alloc;
} }
@@ -357,7 +382,10 @@ pub unsafe fn lua_newuserdata_t<T>(L: *mut lua_State, data: T) -> *mut T {
ud_ptr ud_ptr
} }
// TODO: lua_strlen #[inline(always)]
pub unsafe fn lua_strlen(L: *mut lua_State, i: c_int) -> usize {
lua_objlen(L, i)
}
#[inline(always)] #[inline(always)]
pub unsafe fn lua_isfunction(L: *mut lua_State, n: c_int) -> c_int { pub unsafe fn lua_isfunction(L: *mut lua_State, n: c_int) -> c_int {
+12
View File
@@ -58,6 +58,18 @@ pub struct luarequire_Configuration {
path: *const c_char, path: *const c_char,
) -> luarequire_NavigateResult, ) -> luarequire_NavigateResult,
// Provides an initial alias override opportunity prior to searching for configuration files.
// If NAVIGATE_SUCCESS is returned, the internal state must be updated to point at the
// aliased location.
// Can be left undefined.
pub to_alias_override: Option<
unsafe extern "C-unwind" fn(
L: *mut lua_State,
ctx: *mut c_void,
alias_unprefixed: *const c_char,
) -> luarequire_NavigateResult,
>,
// Provides a final override opportunity if an alias cannot be found in configuration files. If // Provides a final override opportunity if an alias cannot be found in configuration files. If
// NAVIGATE_SUCCESS is returned, this must update the internal state to point at the aliased module. // NAVIGATE_SUCCESS is returned, this must update the internal state to point at the aliased module.
// Can be left undefined. // Can be left undefined.
+3 -3
View File
@@ -97,7 +97,7 @@ struct BufferCursor(Buffer, usize);
impl io::Read for BufferCursor { impl io::Read for BufferCursor {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let lua = self.0 .0.lua.lock(); let lua = self.0.0.lua.lock();
let data = self.0.as_slice(&lua); let data = self.0.as_slice(&lua);
if self.1 == data.len() { if self.1 == data.len() {
return Ok(0); return Ok(0);
@@ -111,7 +111,7 @@ impl io::Read for BufferCursor {
impl io::Write for BufferCursor { impl io::Write for BufferCursor {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let lua = self.0 .0.lua.lock(); let lua = self.0.0.lua.lock();
let data = self.0.as_slice_mut(&lua); let data = self.0.as_slice_mut(&lua);
if self.1 == data.len() { if self.1 == data.len() {
return Ok(0); return Ok(0);
@@ -129,7 +129,7 @@ impl io::Write for BufferCursor {
impl io::Seek for BufferCursor { impl io::Seek for BufferCursor {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> { fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
let lua = self.0 .0.lua.lock(); let lua = self.0.0.lua.lock();
let data = self.0.as_slice(&lua); let data = self.0.as_slice(&lua);
let new_offset = match pos { let new_offset = match pos {
io::SeekFrom::Start(offset) => offset as i64, io::SeekFrom::Start(offset) => offset as i64,
+67 -71
View File
@@ -4,7 +4,6 @@ use std::ffi::CString;
use std::io::Result as IoResult; use std::io::Result as IoResult;
use std::panic::Location; use std::panic::Location;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::string::String as StdString;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::function::Function; use crate::function::Function;
@@ -20,7 +19,7 @@ pub trait AsChunk {
/// Returns optional chunk name /// Returns optional chunk name
/// ///
/// See [`Chunk::set_name`] for possible name prefixes. /// See [`Chunk::set_name`] for possible name prefixes.
fn name(&self) -> Option<StdString> { fn name(&self) -> Option<String> {
None None
} }
@@ -52,13 +51,13 @@ impl AsChunk for &str {
} }
} }
impl AsChunk for StdString { impl AsChunk for String {
fn source<'a>(&self) -> IoResult<Cow<'a, [u8]>> { fn source<'a>(&self) -> IoResult<Cow<'a, [u8]>> {
Ok(Cow::Owned(self.clone().into_bytes())) Ok(Cow::Owned(self.clone().into_bytes()))
} }
} }
impl AsChunk for &StdString { impl AsChunk for &String {
fn source<'a>(&self) -> IoResult<Cow<'a, [u8]>> fn source<'a>(&self) -> IoResult<Cow<'a, [u8]>>
where where
Self: 'a, Self: 'a,
@@ -92,7 +91,7 @@ impl AsChunk for &Vec<u8> {
} }
impl AsChunk for &Path { impl AsChunk for &Path {
fn name(&self) -> Option<StdString> { fn name(&self) -> Option<String> {
Some(format!("@{}", self.display())) Some(format!("@{}", self.display()))
} }
@@ -102,7 +101,7 @@ impl AsChunk for &Path {
} }
impl AsChunk for PathBuf { impl AsChunk for PathBuf {
fn name(&self) -> Option<StdString> { fn name(&self) -> Option<String> {
Some(format!("@{}", self.display())) Some(format!("@{}", self.display()))
} }
@@ -112,7 +111,7 @@ impl AsChunk for PathBuf {
} }
impl<C: AsChunk + ?Sized> AsChunk for Box<C> { impl<C: AsChunk + ?Sized> AsChunk for Box<C> {
fn name(&self) -> Option<StdString> { fn name(&self) -> Option<String> {
(**self).name() (**self).name()
} }
@@ -136,7 +135,7 @@ impl<C: AsChunk + ?Sized> AsChunk for Box<C> {
#[must_use = "`Chunk`s do nothing unless one of `exec`, `eval`, `call`, or `into_function` are called on them"] #[must_use = "`Chunk`s do nothing unless one of `exec`, `eval`, `call`, or `into_function` are called on them"]
pub struct Chunk<'a> { pub struct Chunk<'a> {
pub(crate) lua: WeakLua, pub(crate) lua: WeakLua,
pub(crate) name: StdString, pub(crate) name: String,
pub(crate) env: Result<Option<Table>>, pub(crate) env: Result<Option<Table>>,
pub(crate) mode: Option<ChunkMode>, pub(crate) mode: Option<ChunkMode>,
pub(crate) source: IoResult<Cow<'a, [u8]>>, pub(crate) source: IoResult<Cow<'a, [u8]>>,
@@ -160,7 +159,7 @@ pub enum CompileConstant {
Boolean(bool), Boolean(bool),
Number(crate::Number), Number(crate::Number),
Vector(crate::Vector), Vector(crate::Vector),
String(StdString), String(String),
} }
#[cfg(any(feature = "luau", doc))] #[cfg(any(feature = "luau", doc))]
@@ -192,7 +191,7 @@ impl From<&str> for CompileConstant {
} }
#[cfg(any(feature = "luau", doc))] #[cfg(any(feature = "luau", doc))]
type LibraryMemberConstantMap = HashMap<(StdString, StdString), CompileConstant>; type LibraryMemberConstantMap = HashMap<(String, String), CompileConstant>;
/// Luau compiler /// Luau compiler
#[cfg(any(feature = "luau", doc))] #[cfg(any(feature = "luau", doc))]
@@ -203,14 +202,14 @@ pub struct Compiler {
debug_level: u8, debug_level: u8,
type_info_level: u8, type_info_level: u8,
coverage_level: u8, coverage_level: u8,
vector_lib: Option<StdString>, vector_lib: Option<String>,
vector_ctor: Option<StdString>, vector_ctor: Option<String>,
vector_type: Option<StdString>, vector_type: Option<String>,
mutable_globals: Vec<StdString>, mutable_globals: Vec<String>,
userdata_types: Vec<StdString>, userdata_types: Vec<String>,
libraries_with_known_members: Vec<StdString>, libraries_with_known_members: Vec<String>,
library_constants: Option<LibraryMemberConstantMap>, library_constants: Option<LibraryMemberConstantMap>,
disabled_builtins: Vec<StdString>, disabled_builtins: Vec<String>,
} }
#[cfg(any(feature = "luau", doc))] #[cfg(any(feature = "luau", doc))]
@@ -294,7 +293,7 @@ impl Compiler {
/// To set the library and method name, use the `lib.ctor` format. /// To set the library and method name, use the `lib.ctor` format.
#[doc(hidden)] #[doc(hidden)]
#[must_use] #[must_use]
pub fn set_vector_ctor(mut self, ctor: impl Into<StdString>) -> Self { pub fn set_vector_ctor(mut self, ctor: impl Into<String>) -> Self {
let ctor = ctor.into(); let ctor = ctor.into();
let lib_ctor = ctor.split_once('.'); let lib_ctor = ctor.split_once('.');
self.vector_lib = lib_ctor.as_ref().map(|&(lib, _)| lib.to_owned()); self.vector_lib = lib_ctor.as_ref().map(|&(lib, _)| lib.to_owned());
@@ -307,7 +306,7 @@ impl Compiler {
/// Sets alternative vector type name for type tables, in addition to default type `vector`. /// Sets alternative vector type name for type tables, in addition to default type `vector`.
#[doc(hidden)] #[doc(hidden)]
#[must_use] #[must_use]
pub fn set_vector_type(mut self, r#type: impl Into<StdString>) -> Self { pub fn set_vector_type(mut self, r#type: impl Into<String>) -> Self {
self.vector_type = Some(r#type.into()); self.vector_type = Some(r#type.into());
self self
} }
@@ -316,7 +315,7 @@ impl Compiler {
/// ///
/// It disables the import optimization for fields accessed through it. /// It disables the import optimization for fields accessed through it.
#[must_use] #[must_use]
pub fn add_mutable_global(mut self, global: impl Into<StdString>) -> Self { pub fn add_mutable_global(mut self, global: impl Into<String>) -> Self {
self.mutable_globals.push(global.into()); self.mutable_globals.push(global.into());
self self
} }
@@ -325,21 +324,21 @@ impl Compiler {
/// ///
/// It disables the import optimization for fields accessed through these. /// It disables the import optimization for fields accessed through these.
#[must_use] #[must_use]
pub fn set_mutable_globals<S: Into<StdString>>(mut self, globals: impl IntoIterator<Item = S>) -> Self { pub fn set_mutable_globals<S: Into<String>>(mut self, globals: impl IntoIterator<Item = S>) -> Self {
self.mutable_globals = globals.into_iter().map(|s| s.into()).collect(); self.mutable_globals = globals.into_iter().map(|s| s.into()).collect();
self self
} }
/// Adds a userdata type to the list that will be included in the type information. /// Adds a userdata type to the list that will be included in the type information.
#[must_use] #[must_use]
pub fn add_userdata_type(mut self, r#type: impl Into<StdString>) -> Self { pub fn add_userdata_type(mut self, r#type: impl Into<String>) -> Self {
self.userdata_types.push(r#type.into()); self.userdata_types.push(r#type.into());
self self
} }
/// Sets a list of userdata types that will be included in the type information. /// Sets a list of userdata types that will be included in the type information.
#[must_use] #[must_use]
pub fn set_userdata_types<S: Into<StdString>>(mut self, types: impl IntoIterator<Item = S>) -> Self { pub fn set_userdata_types<S: Into<String>>(mut self, types: impl IntoIterator<Item = S>) -> Self {
self.userdata_types = types.into_iter().map(|s| s.into()).collect(); self.userdata_types = types.into_iter().map(|s| s.into()).collect();
self self
} }
@@ -366,24 +365,21 @@ impl Compiler {
self.libraries_with_known_members.push(lib.clone()); self.libraries_with_known_members.push(lib.clone());
} }
self.library_constants self.library_constants
.get_or_insert_with(HashMap::new) .get_or_insert_default()
.insert((lib, member), r#const.into()); .insert((lib, member), r#const.into());
self self
} }
/// Adds a builtin that should be disabled. /// Adds a builtin that should be disabled.
#[must_use] #[must_use]
pub fn add_disabled_builtin(mut self, builtin: impl Into<StdString>) -> Self { pub fn add_disabled_builtin(mut self, builtin: impl Into<String>) -> Self {
self.disabled_builtins.push(builtin.into()); self.disabled_builtins.push(builtin.into());
self self
} }
/// Sets a list of builtins that should be disabled. /// Sets a list of builtins that should be disabled.
#[must_use] #[must_use]
pub fn set_disabled_builtins<S: Into<StdString>>( pub fn set_disabled_builtins<S: Into<String>>(mut self, builtins: impl IntoIterator<Item = S>) -> Self {
mut self,
builtins: impl IntoIterator<Item = S>,
) -> Self {
self.disabled_builtins = builtins.into_iter().map(|s| s.into()).collect(); self.disabled_builtins = builtins.into_iter().map(|s| s.into()).collect();
self self
} }
@@ -477,11 +473,11 @@ impl Compiler {
options.mutableGlobals = mutable_globals_ptr; options.mutableGlobals = mutable_globals_ptr;
options.userdataTypes = userdata_types_ptr; options.userdataTypes = userdata_types_ptr;
options.librariesWithKnownMembers = libraries_with_known_members_ptr; options.librariesWithKnownMembers = libraries_with_known_members_ptr;
if let Some(map) = self.library_constants.as_ref() { if let Some(map) = self.library_constants.as_ref()
if !self.libraries_with_known_members.is_empty() { && !self.libraries_with_known_members.is_empty()
LIBRARY_MEMBER_CONSTANT_MAP.with_borrow_mut(|gmap| *gmap = map.clone()); {
options.libraryMemberConstantCallback = Some(library_member_constant_callback); LIBRARY_MEMBER_CONSTANT_MAP.with_borrow_mut(|gmap| *gmap = map.clone());
} options.libraryMemberConstantCallback = Some(library_member_constant_callback);
} }
options.disabledBuiltins = disabled_builtins_ptr; options.disabledBuiltins = disabled_builtins_ptr;
ffi::luau_compile(source.as_ref(), options) ffi::luau_compile(source.as_ref(), options)
@@ -490,7 +486,7 @@ impl Compiler {
if bytecode.first() == Some(&0) { if bytecode.first() == Some(&0) {
// The rest of the bytecode is the error message starting with `:` // The rest of the bytecode is the error message starting with `:`
// See https://github.com/luau-lang/luau/blob/0.640/Compiler/src/Compiler.cpp#L4336 // See https://github.com/luau-lang/luau/blob/0.640/Compiler/src/Compiler.cpp#L4336
let message = StdString::from_utf8_lossy(&bytecode[2..]).into_owned(); let message = String::from_utf8_lossy(&bytecode[2..]).into_owned();
return Err(Error::SyntaxError { return Err(Error::SyntaxError {
incomplete_input: message.ends_with("<eof>"), incomplete_input: message.ends_with("<eof>"),
message, message,
@@ -513,7 +509,7 @@ impl Chunk<'_> {
/// - `@` - file path (when truncation is needed, the end of the file path is kept, as this is /// - `@` - file path (when truncation is needed, the end of the file path is kept, as this is
/// more useful for identifying the file) /// more useful for identifying the file)
/// - `=` - custom chunk name (when truncation is needed, the beginning of the name is kept) /// - `=` - custom chunk name (when truncation is needed, the beginning of the name is kept)
pub fn set_name(mut self, name: impl Into<StdString>) -> Self { pub fn set_name(mut self, name: impl Into<String>) -> Self {
self.name = name.into(); self.name = name.into();
self self
} }
@@ -662,19 +658,19 @@ impl Chunk<'_> {
/// ///
/// It does nothing if the chunk is already binary or invalid. /// It does nothing if the chunk is already binary or invalid.
fn compile(&mut self) { fn compile(&mut self) {
if let Ok(ref source) = self.source { if let Ok(ref source) = self.source
if self.detect_mode() == ChunkMode::Text { && self.detect_mode() == ChunkMode::Text
#[cfg(feature = "luau")] {
if let Ok(data) = self.compiler.get_or_insert_with(Default::default).compile(source) { #[cfg(feature = "luau")]
self.source = Ok(Cow::Owned(data)); if let Ok(data) = self.compiler.get_or_insert_default().compile(source) {
self.mode = Some(ChunkMode::Binary); self.source = Ok(Cow::Owned(data));
} self.mode = Some(ChunkMode::Binary);
#[cfg(not(feature = "luau"))] }
if let Ok(func) = self.lua.lock().load_chunk(None, None, None, source.as_ref()) { #[cfg(not(feature = "luau"))]
let data = func.dump(false); if let Ok(func) = self.lua.lock().load_chunk(None, None, None, source.as_ref()) {
self.source = Ok(Cow::Owned(data)); let data = func.dump(false);
self.mode = Some(ChunkMode::Binary); self.source = Ok(Cow::Owned(data));
} self.mode = Some(ChunkMode::Binary);
} }
} }
} }
@@ -687,33 +683,33 @@ impl Chunk<'_> {
// Try to fetch compiled chunk from cache // Try to fetch compiled chunk from cache
let mut text_source = None; let mut text_source = None;
if let Ok(ref source) = self.source { if let Ok(ref source) = self.source
if self.detect_mode() == ChunkMode::Text { && self.detect_mode() == ChunkMode::Text
let lua = self.lua.lock(); {
if let Some(cache) = lua.priv_app_data_ref::<ChunksCache>() { let lua = self.lua.lock();
if let Some(data) = cache.0.get(source.as_ref()) { if let Some(cache) = lua.priv_app_data_ref::<ChunksCache>()
self.source = Ok(Cow::Owned(data.clone())); && let Some(data) = cache.0.get(source.as_ref())
self.mode = Some(ChunkMode::Binary); {
return self; self.source = Ok(Cow::Owned(data.clone()));
} self.mode = Some(ChunkMode::Binary);
} return self;
text_source = Some(source.as_ref().to_vec());
} }
text_source = Some(source.as_ref().to_vec());
} }
// Compile and cache the chunk // Compile and cache the chunk
if let Some(text_source) = text_source { if let Some(text_source) = text_source {
self.compile(); self.compile();
if let Ok(ref binary_source) = self.source { if let Ok(ref binary_source) = self.source
if self.detect_mode() == ChunkMode::Binary { && self.detect_mode() == ChunkMode::Binary
let lua = self.lua.lock(); {
if let Some(mut cache) = lua.priv_app_data_mut::<ChunksCache>() { let lua = self.lua.lock();
cache.0.insert(text_source, binary_source.to_vec()); if let Some(mut cache) = lua.priv_app_data_mut::<ChunksCache>() {
} else { cache.0.insert(text_source, binary_source.to_vec());
let mut cache = ChunksCache(HashMap::new()); } else {
cache.0.insert(text_source, binary_source.to_vec()); let mut cache = ChunksCache(HashMap::new());
lua.set_priv_app_data(cache); cache.0.insert(text_source, binary_source.to_vec());
}; lua.set_priv_app_data(cache);
} }
} }
} }
@@ -761,7 +757,7 @@ impl Chunk<'_> {
ChunkMode::Text ChunkMode::Text
} }
fn convert_name(name: StdString) -> Result<CString> { fn convert_name(name: String) -> Result<CString> {
CString::new(name).map_err(|err| Error::runtime(format!("invalid name: {err}"))) CString::new(name).map_err(|err| Error::runtime(format!("invalid name: {err}")))
} }
+138 -195
View File
@@ -4,16 +4,15 @@ use std::ffi::{CStr, CString, OsStr, OsString};
use std::hash::{BuildHasher, Hash}; use std::hash::{BuildHasher, Hash};
use std::os::raw::c_int; use std::os::raw::c_int;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::string::String as StdString;
use std::{mem, slice, str}; use std::{mem, slice, str};
use bstr::{BStr, BString, ByteSlice, ByteVec}; use bstr::{BStr, BString, ByteVec};
use num_traits::cast; use num_traits::cast;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::function::Function; use crate::function::Function;
use crate::state::{Lua, RawLua}; use crate::state::{Lua, RawLua};
use crate::string::{BorrowedBytes, BorrowedStr, String}; use crate::string::{BorrowedBytes, BorrowedStr, LuaString};
use crate::table::Table; use crate::table::Table;
use crate::thread::Thread; use crate::thread::Thread;
use crate::traits::{FromLua, IntoLua, ShortTypeName as _}; use crate::traits::{FromLua, IntoLua, ShortTypeName as _};
@@ -47,14 +46,14 @@ impl FromLua for Value {
} }
} }
impl IntoLua for String { impl IntoLua for LuaString {
#[inline] #[inline]
fn into_lua(self, _: &Lua) -> Result<Value> { fn into_lua(self, _: &Lua) -> Result<Value> {
Ok(Value::String(self)) Ok(Value::String(self))
} }
} }
impl IntoLua for &String { impl IntoLua for &LuaString {
#[inline] #[inline]
fn into_lua(self, _: &Lua) -> Result<Value> { fn into_lua(self, _: &Lua) -> Result<Value> {
Ok(Value::String(self.clone())) Ok(Value::String(self.clone()))
@@ -67,16 +66,12 @@ impl IntoLua for &String {
} }
} }
impl FromLua for String { impl FromLua for LuaString {
#[inline] #[inline]
fn from_lua(value: Value, lua: &Lua) -> Result<String> { fn from_lua(value: Value, lua: &Lua) -> Result<LuaString> {
let ty = value.type_name(); let ty = value.type_name();
lua.coerce_string(value)? lua.coerce_string(value)?
.ok_or_else(|| Error::FromLuaConversionError { .ok_or_else(|| Error::from_lua_conversion(ty, "string", "expected string or number".to_string()))
from: ty,
to: "string".to_string(),
message: Some("expected string or number".to_string()),
})
} }
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> { unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
@@ -84,7 +79,7 @@ impl FromLua for String {
let type_id = ffi::lua_type(state, idx); let type_id = ffi::lua_type(state, idx);
if type_id == ffi::LUA_TSTRING { if type_id == ffi::LUA_TSTRING {
ffi::lua_xpush(state, lua.ref_thread(), idx); ffi::lua_xpush(state, lua.ref_thread(), idx);
return Ok(String(lua.pop_ref_thread())); return Ok(LuaString(lua.pop_ref_thread()));
} }
// Fallback to default // Fallback to default
Self::from_lua(lua.stack_value(idx, Some(type_id)), lua.lua()) Self::from_lua(lua.stack_value(idx, Some(type_id)), lua.lua())
@@ -119,7 +114,7 @@ impl IntoLua for &BorrowedStr<'_> {
impl FromLua for BorrowedStr<'_> { impl FromLua for BorrowedStr<'_> {
fn from_lua(value: Value, lua: &Lua) -> Result<Self> { fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
let s = String::from_lua(value, lua)?; let s = LuaString::from_lua(value, lua)?;
let BorrowedStr { buf, _lua, .. } = BorrowedStr::try_from(&s)?; let BorrowedStr { buf, _lua, .. } = BorrowedStr::try_from(&s)?;
let buf = unsafe { mem::transmute::<&str, &'static str>(buf) }; let buf = unsafe { mem::transmute::<&str, &'static str>(buf) };
let borrow = Cow::Owned(s); let borrow = Cow::Owned(s);
@@ -127,7 +122,7 @@ impl FromLua for BorrowedStr<'_> {
} }
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> { unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
let s = String::from_stack(idx, lua)?; let s = LuaString::from_stack(idx, lua)?;
let BorrowedStr { buf, _lua, .. } = BorrowedStr::try_from(&s)?; let BorrowedStr { buf, _lua, .. } = BorrowedStr::try_from(&s)?;
let buf = unsafe { mem::transmute::<&str, &'static str>(buf) }; let buf = unsafe { mem::transmute::<&str, &'static str>(buf) };
let borrow = Cow::Owned(s); let borrow = Cow::Owned(s);
@@ -163,7 +158,7 @@ impl IntoLua for &BorrowedBytes<'_> {
impl FromLua for BorrowedBytes<'_> { impl FromLua for BorrowedBytes<'_> {
fn from_lua(value: Value, lua: &Lua) -> Result<Self> { fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
let s = String::from_lua(value, lua)?; let s = LuaString::from_lua(value, lua)?;
let BorrowedBytes { buf, _lua, .. } = BorrowedBytes::from(&s); let BorrowedBytes { buf, _lua, .. } = BorrowedBytes::from(&s);
let buf = unsafe { mem::transmute::<&[u8], &'static [u8]>(buf) }; let buf = unsafe { mem::transmute::<&[u8], &'static [u8]>(buf) };
let borrow = Cow::Owned(s); let borrow = Cow::Owned(s);
@@ -171,7 +166,7 @@ impl FromLua for BorrowedBytes<'_> {
} }
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> { unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
let s = String::from_stack(idx, lua)?; let s = LuaString::from_stack(idx, lua)?;
let BorrowedBytes { buf, _lua, .. } = BorrowedBytes::from(&s); let BorrowedBytes { buf, _lua, .. } = BorrowedBytes::from(&s);
let buf = unsafe { mem::transmute::<&[u8], &'static [u8]>(buf) }; let buf = unsafe { mem::transmute::<&[u8], &'static [u8]>(buf) };
let borrow = Cow::Owned(s); let borrow = Cow::Owned(s);
@@ -204,11 +199,7 @@ impl FromLua for Table {
fn from_lua(value: Value, _: &Lua) -> Result<Table> { fn from_lua(value: Value, _: &Lua) -> Result<Table> {
match value { match value {
Value::Table(table) => Ok(table), Value::Table(table) => Ok(table),
_ => Err(Error::FromLuaConversionError { _ => Err(Error::from_lua_conversion(value.type_name(), "table", None)),
from: value.type_name(),
to: "table".to_string(),
message: None,
}),
} }
} }
} }
@@ -238,11 +229,7 @@ impl FromLua for Function {
fn from_lua(value: Value, _: &Lua) -> Result<Function> { fn from_lua(value: Value, _: &Lua) -> Result<Function> {
match value { match value {
Value::Function(table) => Ok(table), Value::Function(table) => Ok(table),
_ => Err(Error::FromLuaConversionError { _ => Err(Error::from_lua_conversion(value.type_name(), "function", None)),
from: value.type_name(),
to: "function".to_string(),
message: None,
}),
} }
} }
} }
@@ -272,11 +259,7 @@ impl FromLua for Thread {
fn from_lua(value: Value, _: &Lua) -> Result<Thread> { fn from_lua(value: Value, _: &Lua) -> Result<Thread> {
match value { match value {
Value::Thread(t) => Ok(t), Value::Thread(t) => Ok(t),
_ => Err(Error::FromLuaConversionError { _ => Err(Error::from_lua_conversion(value.type_name(), "thread", None)),
from: value.type_name(),
to: "thread".to_string(),
message: None,
}),
} }
} }
} }
@@ -306,11 +289,7 @@ impl FromLua for AnyUserData {
fn from_lua(value: Value, _: &Lua) -> Result<AnyUserData> { fn from_lua(value: Value, _: &Lua) -> Result<AnyUserData> {
match value { match value {
Value::UserData(ud) => Ok(ud), Value::UserData(ud) => Ok(ud),
_ => Err(Error::FromLuaConversionError { _ => Err(Error::from_lua_conversion(value.type_name(), "userdata", None)),
from: value.type_name(),
to: "userdata".to_string(),
message: None,
}),
} }
} }
} }
@@ -428,11 +407,11 @@ impl FromLua for LightUserData {
fn from_lua(value: Value, _: &Lua) -> Result<Self> { fn from_lua(value: Value, _: &Lua) -> Result<Self> {
match value { match value {
Value::LightUserData(ud) => Ok(ud), Value::LightUserData(ud) => Ok(ud),
_ => Err(Error::FromLuaConversionError { _ => Err(Error::from_lua_conversion(
from: value.type_name(), value.type_name(),
to: "lightuserdata".to_string(), "lightuserdata",
message: None, None,
}), )),
} }
} }
} }
@@ -451,11 +430,7 @@ impl FromLua for crate::Vector {
fn from_lua(value: Value, _: &Lua) -> Result<Self> { fn from_lua(value: Value, _: &Lua) -> Result<Self> {
match value { match value {
Value::Vector(v) => Ok(v), Value::Vector(v) => Ok(v),
_ => Err(Error::FromLuaConversionError { _ => Err(Error::from_lua_conversion(value.type_name(), "vector", None)),
from: value.type_name(),
to: "vector".to_string(),
message: None,
}),
} }
} }
} }
@@ -488,37 +463,41 @@ impl FromLua for crate::Buffer {
fn from_lua(value: Value, _: &Lua) -> Result<Self> { fn from_lua(value: Value, _: &Lua) -> Result<Self> {
match value { match value {
Value::Buffer(buf) => Ok(buf), Value::Buffer(buf) => Ok(buf),
_ => Err(Error::FromLuaConversionError { _ => Err(Error::from_lua_conversion(value.type_name(), "buffer", None)),
from: value.type_name(),
to: "buffer".to_string(),
message: None,
}),
} }
} }
} }
impl IntoLua for StdString { impl IntoLua for String {
#[inline] #[inline]
fn into_lua(self, lua: &Lua) -> Result<Value> { fn into_lua(self, lua: &Lua) -> Result<Value> {
#[cfg(feature = "lua55")]
if true {
return Ok(Value::String(lua.create_external_string(self)?));
}
Ok(Value::String(lua.create_string(self)?)) Ok(Value::String(lua.create_string(self)?))
} }
#[inline] #[inline]
unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> { unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> {
#[cfg(feature = "lua55")]
if lua.unlikely_memory_error() {
return crate::util::push_external_string(lua.state(), self.into(), false);
}
push_bytes_into_stack(self, lua) push_bytes_into_stack(self, lua)
} }
} }
impl FromLua for StdString { impl FromLua for String {
#[inline] #[inline]
fn from_lua(value: Value, lua: &Lua) -> Result<Self> { fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
let ty = value.type_name(); let ty = value.type_name();
Ok(lua Ok(lua
.coerce_string(value)? .coerce_string(value)?
.ok_or_else(|| Error::FromLuaConversionError { .ok_or_else(|| {
from: ty, Error::from_lua_conversion(ty, Self::type_name(), "expected string or number".to_string())
to: Self::type_name(),
message: Some("expected string or number".to_string()),
})? })?
.to_str()? .to_str()?
.to_owned()) .to_owned())
@@ -534,11 +513,7 @@ impl FromLua for StdString {
let bytes = slice::from_raw_parts(data as *const u8, size); let bytes = slice::from_raw_parts(data as *const u8, size);
return str::from_utf8(bytes) return str::from_utf8(bytes)
.map(|s| s.to_owned()) .map(|s| s.to_owned())
.map_err(|e| Error::FromLuaConversionError { .map_err(|e| Error::from_lua_conversion("string", Self::type_name(), e.to_string()));
from: "string",
to: Self::type_name(),
message: Some(e.to_string()),
});
} }
// Fallback to default // Fallback to default
Self::from_lua(lua.stack_value(idx, Some(type_id)), lua.lua()) Self::from_lua(lua.stack_value(idx, Some(type_id)), lua.lua())
@@ -577,10 +552,8 @@ impl FromLua for Box<str> {
let ty = value.type_name(); let ty = value.type_name();
Ok(lua Ok(lua
.coerce_string(value)? .coerce_string(value)?
.ok_or_else(|| Error::FromLuaConversionError { .ok_or_else(|| {
from: ty, Error::from_lua_conversion(ty, Self::type_name(), "expected string or number".to_string())
to: Self::type_name(),
message: Some("expected string or number".to_string()),
})? })?
.to_str()? .to_str()?
.to_owned() .to_owned()
@@ -591,6 +564,11 @@ impl FromLua for Box<str> {
impl IntoLua for CString { impl IntoLua for CString {
#[inline] #[inline]
fn into_lua(self, lua: &Lua) -> Result<Value> { fn into_lua(self, lua: &Lua) -> Result<Value> {
#[cfg(feature = "lua55")]
if true {
return Ok(Value::String(lua.create_external_string(self)?));
}
Ok(Value::String(lua.create_string(self.as_bytes())?)) Ok(Value::String(lua.create_string(self.as_bytes())?))
} }
} }
@@ -599,21 +577,12 @@ impl FromLua for CString {
#[inline] #[inline]
fn from_lua(value: Value, lua: &Lua) -> Result<Self> { fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
let ty = value.type_name(); let ty = value.type_name();
let string = lua let string = lua.coerce_string(value)?.ok_or_else(|| {
.coerce_string(value)? Error::from_lua_conversion(ty, Self::type_name(), "expected string or number".to_string())
.ok_or_else(|| Error::FromLuaConversionError { })?;
from: ty,
to: Self::type_name(),
message: Some("expected string or number".to_string()),
})?;
match CStr::from_bytes_with_nul(&string.as_bytes_with_nul()) { match CStr::from_bytes_with_nul(&string.as_bytes_with_nul()) {
Ok(s) => Ok(s.into()), Ok(s) => Ok(s.into()),
Err(_) => Err(Error::FromLuaConversionError { Err(err) => Err(Error::from_lua_conversion(ty, Self::type_name(), err.to_string())),
from: ty,
to: Self::type_name(),
message: Some("invalid C-style string".to_string()),
}),
} }
} }
} }
@@ -635,6 +604,11 @@ impl IntoLua for Cow<'_, CStr> {
impl IntoLua for BString { impl IntoLua for BString {
#[inline] #[inline]
fn into_lua(self, lua: &Lua) -> Result<Value> { fn into_lua(self, lua: &Lua) -> Result<Value> {
#[cfg(feature = "lua55")]
if true {
return Ok(Value::String(lua.create_external_string(self)?));
}
Ok(Value::String(lua.create_string(self)?)) Ok(Value::String(lua.create_string(self)?))
} }
} }
@@ -648,10 +622,8 @@ impl FromLua for BString {
Value::Buffer(buf) => Ok(buf.to_vec().into()), Value::Buffer(buf) => Ok(buf.to_vec().into()),
_ => Ok((*lua _ => Ok((*lua
.coerce_string(value)? .coerce_string(value)?
.ok_or_else(|| Error::FromLuaConversionError { .ok_or_else(|| {
from: ty, Error::from_lua_conversion(ty, Self::type_name(), "expected string or number".to_string())
to: Self::type_name(),
message: Some("expected string or number".to_string()),
})? })?
.as_bytes()) .as_bytes())
.into()), .into()),
@@ -702,23 +674,22 @@ impl FromLua for OsString {
let bs = BString::from_lua(value, lua)?; let bs = BString::from_lua(value, lua)?;
Vec::from(bs) Vec::from(bs)
.into_os_string() .into_os_string()
.map_err(|err| Error::FromLuaConversionError { .map_err(|err| Error::from_lua_conversion(ty, "OsString", err.to_string()))
from: ty,
to: "OsString".into(),
message: Some(err.to_string()),
})
} }
} }
impl IntoLua for &OsStr { impl IntoLua for &OsStr {
#[cfg(unix)]
#[inline] #[inline]
fn into_lua(self, lua: &Lua) -> Result<Value> { fn into_lua(self, lua: &Lua) -> Result<Value> {
let s = <[u8]>::from_os_str(self).ok_or_else(|| Error::ToLuaConversionError { use std::os::unix::ffi::OsStrExt;
from: "OsStr".into(), Ok(Value::String(lua.create_string(self.as_bytes())?))
to: "string", }
message: Some("invalid utf-8 encoding".into()),
})?; #[cfg(not(unix))]
Ok(Value::String(lua.create_string(s)?)) #[inline]
fn into_lua(self, lua: &Lua) -> Result<Value> {
self.display().to_string().into_lua(lua)
} }
} }
@@ -756,34 +727,25 @@ impl FromLua for char {
fn from_lua(value: Value, _lua: &Lua) -> Result<Self> { fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
let ty = value.type_name(); let ty = value.type_name();
match value { match value {
Value::Integer(i) => { Value::Integer(i) => cast(i).and_then(char::from_u32).ok_or_else(|| {
cast(i) let msg = "integer out of range when converting to char";
.and_then(char::from_u32) Error::from_lua_conversion(ty, "char", msg.to_string())
.ok_or_else(|| Error::FromLuaConversionError { }),
from: ty,
to: "char".to_string(),
message: Some("integer out of range when converting to char".to_string()),
})
}
Value::String(s) => { Value::String(s) => {
let str = s.to_str()?; let str = s.to_str()?;
let mut str_iter = str.chars(); let mut str_iter = str.chars();
match (str_iter.next(), str_iter.next()) { match (str_iter.next(), str_iter.next()) {
(Some(char), None) => Ok(char), (Some(char), None) => Ok(char),
_ => Err(Error::FromLuaConversionError { _ => {
from: ty, let msg = "expected string to have exactly one char when converting to char";
to: "char".to_string(), Err(Error::from_lua_conversion(ty, "char", msg.to_string()))
message: Some( }
"expected string to have exactly one char when converting to char".to_string(),
),
}),
} }
} }
_ => Err(Error::FromLuaConversionError { _ => {
from: ty, let msg = "expected string or integer";
to: Self::type_name(), Err(Error::from_lua_conversion(ty, Self::type_name(), msg.to_string()))
message: Some("expected string or integer".to_string()), }
}),
} }
} }
} }
@@ -834,24 +796,14 @@ macro_rules! lua_convert_int {
if let Some(i) = lua.coerce_integer(value.clone())? { if let Some(i) = lua.coerce_integer(value.clone())? {
cast(i) cast(i)
} else { } else {
cast( cast(lua.coerce_number(value)?.ok_or_else(|| {
lua.coerce_number(value)? let msg = "expected number or string coercible to number";
.ok_or_else(|| Error::FromLuaConversionError { Error::from_lua_conversion(ty, stringify!($x), msg.to_string())
from: ty, })?)
to: stringify!($x).to_string(),
message: Some(
"expected number or string coercible to number".to_string(),
),
})?,
)
} }
} }
}) })
.ok_or_else(|| Error::FromLuaConversionError { .ok_or_else(|| Error::from_lua_conversion(ty, stringify!($x), "out of range".to_string()))
from: ty,
to: stringify!($x).to_string(),
message: Some("out of range".to_owned()),
})
} }
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> { unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
@@ -861,10 +813,8 @@ macro_rules! lua_convert_int {
let mut ok = 0; let mut ok = 0;
let i = ffi::lua_tointegerx(state, idx, &mut ok); let i = ffi::lua_tointegerx(state, idx, &mut ok);
if ok != 0 { if ok != 0 {
return cast(i).ok_or_else(|| Error::FromLuaConversionError { return cast(i).ok_or_else(|| {
from: "integer", Error::from_lua_conversion("integer", stringify!($x), "out of range".to_string())
to: stringify!($x).to_string(),
message: Some("out of range".to_owned()),
}); });
} }
} }
@@ -901,13 +851,10 @@ macro_rules! lua_convert_float {
#[inline] #[inline]
fn from_lua(value: Value, lua: &Lua) -> Result<Self> { fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
let ty = value.type_name(); let ty = value.type_name();
lua.coerce_number(value)? lua.coerce_number(value)?.map(|n| n as $x).ok_or_else(|| {
.map(|n| n as $x) let msg = "expected number or string coercible to number";
.ok_or_else(|| Error::FromLuaConversionError { Error::from_lua_conversion(ty, stringify!($x), msg.to_string())
from: ty, })
to: stringify!($x).to_string(),
message: Some("expected number or string coercible to number".to_string()),
})
} }
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> { unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
@@ -967,18 +914,16 @@ where
}, },
Value::Table(table) => { Value::Table(table) => {
let vec = table.sequence_values().collect::<Result<Vec<_>>>()?; let vec = table.sequence_values().collect::<Result<Vec<_>>>()?;
vec.try_into() vec.try_into().map_err(|vec: Vec<T>| {
.map_err(|vec: Vec<T>| Error::FromLuaConversionError { let msg = format!("expected table of length {N}, got {}", vec.len());
from: "table", Error::from_lua_conversion("table", Self::type_name(), msg)
to: Self::type_name(), })
message: Some(format!("expected table of length {N}, got {}", vec.len())), }
}) _ => {
let msg = format!("expected table of length {N}");
let err = Error::from_lua_conversion(value.type_name(), Self::type_name(), msg.to_string());
Err(err)
} }
_ => Err(Error::FromLuaConversionError {
from: value.type_name(),
to: Self::type_name(),
message: Some("expected table".to_string()),
}),
} }
} }
} }
@@ -1009,11 +954,11 @@ impl<T: FromLua> FromLua for Vec<T> {
fn from_lua(value: Value, _lua: &Lua) -> Result<Self> { fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
match value { match value {
Value::Table(table) => table.sequence_values().collect(), Value::Table(table) => table.sequence_values().collect(),
_ => Err(Error::FromLuaConversionError { _ => Err(Error::from_lua_conversion(
from: value.type_name(), value.type_name(),
to: Self::type_name(), Self::type_name(),
message: Some("expected table".to_string()), "expected table".to_string(),
}), )),
} }
} }
} }
@@ -1028,14 +973,13 @@ impl<K: Eq + Hash + IntoLua, V: IntoLua, S: BuildHasher> IntoLua for HashMap<K,
impl<K: Eq + Hash + FromLua, V: FromLua, S: BuildHasher + Default> FromLua for HashMap<K, V, S> { impl<K: Eq + Hash + FromLua, V: FromLua, S: BuildHasher + Default> FromLua for HashMap<K, V, S> {
#[inline] #[inline]
fn from_lua(value: Value, _: &Lua) -> Result<Self> { fn from_lua(value: Value, _: &Lua) -> Result<Self> {
if let Value::Table(table) = value { match value {
table.pairs().collect() Value::Table(table) => table.pairs().collect(),
} else { _ => Err(Error::from_lua_conversion(
Err(Error::FromLuaConversionError { value.type_name(),
from: value.type_name(), Self::type_name(),
to: Self::type_name(), "expected table".to_string(),
message: Some("expected table".to_string()), )),
})
} }
} }
} }
@@ -1050,14 +994,13 @@ impl<K: Ord + IntoLua, V: IntoLua> IntoLua for BTreeMap<K, V> {
impl<K: Ord + FromLua, V: FromLua> FromLua for BTreeMap<K, V> { impl<K: Ord + FromLua, V: FromLua> FromLua for BTreeMap<K, V> {
#[inline] #[inline]
fn from_lua(value: Value, _: &Lua) -> Result<Self> { fn from_lua(value: Value, _: &Lua) -> Result<Self> {
if let Value::Table(table) = value { match value {
table.pairs().collect() Value::Table(table) => table.pairs().collect(),
} else { _ => Err(Error::from_lua_conversion(
Err(Error::FromLuaConversionError { value.type_name(),
from: value.type_name(), Self::type_name(),
to: Self::type_name(), "expected table".to_string(),
message: Some("expected table".to_string()), )),
})
} }
} }
} }
@@ -1077,11 +1020,11 @@ impl<T: Eq + Hash + FromLua, S: BuildHasher + Default> FromLua for HashSet<T, S>
match value { match value {
Value::Table(table) if table.raw_len() > 0 => table.sequence_values().collect(), Value::Table(table) if table.raw_len() > 0 => table.sequence_values().collect(),
Value::Table(table) => table.pairs::<T, Value>().map(|res| res.map(|(k, _)| k)).collect(), Value::Table(table) => table.pairs::<T, Value>().map(|res| res.map(|(k, _)| k)).collect(),
_ => Err(Error::FromLuaConversionError { _ => Err(Error::from_lua_conversion(
from: value.type_name(), value.type_name(),
to: Self::type_name(), Self::type_name(),
message: Some("expected table".to_string()), "expected table".to_string(),
}), )),
} }
} }
} }
@@ -1101,11 +1044,11 @@ impl<T: Ord + FromLua> FromLua for BTreeSet<T> {
match value { match value {
Value::Table(table) if table.raw_len() > 0 => table.sequence_values().collect(), Value::Table(table) if table.raw_len() > 0 => table.sequence_values().collect(),
Value::Table(table) => table.pairs::<T, Value>().map(|res| res.map(|(k, _)| k)).collect(), Value::Table(table) => table.pairs::<T, Value>().map(|res| res.map(|(k, _)| k)).collect(),
_ => Err(Error::FromLuaConversionError { _ => Err(Error::from_lua_conversion(
from: value.type_name(), value.type_name(),
to: Self::type_name(), Self::type_name(),
message: Some("expected table".to_string()), "expected table".to_string(),
}), )),
} }
} }
} }
@@ -1175,11 +1118,11 @@ impl<L: FromLua, R: FromLua> FromLua for Either<L, R> {
// Try the right type // Try the right type
Err(_) => match R::from_lua(value, lua).map(Either::Right) { Err(_) => match R::from_lua(value, lua).map(Either::Right) {
Ok(r) => Ok(r), Ok(r) => Ok(r),
Err(_) => Err(Error::FromLuaConversionError { Err(_) => Err(Error::from_lua_conversion(
from: value_type_name, value_type_name,
to: Self::type_name(), Self::type_name(),
message: None, None,
}), )),
}, },
} }
} }
@@ -1191,12 +1134,12 @@ impl<L: FromLua, R: FromLua> FromLua for Either<L, R> {
Err(_) => match R::from_stack(idx, lua).map(Either::Right) { Err(_) => match R::from_stack(idx, lua).map(Either::Right) {
Ok(r) => Ok(r), Ok(r) => Ok(r),
Err(_) => { Err(_) => {
let value_type_name = CStr::from_ptr(ffi::luaL_typename(lua.state(), idx)); let state = lua.state();
Err(Error::FromLuaConversionError { let from_type_name = CStr::from_ptr(ffi::lua_typename(state, ffi::lua_type(state, idx)))
from: value_type_name.to_str().unwrap(), .to_str()
to: Self::type_name(), .unwrap_or("unknown");
message: None, let err = Error::from_lua_conversion(from_type_name, Self::type_name(), None);
}) Err(err)
} }
}, },
} }
+34 -27
View File
@@ -1,3 +1,9 @@
//! Lua debugging interface.
//!
//! This module provides access to the Lua debug interface, allowing inspection of the call stack,
//! and function information. The main types are [`Debug`] for accessing debug information and
//! [`HookTriggers`] for configuring debug hooks.
use std::borrow::Cow; use std::borrow::Cow;
use std::os::raw::c_int; use std::os::raw::c_int;
@@ -5,7 +11,7 @@ use ffi::{lua_Debug, lua_State};
use crate::function::Function; use crate::function::Function;
use crate::state::RawLua; use crate::state::RawLua;
use crate::util::{assert_stack, linenumber_to_usize, ptr_to_lossy_str, ptr_to_str, StackGuard}; use crate::util::{StackGuard, assert_stack, linenumber_to_usize, ptr_to_lossy_str, ptr_to_str};
/// Contains information about currently executing Lua code. /// Contains information about currently executing Lua code.
/// ///
@@ -133,12 +139,6 @@ impl<'a> Debug<'a> {
} }
} }
#[doc(hidden)]
#[deprecated(note = "Use `current_line` instead")]
pub fn curr_line(&self) -> i32 {
self.current_line().map(|n| n as i32).unwrap_or(-1)
}
/// Corresponds to the `l` "what" mask. Returns the current line. /// Corresponds to the `l` "what" mask. Returns the current line.
pub fn current_line(&self) -> Option<usize> { pub fn current_line(&self) -> Option<usize> {
unsafe { unsafe {
@@ -159,10 +159,10 @@ impl<'a> Debug<'a> {
/// Corresponds to the `t` "what" mask. Returns true if the hook is in a function tail call, /// Corresponds to the `t` "what" mask. Returns true if the hook is in a function tail call,
/// false otherwise. /// false otherwise.
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))) doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52")))
)] )]
pub fn is_tail_call(&self) -> bool { pub fn is_tail_call(&self) -> bool {
unsafe { unsafe {
@@ -190,15 +190,15 @@ impl<'a> Debug<'a> {
#[cfg(not(feature = "luau"))] #[cfg(not(feature = "luau"))]
let stack = DebugStack { let stack = DebugStack {
num_ups: (*self.ar).nups as _, num_upvalues: (*self.ar).nups as _,
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(not(any(feature = "lua51", feature = "luajit")))]
num_params: (*self.ar).nparams as _, num_params: (*self.ar).nparams as _,
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(not(any(feature = "lua51", feature = "luajit")))]
is_vararg: (*self.ar).isvararg != 0, is_vararg: (*self.ar).isvararg != 0,
}; };
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
let stack = DebugStack { let stack = DebugStack {
num_ups: (*self.ar).nupvals, num_upvalues: (*self.ar).nupvals,
num_params: (*self.ar).nparams, num_params: (*self.ar).nparams,
is_vararg: (*self.ar).isvararg != 0, is_vararg: (*self.ar).isvararg != 0,
}; };
@@ -208,6 +208,8 @@ impl<'a> Debug<'a> {
} }
/// Represents a specific event that triggered the hook. /// Represents a specific event that triggered the hook.
#[cfg(not(feature = "luau"))]
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DebugEvent { pub enum DebugEvent {
Call, Call,
@@ -218,6 +220,9 @@ pub enum DebugEvent {
Unknown(c_int), Unknown(c_int),
} }
/// Contains the name information of a function in the call stack.
///
/// Returned by the [`Debug::names`] method.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct DebugNames<'a> { pub struct DebugNames<'a> {
/// A (reasonable) name of the function (`None` if the name cannot be found). /// A (reasonable) name of the function (`None` if the name cannot be found).
@@ -228,6 +233,9 @@ pub struct DebugNames<'a> {
pub name_what: Option<&'static str>, pub name_what: Option<&'static str>,
} }
/// Contains the source information of a function in the call stack.
///
/// Returned by the [`Debug::source`] method.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct DebugSource<'a> { pub struct DebugSource<'a> {
/// Source of the chunk that created the function. /// Source of the chunk that created the function.
@@ -243,23 +251,20 @@ pub struct DebugSource<'a> {
pub what: &'static str, pub what: &'static str,
} }
/// Contains stack information about a function in the call stack.
///
/// Returned by the [`Debug::stack`] method.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct DebugStack { pub struct DebugStack {
/// Number of upvalues. /// The number of upvalues of the function.
pub num_ups: u8, pub num_upvalues: u8,
/// Number of parameters. /// The number of parameters of the function (always 0 for C).
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau"))] #[cfg(any(not(any(feature = "lua51", feature = "luajit")), doc))]
#[cfg_attr( #[cfg_attr(docsrs, doc(cfg(not(any(feature = "lua51", feature = "luajit")))))]
docsrs,
doc(cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau")))
)]
pub num_params: u8, pub num_params: u8,
/// Whether the function is a vararg function. /// Whether the function is a variadic function (always true for C).
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau"))] #[cfg(any(not(any(feature = "lua51", feature = "luajit")), doc))]
#[cfg_attr( #[cfg_attr(docsrs, doc(cfg(not(any(feature = "lua51", feature = "luajit")))))]
docsrs,
doc(cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau")))
)]
pub is_vararg: bool, pub is_vararg: bool,
} }
@@ -337,6 +342,7 @@ impl HookTriggers {
} }
// Compute the mask to pass to `lua_sethook`. // Compute the mask to pass to `lua_sethook`.
#[cfg(not(feature = "luau"))]
pub(crate) const fn mask(&self) -> c_int { pub(crate) const fn mask(&self) -> c_int {
let mut mask: c_int = 0; let mut mask: c_int = 0;
if self.on_calls { if self.on_calls {
@@ -356,6 +362,7 @@ impl HookTriggers {
// Returns the `count` parameter to pass to `lua_sethook`, if applicable. Otherwise, zero is // Returns the `count` parameter to pass to `lua_sethook`, if applicable. Otherwise, zero is
// returned. // returned.
#[cfg(not(feature = "luau"))]
pub(crate) const fn count(&self) -> c_int { pub(crate) const fn count(&self) -> c_int {
match self.every_nth_instruction { match self.every_nth_instruction {
Some(n) => n as c_int, Some(n) => n as c_int,
+30 -41
View File
@@ -4,7 +4,6 @@ use std::io::Error as IoError;
use std::net::AddrParseError; use std::net::AddrParseError;
use std::result::Result as StdResult; use std::result::Result as StdResult;
use std::str::Utf8Error; use std::str::Utf8Error;
use std::string::String as StdString;
use std::sync::Arc; use std::sync::Arc;
use crate::private::Sealed; use crate::private::Sealed;
@@ -22,7 +21,7 @@ pub enum Error {
/// Syntax error while parsing Lua source code. /// Syntax error while parsing Lua source code.
SyntaxError { SyntaxError {
/// The error message as returned by Lua. /// The error message as returned by Lua.
message: StdString, message: String,
/// `true` if the error can likely be fixed by appending more input to the source code. /// `true` if the error can likely be fixed by appending more input to the source code.
/// ///
/// This is useful for implementing REPLs as they can query the user for more input if this /// This is useful for implementing REPLs as they can query the user for more input if this
@@ -34,20 +33,20 @@ pub enum Error {
/// The Lua VM returns this error when a builtin operation is performed on incompatible types. /// The Lua VM returns this error when a builtin operation is performed on incompatible types.
/// Among other things, this includes invoking operators on wrong types (such as calling or /// Among other things, this includes invoking operators on wrong types (such as calling or
/// indexing a `nil` value). /// indexing a `nil` value).
RuntimeError(StdString), RuntimeError(String),
/// Lua memory error, aka `LUA_ERRMEM` /// Lua memory error, aka `LUA_ERRMEM`
/// ///
/// The Lua VM returns this error when the allocator does not return the requested memory, aka /// The Lua VM returns this error when the allocator does not return the requested memory, aka
/// it is an out-of-memory error. /// it is an out-of-memory error.
MemoryError(StdString), MemoryError(String),
/// Lua garbage collector error, aka `LUA_ERRGCMM`. /// Lua garbage collector error, aka `LUA_ERRGCMM`.
/// ///
/// The Lua VM returns this error when there is an error running a `__gc` metamethod. /// The Lua VM returns this error when there is an error running a `__gc` metamethod.
#[cfg(any(feature = "lua53", feature = "lua52", doc))] #[cfg(any(feature = "lua53", feature = "lua52", doc))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua53", feature = "lua52"))))] #[cfg_attr(docsrs, doc(cfg(any(feature = "lua53", feature = "lua52"))))]
GarbageCollectorError(StdString), GarbageCollectorError(String),
/// Potentially unsafe action in safe mode. /// Potentially unsafe action in safe mode.
SafetyError(StdString), SafetyError(String),
/// Memory control is not available. /// Memory control is not available.
/// ///
/// This error can only happen when Lua state was not created by us and does not have the /// This error can only happen when Lua state was not created by us and does not have the
@@ -80,23 +79,14 @@ pub enum Error {
/// (which is stored in the corresponding field). /// (which is stored in the corresponding field).
BadArgument { BadArgument {
/// Function that was called. /// Function that was called.
to: Option<StdString>, to: Option<String>,
/// Argument position (usually starts from 1). /// Argument position (usually starts from 1).
pos: usize, pos: usize,
/// Argument name. /// Argument name.
name: Option<StdString>, name: Option<String>,
/// Underlying error returned when converting argument to a Lua value. /// Underlying error returned when converting argument to a Lua value.
cause: Arc<Error>, cause: Arc<Error>,
}, },
/// A Rust value could not be converted to a Lua value.
ToLuaConversionError {
/// Name of the Rust type that could not be converted.
from: String,
/// Name of the Lua type that could not be created.
to: &'static str,
/// A message indicating why the conversion failed in more detail.
message: Option<StdString>,
},
/// A Lua value could not be converted to the expected Rust type. /// A Lua value could not be converted to the expected Rust type.
FromLuaConversionError { FromLuaConversionError {
/// Name of the Lua type that could not be converted. /// Name of the Lua type that could not be converted.
@@ -104,7 +94,7 @@ pub enum Error {
/// Name of the Rust type that could not be created. /// Name of the Rust type that could not be created.
to: String, to: String,
/// A string containing more detailed error information. /// A string containing more detailed error information.
message: Option<StdString>, message: Option<String>,
}, },
/// [`Thread::resume`] was called on an unresumable coroutine. /// [`Thread::resume`] was called on an unresumable coroutine.
/// ///
@@ -154,17 +144,17 @@ pub enum Error {
/// A [`MetaMethod`] operation is restricted (typically for `__gc` or `__metatable`). /// A [`MetaMethod`] operation is restricted (typically for `__gc` or `__metatable`).
/// ///
/// [`MetaMethod`]: crate::MetaMethod /// [`MetaMethod`]: crate::MetaMethod
MetaMethodRestricted(StdString), MetaMethodRestricted(String),
/// A [`MetaMethod`] (eg. `__index` or `__newindex`) has invalid type. /// A [`MetaMethod`] (eg. `__index` or `__newindex`) has invalid type.
/// ///
/// [`MetaMethod`]: crate::MetaMethod /// [`MetaMethod`]: crate::MetaMethod
MetaMethodTypeError { MetaMethodTypeError {
/// Name of the metamethod. /// Name of the metamethod.
method: StdString, method: String,
/// Passed value type. /// Passed value type.
type_name: &'static str, type_name: &'static str,
/// A string containing more detailed error information. /// A string containing more detailed error information.
message: Option<StdString>, message: Option<String>,
}, },
/// A [`RegistryKey`] produced from a different Lua state was used. /// A [`RegistryKey`] produced from a different Lua state was used.
/// ///
@@ -173,7 +163,7 @@ pub enum Error {
/// A Rust callback returned `Err`, raising the contained `Error` as a Lua error. /// A Rust callback returned `Err`, raising the contained `Error` as a Lua error.
CallbackError { CallbackError {
/// Lua call stack backtrace. /// Lua call stack backtrace.
traceback: StdString, traceback: String,
/// Original error returned by the Rust code. /// Original error returned by the Rust code.
cause: Arc<Error>, cause: Arc<Error>,
}, },
@@ -185,11 +175,11 @@ pub enum Error {
/// Serialization error. /// Serialization error.
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
SerializeError(StdString), SerializeError(String),
/// Deserialization error. /// Deserialization error.
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
DeserializeError(StdString), DeserializeError(String),
/// A custom error. /// A custom error.
/// ///
/// This can be used for returning user-defined errors from callbacks. /// This can be used for returning user-defined errors from callbacks.
@@ -201,7 +191,7 @@ pub enum Error {
/// An error with additional context. /// An error with additional context.
WithContext { WithContext {
/// A string containing additional context. /// A string containing additional context.
context: StdString, context: String,
/// Underlying error. /// Underlying error.
cause: Arc<Error>, cause: Arc<Error>,
}, },
@@ -225,7 +215,7 @@ impl fmt::Display for Error {
} }
Error::SafetyError(msg) => { Error::SafetyError(msg) => {
write!(fmt, "safety error: {msg}") write!(fmt, "safety error: {msg}")
}, }
Error::MemoryControlNotAvailable => { Error::MemoryControlNotAvailable => {
write!(fmt, "memory control is not available") write!(fmt, "memory control is not available")
} }
@@ -238,10 +228,7 @@ impl fmt::Display for Error {
fmt, fmt,
"out of Lua stack, too many arguments to a Lua function or too many return values from a callback" "out of Lua stack, too many arguments to a Lua function or too many return values from a callback"
), ),
Error::BindError => write!( Error::BindError => write!(fmt, "too many arguments to Function::bind"),
fmt,
"too many arguments to Function::bind"
),
Error::BadArgument { to, pos, name, cause } => { Error::BadArgument { to, pos, name, cause } => {
if let Some(name) = name { if let Some(name) = name {
write!(fmt, "bad argument `{name}`")?; write!(fmt, "bad argument `{name}`")?;
@@ -252,13 +239,6 @@ impl fmt::Display for Error {
write!(fmt, " to `{to}`")?; write!(fmt, " to `{to}`")?;
} }
write!(fmt, ": {cause}") write!(fmt, ": {cause}")
},
Error::ToLuaConversionError { from, to, message } => {
write!(fmt, "error converting {from} to Lua {to}")?;
match message {
None => Ok(()),
Some(message) => write!(fmt, " ({message})"),
}
} }
Error::FromLuaConversionError { from, to, message } => { Error::FromLuaConversionError { from, to, message } => {
write!(fmt, "error converting Lua {from} to {to}")?; write!(fmt, "error converting Lua {from} to {to}")?;
@@ -273,7 +253,11 @@ impl fmt::Display for Error {
Error::UserDataBorrowError => write!(fmt, "error borrowing userdata"), Error::UserDataBorrowError => write!(fmt, "error borrowing userdata"),
Error::UserDataBorrowMutError => write!(fmt, "error mutably borrowing userdata"), Error::UserDataBorrowMutError => write!(fmt, "error mutably borrowing userdata"),
Error::MetaMethodRestricted(method) => write!(fmt, "metamethod {method} is restricted"), Error::MetaMethodRestricted(method) => write!(fmt, "metamethod {method} is restricted"),
Error::MetaMethodTypeError { method, type_name, message } => { Error::MetaMethodTypeError {
method,
type_name,
message,
} => {
write!(fmt, "metamethod {method} has unsupported type {type_name}")?; write!(fmt, "metamethod {method} has unsupported type {type_name}")?;
match message { match message {
None => Ok(()), None => Ok(()),
@@ -286,7 +270,11 @@ impl fmt::Display for Error {
Error::CallbackError { cause, traceback } => { Error::CallbackError { cause, traceback } => {
// Trace errors down to the root // Trace errors down to the root
let (mut cause, mut full_traceback) = (cause, None); let (mut cause, mut full_traceback) = (cause, None);
while let Error::CallbackError { cause: cause2, traceback: traceback2 } = &**cause { while let Error::CallbackError {
cause: cause2,
traceback: traceback2,
} = &**cause
{
cause = cause2; cause = cause2;
full_traceback = Some(traceback2); full_traceback = Some(traceback2);
} }
@@ -312,11 +300,11 @@ impl fmt::Display for Error {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
Error::SerializeError(err) => { Error::SerializeError(err) => {
write!(fmt, "serialize error: {err}") write!(fmt, "serialize error: {err}")
}, }
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
Error::DeserializeError(err) => { Error::DeserializeError(err) => {
write!(fmt, "deserialize error: {err}") write!(fmt, "deserialize error: {err}")
}, }
Error::ExternalError(err) => err.fmt(fmt), Error::ExternalError(err) => err.fmt(fmt),
Error::WithContext { context, cause } => { Error::WithContext { context, cause } => {
writeln!(fmt, "{context}")?; writeln!(fmt, "{context}")?;
@@ -394,6 +382,7 @@ impl Error {
} }
} }
#[inline]
pub(crate) fn from_lua_conversion( pub(crate) fn from_lua_conversion(
from: &'static str, from: &'static str,
to: impl ToString, to: impl ToString,
+123 -12
View File
@@ -1,3 +1,84 @@
//! Lua function handling.
//!
//! This module provides types for working with Lua functions from Rust, including
//! both Lua-defined functions and native Rust callbacks.
//!
//! # Main Types
//!
//! - [`Function`] - A handle to a Lua function that can be called from Rust.
//! - [`FunctionInfo`] - Debug information about a function (name, source, line numbers, etc.).
//! - [`CoverageInfo`] - Code coverage data for Luau functions (requires `luau` feature).
//!
//! # Calling Functions
//!
//! Use [`Function::call`] to invoke a Lua function synchronously:
//!
//! ```
//! # use mlua::{Function, Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//!
//! // Get a built-in function
//! let print: Function = lua.globals().get("print")?;
//! print.call::<()>("Hello from Rust!")?;
//!
//! // Call a function that returns values
//! let tonumber: Function = lua.globals().get("tonumber")?;
//! let n: i32 = tonumber.call("42")?;
//! assert_eq!(n, 42);
//! # Ok(())
//! # }
//! ```
//!
//! For asynchronous execution, use `Function::call_async` (requires `async` feature):
//!
//! ```ignore
//! let result: String = my_async_func.call_async(args).await?;
//! ```
//!
//! # Creating Functions
//!
//! Functions can be created from Rust closures using [`Lua::create_function`]:
//!
//! ```
//! # use mlua::{Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//!
//! let greet = lua.create_function(|_, name: String| {
//! Ok(format!("Hello, {}!", name))
//! })?;
//!
//! lua.globals().set("greet", greet)?;
//! let result: String = lua.load(r#"greet("World")"#).eval()?;
//! assert_eq!(result, "Hello, World!");
//! # Ok(())
//! # }
//! ```
//!
//! For simpler cases, use [`Function::wrap`] or [`Function::wrap_raw`] to convert a Rust function
//! directly:
//!
//! ```
//! # use mlua::{Function, Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//!
//! fn add(a: i32, b: i32) -> i32 { a + b }
//!
//! lua.globals().set("add", Function::wrap_raw(add))?;
//! let sum: i32 = lua.load("add(2, 3)").eval()?;
//! assert_eq!(sum, 5);
//! # Ok(())
//! # }
//! ```
//!
//! # Function Environments
//!
//! Lua functions have an associated environment table that determines how global
//! variables are resolved. Use [`Function::environment`] and [`Function::set_environment`]
//! to inspect or modify this environment.
use std::cell::RefCell; use std::cell::RefCell;
use std::os::raw::{c_int, c_void}; use std::os::raw::{c_int, c_void};
use std::{mem, ptr, slice}; use std::{mem, ptr, slice};
@@ -8,7 +89,7 @@ use crate::table::Table;
use crate::traits::{FromLuaMulti, IntoLua, IntoLuaMulti, LuaNativeFn, LuaNativeFnMut}; use crate::traits::{FromLuaMulti, IntoLua, IntoLuaMulti, LuaNativeFn, LuaNativeFnMut};
use crate::types::{Callback, LuaType, MaybeSend, ValueRef}; use crate::types::{Callback, LuaType, MaybeSend, ValueRef};
use crate::util::{ use crate::util::{
assert_stack, check_stack, linenumber_to_usize, pop_error, ptr_to_lossy_str, ptr_to_str, StackGuard, StackGuard, assert_stack, check_stack, linenumber_to_usize, pop_error, ptr_to_lossy_str, ptr_to_str,
}; };
use crate::value::Value; use crate::value::Value;
@@ -18,7 +99,7 @@ use {
crate::traits::LuaNativeAsyncFn, crate::traits::LuaNativeAsyncFn,
crate::types::AsyncCallback, crate::types::AsyncCallback,
std::future::{self, Future}, std::future::{self, Future},
std::pin::{pin, Pin}, std::pin::{Pin, pin},
std::task::{Context, Poll}, std::task::{Context, Poll},
}; };
@@ -32,6 +113,7 @@ pub struct Function(pub(crate) ValueRef);
/// ///
/// [`Lua Debug Interface`]: https://www.lua.org/manual/5.4/manual.html#4.7 /// [`Lua Debug Interface`]: https://www.lua.org/manual/5.4/manual.html#4.7
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[non_exhaustive]
pub struct FunctionInfo { pub struct FunctionInfo {
/// A (reasonable) name of the function (`None` if the name cannot be found). /// A (reasonable) name of the function (`None` if the name cannot be found).
pub name: Option<String>, pub name: Option<String>,
@@ -50,6 +132,16 @@ pub struct FunctionInfo {
pub line_defined: Option<usize>, pub line_defined: Option<usize>,
/// The line number where the definition of the function ends (not set by Luau). /// The line number where the definition of the function ends (not set by Luau).
pub last_line_defined: Option<usize>, pub last_line_defined: Option<usize>,
/// The number of upvalues of the function.
pub num_upvalues: u8,
/// The number of parameters of the function (always 0 for C).
#[cfg(any(not(any(feature = "lua51", feature = "luajit")), doc))]
#[cfg_attr(docsrs, doc(cfg(not(any(feature = "lua51", feature = "luajit")))))]
pub num_params: u8,
/// Whether the function is a variadic function (always true for C).
#[cfg(any(not(any(feature = "lua51", feature = "luajit")), doc))]
#[cfg_attr(docsrs, doc(cfg(not(any(feature = "lua51", feature = "luajit")))))]
pub is_vararg: bool,
} }
/// Luau function coverage snapshot. /// Luau function coverage snapshot.
@@ -276,7 +368,7 @@ impl Function {
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
ffi::lua_getfenv(state, -1); ffi::lua_getfenv(state, -1);
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
for i in 1..=255 { for i in 1..=255 {
// Traverse upvalues until we find the _ENV one // Traverse upvalues until we find the _ENV one
match ffi::lua_getupvalue(state, -1, i) { match ffi::lua_getupvalue(state, -1, i) {
@@ -316,7 +408,7 @@ impl Function {
lua.push_ref(&env.0); lua.push_ref(&env.0);
ffi::lua_setfenv(state, -2); ffi::lua_setfenv(state, -2);
} }
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
for i in 1..=255 { for i in 1..=255 {
match ffi::lua_getupvalue(state, -1, i) { match ffi::lua_getupvalue(state, -1, i) {
s if s.is_null() => return Ok(false), s if s.is_null() => return Ok(false),
@@ -343,7 +435,8 @@ impl Function {
/// Returns information about the function. /// Returns information about the function.
/// ///
/// Corresponds to the `>Sn` what mask for [`lua_getinfo`] when applied to the function. /// Corresponds to the `>Snu` (`>Sn` for Luau) what mask for
/// [`lua_getinfo`] when applied to the function.
/// ///
/// [`lua_getinfo`]: https://www.lua.org/manual/5.4/manual.html#lua_getinfo /// [`lua_getinfo`]: https://www.lua.org/manual/5.4/manual.html#lua_getinfo
pub fn info(&self) -> FunctionInfo { pub fn info(&self) -> FunctionInfo {
@@ -355,11 +448,16 @@ impl Function {
let mut ar: ffi::lua_Debug = mem::zeroed(); let mut ar: ffi::lua_Debug = mem::zeroed();
lua.push_ref(&self.0); lua.push_ref(&self.0);
#[cfg(not(feature = "luau"))] #[cfg(not(feature = "luau"))]
let res = ffi::lua_getinfo(state, cstr!(">Sn"), &mut ar); let res = ffi::lua_getinfo(state, cstr!(">Snu"), &mut ar);
#[cfg(not(feature = "luau"))]
mlua_assert!(res != 0, "lua_getinfo failed with `>Snu`");
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
let res = ffi::lua_getinfo(state, -1, cstr!("sn"), &mut ar); let res = ffi::lua_getinfo(state, -1, cstr!("snau"), &mut ar);
mlua_assert!(res != 0, "lua_getinfo failed with `>Sn`"); #[cfg(feature = "luau")]
mlua_assert!(res != 0, "lua_getinfo failed with `snau`");
FunctionInfo { FunctionInfo {
name: ptr_to_lossy_str(ar.name).map(|s| s.into_owned()), name: ptr_to_lossy_str(ar.name).map(|s| s.into_owned()),
@@ -381,6 +479,14 @@ impl Function {
last_line_defined: linenumber_to_usize(ar.lastlinedefined), last_line_defined: linenumber_to_usize(ar.lastlinedefined),
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
last_line_defined: None, last_line_defined: None,
#[cfg(not(feature = "luau"))]
num_upvalues: ar.nups as _,
#[cfg(feature = "luau")]
num_upvalues: ar.nupvals,
#[cfg(not(any(feature = "lua51", feature = "luajit")))]
num_params: ar.nparams,
#[cfg(not(any(feature = "lua51", feature = "luajit")))]
is_vararg: ar.isvararg != 0,
} }
} }
} }
@@ -400,11 +506,14 @@ impl Function {
_state: *mut ffi::lua_State, _state: *mut ffi::lua_State,
buf: *const c_void, buf: *const c_void,
buf_len: usize, buf_len: usize,
data: *mut c_void, data_ptr: *mut c_void,
) -> c_int { ) -> c_int {
let data = &mut *(data as *mut Vec<u8>); // If `data` is null, then it's a signal that write is finished.
let buf = slice::from_raw_parts(buf as *const u8, buf_len); if !data_ptr.is_null() && buf_len > 0 {
data.extend_from_slice(buf); let data = &mut *(data_ptr as *mut Vec<u8>);
let buf = slice::from_raw_parts(buf as *const u8, buf_len);
data.extend_from_slice(buf);
}
0 0
} }
@@ -653,7 +762,9 @@ impl LuaType for Function {
const TYPE_ID: c_int = ffi::LUA_TFUNCTION; const TYPE_ID: c_int = ffi::LUA_TFUNCTION;
} }
/// Future for asynchronous function calls.
#[cfg(feature = "async")] #[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
#[must_use = "futures do nothing unless you `.await` or poll them"] #[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct AsyncCallFuture<R: FromLuaMulti>(Result<AsyncThread<R>>); pub struct AsyncCallFuture<R: FromLuaMulti>(Result<AsyncThread<R>>);
+7 -10
View File
@@ -66,7 +66,6 @@
// warnings at all. // warnings at all.
#![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(not(send), allow(clippy::arc_with_non_send_sync))] #![cfg_attr(not(send), allow(clippy::arc_with_non_send_sync))]
#![allow(clippy::ptr_eq)]
#![allow(unsafe_op_in_unsafe_fn)] #![allow(unsafe_op_in_unsafe_fn)]
#[macro_use] #[macro_use]
@@ -75,9 +74,7 @@ mod macros;
mod buffer; mod buffer;
mod chunk; mod chunk;
mod conversion; mod conversion;
mod debug;
mod error; mod error;
mod function;
#[cfg(any(feature = "luau", doc))] #[cfg(any(feature = "luau", doc))]
mod luau; mod luau;
mod memory; mod memory;
@@ -86,7 +83,6 @@ mod scope;
mod state; mod state;
mod stdlib; mod stdlib;
mod string; mod string;
mod table;
mod thread; mod thread;
mod traits; mod traits;
mod types; mod types;
@@ -95,21 +91,23 @@ mod util;
mod value; mod value;
mod vector; mod vector;
pub mod debug;
pub mod function;
pub mod prelude; pub mod prelude;
pub mod table;
pub use bstr::BString; pub use bstr::BString;
pub use ffi::{self, lua_CFunction, lua_State}; pub use ffi::{self, lua_CFunction, lua_State};
pub use crate::chunk::{AsChunk, Chunk, ChunkMode}; pub use crate::chunk::{AsChunk, Chunk, ChunkMode};
pub use crate::debug::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack};
pub use crate::error::{Error, ErrorContext, ExternalError, ExternalResult, Result}; pub use crate::error::{Error, ErrorContext, ExternalError, ExternalResult, Result};
pub use crate::function::{Function, FunctionInfo}; pub use crate::function::Function;
pub use crate::multi::{MultiValue, Variadic}; pub use crate::multi::{MultiValue, Variadic};
pub use crate::scope::Scope; pub use crate::scope::Scope;
pub use crate::state::{GCMode, Lua, LuaOptions, WeakLua}; pub use crate::state::{GCMode, Lua, LuaOptions, WeakLua};
pub use crate::stdlib::StdLib; pub use crate::stdlib::StdLib;
pub use crate::string::{BorrowedBytes, BorrowedStr, String}; pub use crate::string::{BorrowedBytes, BorrowedStr, LuaString, LuaString as String};
pub use crate::table::{Table, TablePairs, TableSequence}; pub use crate::table::Table;
pub use crate::thread::{Thread, ThreadStatus}; pub use crate::thread::{Thread, ThreadStatus};
pub use crate::traits::{ pub use crate::traits::{
FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, LuaNativeFn, LuaNativeFnMut, ObjectLike, FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, LuaNativeFn, LuaNativeFnMut, ObjectLike,
@@ -131,7 +129,6 @@ pub use crate::debug::HookTriggers;
pub use crate::{ pub use crate::{
buffer::Buffer, buffer::Buffer,
chunk::{CompileConstant, Compiler}, chunk::{CompileConstant, Compiler},
function::CoverageInfo,
luau::{HeapDump, NavigateError, Require, TextRequirer}, luau::{HeapDump, NavigateError, Require, TextRequirer},
vector::Vector, vector::Vector,
}; };
@@ -143,7 +140,7 @@ pub use crate::{thread::AsyncThread, traits::LuaNativeAsyncFn};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
#[doc(inline)] #[doc(inline)]
pub use crate::{ pub use crate::{
serde::{de::Options as DeserializeOptions, ser::Options as SerializeOptions, LuaSerdeExt}, serde::{LuaSerdeExt, de::Options as DeserializeOptions, ser::Options as SerializeOptions},
value::SerializableValue, value::SerializableValue,
}; };
+13 -13
View File
@@ -79,10 +79,10 @@ impl HeapDump {
let mut size_by_type = HashMap::new(); let mut size_by_type = HashMap::new();
let objects = self.data["objects"].as_object()?; let objects = self.data["objects"].as_object()?;
for obj in objects.values() { for obj in objects.values() {
if let Some(cat_id) = category_id { if let Some(cat_id) = category_id
if obj["cat"].as_i64()? != cat_id { && obj["cat"].as_i64()? != cat_id
continue; {
} continue;
} }
update_size(&mut size_by_type, obj["type"].as_str()?, obj["size"].as_u64()?); update_size(&mut size_by_type, obj["type"].as_str()?, obj["size"].as_u64()?);
} }
@@ -123,18 +123,18 @@ impl HeapDump {
if obj["type"] != "userdata" { if obj["type"] != "userdata" {
continue; continue;
} }
if let Some(cat_id) = category_id { if let Some(cat_id) = category_id
if obj["cat"].as_i64()? != cat_id { && obj["cat"].as_i64()? != cat_id
continue; {
} continue;
} }
// Determine userdata type from metatable // Determine userdata type from metatable
let mut ud_type = "unknown"; let mut ud_type = "unknown";
if let Some(metatable_addr) = obj["metatable"].as_str() { if let Some(metatable_addr) = obj["metatable"].as_str()
if let Some(t) = get_key(objects, &objects[metatable_addr], "__type") { && let Some(t) = get_key(objects, &objects[metatable_addr], "__type")
ud_type = t; {
} ud_type = t;
} }
update_size(&mut size_by_userdata, ud_type, obj["size"].as_u64()?); update_size(&mut size_by_userdata, ud_type, obj["size"].as_u64()?);
} }
@@ -155,7 +155,7 @@ impl HeapDump {
/// Updates the size mapping for a given key. /// Updates the size mapping for a given key.
fn update_size<K: Eq + Hash>(size_type: &mut HashMap<K, (usize, u64)>, key: K, size: u64) { fn update_size<K: Eq + Hash>(size_type: &mut HashMap<K, (usize, u64)>, key: K, size: u64) {
let (ref mut count, ref mut total_size) = size_type.entry(key).or_insert((0, 0)); let (count, total_size) = size_type.entry(key).or_insert((0, 0));
*count += 1; *count += 1;
*total_size += size; *total_size += size;
} }
+2 -2
View File
@@ -313,8 +313,8 @@ mod tests {
fn test_error_cases() { fn test_error_cases() {
assert!(parse("").is_err()); assert!(parse("").is_err());
assert!(parse("nul").is_err()); assert!(parse("nul").is_err());
assert!(parse("tru").is_err()); assert!(parse("tru").is_err()); // typos:ignore
assert!(parse("fals").is_err()); assert!(parse("fals").is_err()); // typos:ignore
assert!(parse(r#""unterminated"#).is_err()); assert!(parse(r#""unterminated"#).is_err());
assert!(parse("[1,2,]").is_err()); assert!(parse("[1,2,]").is_err());
assert!(parse(r#"{"key""#).is_err()); assert!(parse(r#"{"key""#).is_err());
+1 -1
View File
@@ -5,7 +5,7 @@ use std::ptr;
use crate::chunk::ChunkMode; use crate::chunk::ChunkMode;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::function::Function; use crate::function::Function;
use crate::state::{callback_error_ext, ExtraData, Lua}; use crate::state::{ExtraData, Lua, callback_error_ext};
use crate::traits::{FromLuaMulti, IntoLua}; use crate::traits::{FromLuaMulti, IntoLua};
use crate::types::MaybeSend; use crate::types::MaybeSend;
+2 -1
View File
@@ -8,7 +8,7 @@ use std::{fmt, mem, ptr};
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::function::Function; use crate::function::Function;
use crate::state::{callback_error_ext, Lua}; use crate::state::{Lua, callback_error_ext};
use crate::table::Table; use crate::table::Table;
use crate::types::MaybeSend; use crate::types::MaybeSend;
@@ -299,6 +299,7 @@ pub(super) unsafe extern "C-unwind" fn init_config(config: *mut ffi::luarequire_
(*config).is_require_allowed = is_require_allowed; (*config).is_require_allowed = is_require_allowed;
(*config).reset = reset; (*config).reset = reset;
(*config).jump_to_alias = jump_to_alias; (*config).jump_to_alias = jump_to_alias;
(*config).to_alias_override = None;
(*config).to_alias_fallback = None; (*config).to_alias_fallback = None;
(*config).to_parent = to_parent; (*config).to_parent = to_parent;
(*config).to_child = to_child; (*config).to_child = to_child;
+4 -4
View File
@@ -42,10 +42,10 @@ impl TextRequirer {
} }
fn normalize_chunk_name(chunk_name: &str) -> &str { fn normalize_chunk_name(chunk_name: &str) -> &str {
if let Some((path, line)) = chunk_name.rsplit_once(':') { if let Some((path, line)) = chunk_name.rsplit_once(':')
if line.parse::<u32>().is_ok() { && line.parse::<u32>().is_ok()
return path; {
} return path;
} }
chunk_name chunk_name
} }
+1 -14
View File
@@ -28,9 +28,7 @@ impl MemoryState {
} }
#[cfg(not(feature = "luau"))] #[cfg(not(feature = "luau"))]
#[rustversion::since(1.85)]
#[inline] #[inline]
#[allow(clippy::incompatible_msrv)]
pub(crate) unsafe fn get(state: *mut ffi::lua_State) -> *mut Self { pub(crate) unsafe fn get(state: *mut ffi::lua_State) -> *mut Self {
let mut mem_state = ptr::null_mut(); let mut mem_state = ptr::null_mut();
if !ptr::fn_addr_eq(ffi::lua_getallocf(state, &mut mem_state), ALLOCATOR) { if !ptr::fn_addr_eq(ffi::lua_getallocf(state, &mut mem_state), ALLOCATOR) {
@@ -39,17 +37,6 @@ impl MemoryState {
mem_state as *mut MemoryState mem_state as *mut MemoryState
} }
#[cfg(not(feature = "luau"))]
#[rustversion::before(1.85)]
#[inline]
pub(crate) unsafe fn get(state: *mut ffi::lua_State) -> *mut Self {
let mut mem_state = ptr::null_mut();
if ffi::lua_getallocf(state, &mut mem_state) != ALLOCATOR {
mem_state = ptr::null_mut();
}
mem_state as *mut MemoryState
}
#[inline] #[inline]
pub(crate) fn used_memory(&self) -> usize { pub(crate) fn used_memory(&self) -> usize {
self.used_memory as usize self.used_memory as usize
@@ -83,7 +70,7 @@ impl MemoryState {
} }
// Does nothing apart from calling `f()`, we don't need to bypass any limits // Does nothing apart from calling `f()`, we don't need to bypass any limits
#[cfg(any(feature = "lua52", feature = "lua53", feature = "lua54"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
#[inline] #[inline]
pub(crate) unsafe fn relax_limit_with(_state: *mut ffi::lua_State, f: impl FnOnce()) { pub(crate) unsafe fn relax_limit_with(_state: *mut ffi::lua_State, f: impl FnOnce()) {
f(); f();
+1 -1
View File
@@ -1,4 +1,4 @@
use std::collections::{vec_deque, VecDeque}; use std::collections::{VecDeque, vec_deque};
use std::iter::FromIterator; use std::iter::FromIterator;
use std::mem; use std::mem;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
+7 -8
View File
@@ -5,16 +5,16 @@ pub use crate::{
AnyUserData as LuaAnyUserData, BorrowedBytes as LuaBorrowedBytes, BorrowedStr as LuaBorrowedStr, AnyUserData as LuaAnyUserData, BorrowedBytes as LuaBorrowedBytes, BorrowedStr as LuaBorrowedStr,
Chunk as LuaChunk, Either as LuaEither, Error as LuaError, ErrorContext as LuaErrorContext, Chunk as LuaChunk, Either as LuaEither, Error as LuaError, ErrorContext as LuaErrorContext,
ExternalError as LuaExternalError, ExternalResult as LuaExternalResult, FromLua, FromLuaMulti, ExternalError as LuaExternalError, ExternalResult as LuaExternalResult, FromLua, FromLuaMulti,
Function as LuaFunction, FunctionInfo as LuaFunctionInfo, GCMode as LuaGCMode, Integer as LuaInteger, Function as LuaFunction, GCMode as LuaGCMode, Integer as LuaInteger, IntoLua, IntoLuaMulti,
IntoLua, IntoLuaMulti, LightUserData as LuaLightUserData, Lua, LuaNativeFn, LuaNativeFnMut, LuaOptions, LightUserData as LuaLightUserData, Lua, LuaNativeFn, LuaNativeFnMut, LuaOptions, LuaString,
MetaMethod as LuaMetaMethod, MultiValue as LuaMultiValue, Nil as LuaNil, Number as LuaNumber, MetaMethod as LuaMetaMethod, MultiValue as LuaMultiValue, Nil as LuaNil, Number as LuaNumber,
ObjectLike as LuaObjectLike, RegistryKey as LuaRegistryKey, Result as LuaResult, StdLib as LuaStdLib, ObjectLike as LuaObjectLike, RegistryKey as LuaRegistryKey, Result as LuaResult, StdLib as LuaStdLib,
String as LuaString, Table as LuaTable, TablePairs as LuaTablePairs, TableSequence as LuaTableSequence, Table as LuaTable, Thread as LuaThread, ThreadStatus as LuaThreadStatus, UserData as LuaUserData,
Thread as LuaThread, ThreadStatus as LuaThreadStatus, UserData as LuaUserData,
UserDataFields as LuaUserDataFields, UserDataMetatable as LuaUserDataMetatable, UserDataFields as LuaUserDataFields, UserDataMetatable as LuaUserDataMetatable,
UserDataMethods as LuaUserDataMethods, UserDataRef as LuaUserDataRef, UserDataMethods as LuaUserDataMethods, UserDataRef as LuaUserDataRef,
UserDataRefMut as LuaUserDataRefMut, UserDataRegistry as LuaUserDataRegistry, Value as LuaValue, UserDataRefMut as LuaUserDataRefMut, UserDataRegistry as LuaUserDataRegistry, Value as LuaValue,
Variadic as LuaVariadic, VmState as LuaVmState, WeakLua, Variadic as LuaVariadic, VmState as LuaVmState, WeakLua, function::FunctionInfo as LuaFunctionInfo,
table::TablePairs as LuaTablePairs, table::TableSequence as LuaTableSequence,
}; };
#[cfg(not(feature = "luau"))] #[cfg(not(feature = "luau"))]
@@ -24,9 +24,8 @@ pub use crate::HookTriggers as LuaHookTriggers;
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
#[doc(no_inline)] #[doc(no_inline)]
pub use crate::{ pub use crate::{
CompileConstant as LuaCompileConstant, CoverageInfo as LuaCoverageInfo, CompileConstant as LuaCompileConstant, NavigateError as LuaNavigateError, Require as LuaRequire,
NavigateError as LuaNavigateError, Require as LuaRequire, TextRequirer as LuaTextRequirer, TextRequirer as LuaTextRequirer, Vector as LuaVector,
Vector as LuaVector,
}; };
#[cfg(feature = "async")] #[cfg(feature = "async")]
+1 -1
View File
@@ -8,7 +8,7 @@ use crate::state::{Lua, LuaGuard, RawLua};
use crate::traits::{FromLuaMulti, IntoLuaMulti}; use crate::traits::{FromLuaMulti, IntoLuaMulti};
use crate::types::{Callback, CallbackUpvalue, ScopedCallback, ValueRef}; use crate::types::{Callback, CallbackUpvalue, ScopedCallback, ValueRef};
use crate::userdata::{AnyUserData, UserData, UserDataRegistry, UserDataStorage}; use crate::userdata::{AnyUserData, UserData, UserDataRegistry, UserDataStorage};
use crate::util::{self, check_stack, get_metatable_ptr, get_userdata, take_userdata, StackGuard}; use crate::util::{self, StackGuard, check_stack, get_metatable_ptr, get_userdata, take_userdata};
/// Constructed by the [`Lua::scope`] method, allows temporarily creating Lua userdata and /// Constructed by the [`Lua::scope`] method, allows temporarily creating Lua userdata and
/// callbacks that are not required to be `Send` or `'static`. /// callbacks that are not required to be `Send` or `'static`.
+3 -4
View File
@@ -4,7 +4,6 @@ use std::cell::RefCell;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::rc::Rc; use std::rc::Rc;
use std::result::Result as StdResult; use std::result::Result as StdResult;
use std::string::String as StdString;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use serde::de::{self, IntoDeserializer}; use serde::de::{self, IntoDeserializer};
@@ -243,14 +242,14 @@ impl<'de> serde::Deserializer<'de> for Deserializer {
Value::Table(table) => { Value::Table(table) => {
let _guard = RecursionGuard::new(&table, &self.visited); let _guard = RecursionGuard::new(&table, &self.visited);
let mut iter = table.pairs::<StdString, Value>(); let mut iter = table.pairs::<String, Value>();
let (variant, value) = match iter.next() { let (variant, value) = match iter.next() {
Some(v) => v?, Some(v) => v?,
None => { None => {
return Err(de::Error::invalid_value( return Err(de::Error::invalid_value(
de::Unexpected::Map, de::Unexpected::Map,
&"map with a single key", &"map with a single key",
)) ));
} }
}; };
@@ -621,7 +620,7 @@ impl<'de> de::MapAccess<'de> for MapDeserializer<'_> {
} }
struct EnumDeserializer { struct EnumDeserializer {
variant: StdString, variant: String,
value: Option<Value>, value: Option<Value>,
options: Options, options: Options,
visited: Rc<RefCell<FxHashSet<*const c_void>>>, visited: Rc<RefCell<FxHashSet<*const c_void>>>,
+5 -5
View File
@@ -1,6 +1,6 @@
//! Serialize a Rust data structure into Lua value. //! Serialize a Rust data structure into Lua value.
use serde::{ser, Serialize}; use serde::{Serialize, ser};
use super::LuaSerdeExt; use super::LuaSerdeExt;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
@@ -531,10 +531,10 @@ impl ser::SerializeStruct for SerializeStruct<'_> {
Some(table @ Value::Table(_)) => Ok(table), Some(table @ Value::Table(_)) => Ok(table),
Some(value @ Value::String(_)) if self.options.detect_serde_json_arbitrary_precision => { Some(value @ Value::String(_)) if self.options.detect_serde_json_arbitrary_precision => {
let number_s = value.to_string()?; let number_s = value.to_string()?;
if number_s.contains(['.', 'e', 'E']) { if number_s.contains(['.', 'e', 'E'])
if let Ok(number) = number_s.parse().map(Value::Number) { && let Ok(number) = number_s.parse().map(Value::Number)
return Ok(number); {
} return Ok(number);
} }
Ok(number_s Ok(number_s
.parse() .parse()
+120 -44
View File
@@ -15,7 +15,7 @@ use crate::memory::MemoryState;
use crate::multi::MultiValue; use crate::multi::MultiValue;
use crate::scope::Scope; use crate::scope::Scope;
use crate::stdlib::StdLib; use crate::stdlib::StdLib;
use crate::string::String; use crate::string::LuaString;
use crate::table::Table; use crate::table::Table;
use crate::thread::Thread; use crate::thread::Thread;
use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti}; use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti};
@@ -24,7 +24,7 @@ use crate::types::{
ReentrantMutexGuard, RegistryKey, VmState, XRc, XWeak, ReentrantMutexGuard, RegistryKey, VmState, XRc, XWeak,
}; };
use crate::userdata::{AnyUserData, UserData, UserDataProxy, UserDataRegistry, UserDataStorage}; use crate::userdata::{AnyUserData, UserData, UserDataProxy, UserDataRegistry, UserDataStorage};
use crate::util::{assert_stack, check_stack, protect_lua_closure, push_string, rawset_field, StackGuard}; use crate::util::{StackGuard, assert_stack, check_stack, protect_lua_closure, push_string, rawset_field};
use crate::value::{Nil, Value}; use crate::value::{Nil, Value};
#[cfg(not(feature = "luau"))] #[cfg(not(feature = "luau"))]
@@ -73,8 +73,8 @@ pub(crate) struct LuaGuard(ArcReentrantMutexGuard<RawLua>);
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum GCMode { pub enum GCMode {
Incremental, Incremental,
#[cfg(feature = "lua54")] #[cfg(any(feature = "lua55", feature = "lua54"))]
#[cfg_attr(docsrs, doc(cfg(feature = "lua54")))] #[cfg_attr(docsrs, doc(cfg(any(feature = "lua55", feature = "lua54"))))]
Generational, Generational,
} }
@@ -249,7 +249,7 @@ impl Lua {
ffi::luaL_loadstring as _, ffi::luaL_loadstring as _,
ffi::luaL_openlibs as _, ffi::luaL_openlibs as _,
]); ]);
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
{ {
_symbols.push(ffi::lua_getglobal as _); _symbols.push(ffi::lua_getglobal as _);
_symbols.push(ffi::lua_setglobal as _); _symbols.push(ffi::lua_setglobal as _);
@@ -337,6 +337,39 @@ impl Lua {
R::from_stack_multi(nresults, &lua) R::from_stack_multi(nresults, &lua)
} }
/// Runs callback with the inner RawLua value. It can be used to manually push and get values on
/// the stack.
///
/// This function is safe because all unsafe actions with RawLua can only be done with unsafe
///
/// # Example
/// ```
/// # use mlua::{Lua, Result, FromLua, IntoLua};
/// # fn main() -> Result<()> {
/// let lua = Lua::new();
/// let n: i32 = {
/// let num = 11i32;
/// lua.exec_raw_lua(|lua| {
/// unsafe {
/// <i32 as IntoLua>::push_into_stack(num, lua)?;
/// }
///
/// let n = unsafe {
/// <i32 as FromLua>::from_stack(-1, lua)?
/// };
/// Result::Ok(n)
/// })
/// }?;
/// assert_eq!(n, 11);
/// # Ok(())
/// # }
/// ```
#[doc(hidden)]
pub fn exec_raw_lua<R>(&self, f: impl FnOnce(&RawLua) -> R) -> R {
let lua = self.lock();
f(&lua)
}
/// Loads the specified subset of the standard libraries into an existing Lua state. /// Loads the specified subset of the standard libraries into an existing Lua state.
/// ///
/// Use the [`StdLib`] flags to specify the libraries you want to load. /// Use the [`StdLib`] flags to specify the libraries you want to load.
@@ -382,7 +415,7 @@ impl Lua {
#[cfg(not(feature = "luau"))] #[cfg(not(feature = "luau"))]
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))] #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
pub fn preload_module(&self, modname: &str, func: Function) -> Result<()> { pub fn preload_module(&self, modname: &str, func: Function) -> Result<()> {
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
let preload = unsafe { let preload = unsafe {
self.exec_raw::<Option<Table>>((), |state| { self.exec_raw::<Option<Table>>((), |state| {
ffi::lua_getfield(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_PRELOAD_TABLE); ffi::lua_getfield(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_PRELOAD_TABLE);
@@ -814,15 +847,14 @@ impl Lua {
} }
/// Sets the warning function to be used by Lua to emit warnings. /// Sets the warning function to be used by Lua to emit warnings.
#[cfg(feature = "lua54")] #[cfg(any(feature = "lua55", feature = "lua54"))]
#[cfg_attr(docsrs, doc(cfg(feature = "lua54")))] #[cfg_attr(docsrs, doc(cfg(any(feature = "lua55", feature = "lua54"))))]
pub fn set_warning_function<F>(&self, callback: F) pub fn set_warning_function<F>(&self, callback: F)
where where
F: Fn(&Lua, &str, bool) -> Result<()> + MaybeSend + 'static, F: Fn(&Lua, &str, bool) -> Result<()> + MaybeSend + 'static,
{ {
use std::ffi::CStr; use std::ffi::CStr;
use std::os::raw::{c_char, c_void}; use std::os::raw::{c_char, c_void};
use std::string::String as StdString;
unsafe extern "C-unwind" fn warn_proc(ud: *mut c_void, msg: *const c_char, tocont: c_int) { unsafe extern "C-unwind" fn warn_proc(ud: *mut c_void, msg: *const c_char, tocont: c_int) {
let extra = ud as *mut ExtraData; let extra = ud as *mut ExtraData;
@@ -832,7 +864,7 @@ impl Lua {
if XRc::strong_count(&warn_callback) > 2 { if XRc::strong_count(&warn_callback) > 2 {
return Ok(()); return Ok(());
} }
let msg = StdString::from_utf8_lossy(CStr::from_ptr(msg).to_bytes()); let msg = String::from_utf8_lossy(CStr::from_ptr(msg).to_bytes());
warn_callback((*extra).lua(), &msg, tocont != 0) warn_callback((*extra).lua(), &msg, tocont != 0)
}); });
} }
@@ -847,8 +879,8 @@ impl Lua {
/// Removes warning function previously set by `set_warning_function`. /// Removes warning function previously set by `set_warning_function`.
/// ///
/// This function has no effect if a warning function was not previously set. /// This function has no effect if a warning function was not previously set.
#[cfg(feature = "lua54")] #[cfg(any(feature = "lua55", feature = "lua54"))]
#[cfg_attr(docsrs, doc(cfg(feature = "lua54")))] #[cfg_attr(docsrs, doc(cfg(any(feature = "lua55", feature = "lua54"))))]
pub fn remove_warning_function(&self) { pub fn remove_warning_function(&self) {
let lua = self.lock(); let lua = self.lock();
unsafe { unsafe {
@@ -861,8 +893,8 @@ impl Lua {
/// ///
/// A message in a call with `incomplete` set to `true` should be continued in /// A message in a call with `incomplete` set to `true` should be continued in
/// another call to this function. /// another call to this function.
#[cfg(feature = "lua54")] #[cfg(any(feature = "lua55", feature = "lua54"))]
#[cfg_attr(docsrs, doc(cfg(feature = "lua54")))] #[cfg_attr(docsrs, doc(cfg(any(feature = "lua55", feature = "lua54"))))]
pub fn warning(&self, msg: impl AsRef<str>, incomplete: bool) { pub fn warning(&self, msg: impl AsRef<str>, incomplete: bool) {
let msg = msg.as_ref(); let msg = msg.as_ref();
let mut bytes = vec![0; msg.len() + 1]; let mut bytes = vec![0; msg.len() + 1];
@@ -903,7 +935,7 @@ impl Lua {
/// ///
/// The `msg` parameter, if provided, is added at the beginning of the traceback. /// The `msg` parameter, if provided, is added at the beginning of the traceback.
/// The `level` parameter works the same way as in [`Lua::inspect_stack`]. /// The `level` parameter works the same way as in [`Lua::inspect_stack`].
pub fn traceback(&self, msg: Option<&str>, level: usize) -> Result<String> { pub fn traceback(&self, msg: Option<&str>, level: usize) -> Result<LuaString> {
let lua = self.lock(); let lua = self.lock();
unsafe { unsafe {
check_stack(lua.state(), 3)?; check_stack(lua.state(), 3)?;
@@ -915,7 +947,7 @@ impl Lua {
// `protect_lua` adds it's own call frame, so we need to increase level by 1 // `protect_lua` adds it's own call frame, so we need to increase level by 1
ffi::luaL_traceback(state, state, msg, (level + 1) as c_int); ffi::luaL_traceback(state, state, msg, (level + 1) as c_int);
})?; })?;
Ok(String(lua.pop_ref())) Ok(LuaString(lua.pop_ref()))
} }
} }
@@ -954,7 +986,13 @@ impl Lua {
} }
/// Returns `true` if the garbage collector is currently running automatically. /// Returns `true` if the garbage collector is currently running automatically.
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau"))] #[cfg(any(
feature = "lua55",
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luau"
))]
pub fn gc_is_running(&self) -> bool { pub fn gc_is_running(&self) -> bool {
let lua = self.lock(); let lua = self.lock();
unsafe { ffi::lua_gc(lua.main_state(), ffi::LUA_GCISRUNNING, 0) != 0 } unsafe { ffi::lua_gc(lua.main_state(), ffi::LUA_GCISRUNNING, 0) != 0 }
@@ -1019,8 +1057,12 @@ impl Lua {
let lua = self.lock(); let lua = self.lock();
let state = lua.main_state(); let state = lua.main_state();
unsafe { unsafe {
#[cfg(not(feature = "luau"))] #[cfg(feature = "lua55")]
return ffi::lua_gc(state, ffi::LUA_GCPARAM, ffi::LUA_GCPPAUSE, pause);
#[cfg(not(any(feature = "lua55", feature = "luau")))]
return ffi::lua_gc(state, ffi::LUA_GCSETPAUSE, pause); return ffi::lua_gc(state, ffi::LUA_GCSETPAUSE, pause);
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
return ffi::lua_gc(state, ffi::LUA_GCSETGOAL, pause); return ffi::lua_gc(state, ffi::LUA_GCSETGOAL, pause);
} }
@@ -1034,7 +1076,18 @@ impl Lua {
/// [documentation]: https://www.lua.org/manual/5.4/manual.html#2.5 /// [documentation]: https://www.lua.org/manual/5.4/manual.html#2.5
pub fn gc_set_step_multiplier(&self, step_multiplier: c_int) -> c_int { pub fn gc_set_step_multiplier(&self, step_multiplier: c_int) -> c_int {
let lua = self.lock(); let lua = self.lock();
unsafe { ffi::lua_gc(lua.main_state(), ffi::LUA_GCSETSTEPMUL, step_multiplier) } unsafe {
#[cfg(feature = "lua55")]
return ffi::lua_gc(
lua.main_state(),
ffi::LUA_GCPARAM,
ffi::LUA_GCPSTEPMUL,
step_multiplier,
);
#[cfg(not(feature = "lua55"))]
return ffi::lua_gc(lua.main_state(), ffi::LUA_GCSETSTEPMUL, step_multiplier);
}
} }
/// Changes the collector to incremental mode with the given parameters. /// Changes the collector to incremental mode with the given parameters.
@@ -1076,9 +1129,16 @@ impl Lua {
GCMode::Incremental GCMode::Incremental
} }
#[cfg(feature = "lua55")]
let prev_mode = unsafe {
ffi::lua_gc(state, ffi::LUA_GCPARAM, ffi::LUA_GCPPAUSE, pause);
ffi::lua_gc(state, ffi::LUA_GCPARAM, ffi::LUA_GCPSTEPMUL, step_multiplier);
ffi::lua_gc(state, ffi::LUA_GCPARAM, ffi::LUA_GCPSTEPSIZE, step_size);
ffi::lua_gc(state, ffi::LUA_GCINC)
};
#[cfg(feature = "lua54")] #[cfg(feature = "lua54")]
let prev_mode = unsafe { ffi::lua_gc(state, ffi::LUA_GCINC, pause, step_multiplier, step_size) }; let prev_mode = unsafe { ffi::lua_gc(state, ffi::LUA_GCINC, pause, step_multiplier, step_size) };
#[cfg(feature = "lua54")] #[cfg(any(feature = "lua55", feature = "lua54"))]
match prev_mode { match prev_mode {
ffi::LUA_GCINC => GCMode::Incremental, ffi::LUA_GCINC => GCMode::Incremental,
ffi::LUA_GCGEN => GCMode::Generational, ffi::LUA_GCGEN => GCMode::Generational,
@@ -1092,11 +1152,19 @@ impl Lua {
/// can be found in the Lua 5.4 [documentation][lua_doc]. /// can be found in the Lua 5.4 [documentation][lua_doc].
/// ///
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#2.5.2 /// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#2.5.2
#[cfg(feature = "lua54")] #[cfg(any(feature = "lua55", feature = "lua54"))]
#[cfg_attr(docsrs, doc(cfg(feature = "lua54")))] #[cfg_attr(docsrs, doc(cfg(any(feature = "lua55", feature = "lua54"))))]
pub fn gc_gen(&self, minor_multiplier: c_int, major_multiplier: c_int) -> GCMode { pub fn gc_gen(&self, minor_multiplier: c_int, major_multiplier: c_int) -> GCMode {
let lua = self.lock(); let lua = self.lock();
let state = lua.main_state(); let state = lua.main_state();
#[cfg(feature = "lua55")]
let prev_mode = unsafe {
ffi::lua_gc(state, ffi::LUA_GCPARAM, ffi::LUA_GCPMINORMUL, minor_multiplier);
ffi::lua_gc(state, ffi::LUA_GCPARAM, ffi::LUA_GCPMINORMAJOR, major_multiplier);
// TODO: LUA_GCPMAJORMINOR
ffi::lua_gc(state, ffi::LUA_GCGEN)
};
#[cfg(not(feature = "lua55"))]
let prev_mode = unsafe { ffi::lua_gc(state, ffi::LUA_GCGEN, minor_multiplier, major_multiplier) }; let prev_mode = unsafe { ffi::lua_gc(state, ffi::LUA_GCGEN, minor_multiplier, major_multiplier) };
match prev_mode { match prev_mode {
ffi::LUA_GCGEN => GCMode::Generational, ffi::LUA_GCGEN => GCMode::Generational,
@@ -1136,10 +1204,10 @@ impl Lua {
#[doc(hidden)] #[doc(hidden)]
#[allow(clippy::result_unit_err)] #[allow(clippy::result_unit_err)]
pub fn set_fflag(name: &str, enabled: bool) -> StdResult<(), ()> { pub fn set_fflag(name: &str, enabled: bool) -> StdResult<(), ()> {
if let Ok(name) = std::ffi::CString::new(name) { if let Ok(name) = std::ffi::CString::new(name)
if unsafe { ffi::luau_setfflag(name.as_ptr(), enabled as c_int) != 0 } { && unsafe { ffi::luau_setfflag(name.as_ptr(), enabled as c_int) != 0 }
return Ok(()); {
} return Ok(());
} }
Err(()) Err(())
} }
@@ -1179,10 +1247,21 @@ impl Lua {
/// Lua strings can be arbitrary `[u8]` data including embedded nulls, so in addition to `&str` /// Lua strings can be arbitrary `[u8]` data including embedded nulls, so in addition to `&str`
/// and `&String`, you can also pass plain `&[u8]` here. /// and `&String`, you can also pass plain `&[u8]` here.
#[inline] #[inline]
pub fn create_string(&self, s: impl AsRef<[u8]>) -> Result<String> { pub fn create_string(&self, s: impl AsRef<[u8]>) -> Result<LuaString> {
unsafe { self.lock().create_string(s.as_ref()) } unsafe { self.lock().create_string(s.as_ref()) }
} }
/// Creates and returns an external Lua string.
///
/// External string is a string where the memory is managed by Rust code, and Lua only holds a
/// reference to it. This can be used to avoid copying large strings into Lua memory.
#[cfg(feature = "lua55")]
#[cfg_attr(docsrs, doc(cfg(feature = "lua55")))]
#[inline]
pub fn create_external_string(&self, s: impl Into<Vec<u8>>) -> Result<LuaString> {
unsafe { self.lock().create_external_string(s.into()) }
}
/// Creates and returns a Luau [buffer] object from a byte slice of data. /// Creates and returns a Luau [buffer] object from a byte slice of data.
/// ///
/// [buffer]: https://luau.org/library#buffer-library /// [buffer]: https://luau.org/library#buffer-library
@@ -1317,7 +1396,12 @@ impl Lua {
/// This function is unsafe because provides a way to execute unsafe C function. /// This function is unsafe because provides a way to execute unsafe C function.
pub unsafe fn create_c_function(&self, func: ffi::lua_CFunction) -> Result<Function> { pub unsafe fn create_c_function(&self, func: ffi::lua_CFunction) -> Result<Function> {
let lua = self.lock(); let lua = self.lock();
if cfg!(any(feature = "lua54", feature = "lua53", feature = "lua52")) { if cfg!(any(
feature = "lua55",
feature = "lua54",
feature = "lua53",
feature = "lua52"
)) {
ffi::lua_pushcfunction(lua.ref_thread(), func); ffi::lua_pushcfunction(lua.ref_thread(), func);
return Ok(Function(lua.pop_ref_thread())); return Ok(Function(lua.pop_ref_thread()));
} }
@@ -1578,7 +1662,7 @@ impl Lua {
unsafe { unsafe {
let _sg = StackGuard::new(state); let _sg = StackGuard::new(state);
assert_stack(state, 1); assert_stack(state, 1);
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS); ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
ffi::lua_pushvalue(state, ffi::LUA_GLOBALSINDEX); ffi::lua_pushvalue(state, ffi::LUA_GLOBALSINDEX);
@@ -1610,7 +1694,7 @@ impl Lua {
lua.push_ref(&globals.0); lua.push_ref(&globals.0);
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
ffi::lua_rawseti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS); ffi::lua_rawseti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
ffi::lua_replace(state, ffi::LUA_GLOBALSINDEX); ffi::lua_replace(state, ffi::LUA_GLOBALSINDEX);
@@ -1656,7 +1740,7 @@ impl Lua {
/// ///
/// To succeed, the value must be a string (in which case this is a no-op), an integer, or a /// To succeed, the value must be a string (in which case this is a no-op), an integer, or a
/// number. /// number.
pub fn coerce_string(&self, v: Value) -> Result<Option<String>> { pub fn coerce_string(&self, v: Value) -> Result<Option<LuaString>> {
Ok(match v { Ok(match v {
Value::String(s) => Some(s), Value::String(s) => Some(s),
v => unsafe { v => unsafe {
@@ -1674,7 +1758,7 @@ impl Lua {
})? })?
}; };
if !res.is_null() { if !res.is_null() {
Some(String(lua.pop_ref())) Some(LuaString(lua.pop_ref()))
} else { } else {
None None
} }
@@ -1700,11 +1784,7 @@ impl Lua {
lua.push_value(&v)?; lua.push_value(&v)?;
let mut isint = 0; let mut isint = 0;
let i = ffi::lua_tointegerx(state, -1, &mut isint); let i = ffi::lua_tointegerx(state, -1, &mut isint);
if isint == 0 { if isint == 0 { None } else { Some(i) }
None
} else {
Some(i)
}
}, },
}) })
} }
@@ -1726,11 +1806,7 @@ impl Lua {
lua.push_value(&v)?; lua.push_value(&v)?;
let mut isnum = 0; let mut isnum = 0;
let n = ffi::lua_tonumberx(state, -1, &mut isnum); let n = ffi::lua_tonumberx(state, -1, &mut isnum);
if isnum == 0 { if isnum == 0 { None } else { Some(n) }
None
} else {
Some(n)
}
}, },
}) })
} }
@@ -2098,7 +2174,7 @@ impl Lua {
/// Suspends the current async function, returning the provided arguments to caller. /// Suspends the current async function, returning the provided arguments to caller.
/// ///
/// This function is similar to [`coroutine.yield`] but allow yeilding Rust functions /// This function is similar to [`coroutine.yield`] but allow yielding Rust functions
/// and passing values to the caller. /// and passing values to the caller.
/// Please note that you cannot cross [`Thread`] boundaries (e.g. calling `yield_with` on one /// Please note that you cannot cross [`Thread`] boundaries (e.g. calling `yield_with` on one
/// thread and resuming on another). /// thread and resuming on another).
@@ -2210,7 +2286,7 @@ impl Lua {
})?, })?,
)?; )?;
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
let searchers: Table = package.get("searchers")?; let searchers: Table = package.get("searchers")?;
#[cfg(any(feature = "lua51", feature = "luajit"))] #[cfg(any(feature = "lua51", feature = "luajit"))]
let searchers: Table = package.get("loaders")?; let searchers: Table = package.get("loaders")?;
+3 -3
View File
@@ -14,7 +14,7 @@ use crate::state::RawLua;
use crate::stdlib::StdLib; use crate::stdlib::StdLib;
use crate::types::{AppData, ReentrantMutex, XRc}; use crate::types::{AppData, ReentrantMutex, XRc};
use crate::userdata::RawUserDataRegistry; use crate::userdata::RawUserDataRegistry;
use crate::util::{get_internal_metatable, push_internal_userdata, TypeKey, WrappedFailure}; use crate::util::{TypeKey, WrappedFailure, get_internal_metatable, push_internal_userdata};
#[cfg(any(feature = "luau", doc))] #[cfg(any(feature = "luau", doc))]
use crate::chunk::Compiler; use crate::chunk::Compiler;
@@ -77,7 +77,7 @@ pub(crate) struct ExtraData {
pub(super) hook_callback: Option<crate::types::HookCallback>, pub(super) hook_callback: Option<crate::types::HookCallback>,
#[cfg(not(feature = "luau"))] #[cfg(not(feature = "luau"))]
pub(super) hook_triggers: crate::debug::HookTriggers, pub(super) hook_triggers: crate::debug::HookTriggers,
#[cfg(feature = "lua54")] #[cfg(any(feature = "lua55", feature = "lua54"))]
pub(super) warn_callback: Option<crate::types::WarnCallback>, pub(super) warn_callback: Option<crate::types::WarnCallback>,
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
pub(super) interrupt_callback: Option<crate::types::InterruptCallback>, pub(super) interrupt_callback: Option<crate::types::InterruptCallback>,
@@ -182,7 +182,7 @@ impl ExtraData {
hook_callback: None, hook_callback: None,
#[cfg(not(feature = "luau"))] #[cfg(not(feature = "luau"))]
hook_triggers: Default::default(), hook_triggers: Default::default(),
#[cfg(feature = "lua54")] #[cfg(any(feature = "lua55", feature = "lua54"))]
warn_callback: None, warn_callback: None,
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
interrupt_callback: None, interrupt_callback: None,
+67 -30
View File
@@ -10,10 +10,10 @@ use std::sync::Arc;
use crate::chunk::ChunkMode; use crate::chunk::ChunkMode;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::function::Function; use crate::function::Function;
use crate::memory::{MemoryState, ALLOCATOR}; use crate::memory::{ALLOCATOR, MemoryState};
use crate::state::util::callback_error_ext; use crate::state::util::callback_error_ext;
use crate::stdlib::StdLib; use crate::stdlib::StdLib;
use crate::string::String; use crate::string::LuaString;
use crate::table::Table; use crate::table::Table;
use crate::thread::Thread; use crate::thread::Thread;
use crate::traits::IntoLua; use crate::traits::IntoLua;
@@ -22,14 +22,14 @@ use crate::types::{
LuaType, MaybeSend, ReentrantMutex, RegistryKey, ValueRef, XRc, LuaType, MaybeSend, ReentrantMutex, RegistryKey, ValueRef, XRc,
}; };
use crate::userdata::{ use crate::userdata::{
init_userdata_metatable, AnyUserData, MetaMethod, RawUserDataRegistry, UserData, UserDataRegistry, AnyUserData, MetaMethod, RawUserDataRegistry, UserData, UserDataRegistry, UserDataStorage,
UserDataStorage, init_userdata_metatable,
}; };
use crate::util::{ use crate::util::{
assert_stack, check_stack, get_destructed_userdata_metatable, get_internal_userdata, get_main_state, StackGuard, WrappedFailure, assert_stack, check_stack, get_destructed_userdata_metatable,
get_metatable_ptr, get_userdata, init_error_registry, init_internal_metatable, pop_error, get_internal_userdata, get_main_state, get_metatable_ptr, get_userdata, init_error_registry,
push_internal_userdata, push_string, push_table, push_userdata, rawset_field, safe_pcall, safe_xpcall, init_internal_metatable, pop_error, push_internal_userdata, push_string, push_table, push_userdata,
short_type_name, StackGuard, WrappedFailure, rawset_field, safe_pcall, safe_xpcall, short_type_name,
}; };
use crate::value::{Nil, Value}; use crate::value::{Nil, Value};
@@ -122,6 +122,12 @@ impl RawLua {
pub(super) unsafe fn new(libs: StdLib, options: &LuaOptions) -> XRc<ReentrantMutex<Self>> { pub(super) unsafe fn new(libs: StdLib, options: &LuaOptions) -> XRc<ReentrantMutex<Self>> {
let mem_state: *mut MemoryState = Box::into_raw(Box::default()); let mem_state: *mut MemoryState = Box::into_raw(Box::default());
#[cfg(feature = "lua55")]
let mut state = {
let seed = ffi::luaL_makeseed(ptr::null_mut());
ffi::lua_newstate(ALLOCATOR, mem_state as *mut c_void, seed)
};
#[cfg(not(feature = "lua55"))]
let mut state = ffi::lua_newstate(ALLOCATOR, mem_state as *mut c_void); let mut state = ffi::lua_newstate(ALLOCATOR, mem_state as *mut c_void);
// If state is null then switch to Lua internal allocator // If state is null then switch to Lua internal allocator
if state.is_null() { if state.is_null() {
@@ -153,7 +159,7 @@ impl RawLua {
(|| -> Result<()> { (|| -> Result<()> {
let _sg = StackGuard::new(state); let _sg = StackGuard::new(state);
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS); ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
ffi::lua_pushvalue(state, ffi::LUA_GLOBALSINDEX); ffi::lua_pushvalue(state, ffi::LUA_GLOBALSINDEX);
@@ -416,7 +422,7 @@ impl RawLua {
VmState::Yield => { VmState::Yield => {
// Only count and line events can yield // Only count and line events can yield
if event == ffi::LUA_HOOKCOUNT || event == ffi::LUA_HOOKLINE { if event == ffi::LUA_HOOKCOUNT || event == ffi::LUA_HOOKLINE {
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
if ffi::lua_isyieldable(state) != 0 { if ffi::lua_isyieldable(state) != 0 {
ffi::lua_yield(state, 0); ffi::lua_yield(state, 0);
} }
@@ -510,17 +516,34 @@ impl RawLua {
} }
/// See [`Lua::create_string`] /// See [`Lua::create_string`]
pub(crate) unsafe fn create_string(&self, s: &[u8]) -> Result<String> { pub(crate) unsafe fn create_string(&self, s: &[u8]) -> Result<LuaString> {
let state = self.state(); let state = self.state();
if self.unlikely_memory_error() { if self.unlikely_memory_error() {
push_string(state, s, false)?; push_string(state, s, false)?;
return Ok(String(self.pop_ref())); return Ok(LuaString(self.pop_ref()));
} }
let _sg = StackGuard::new(state); let _sg = StackGuard::new(state);
check_stack(state, 3)?; check_stack(state, 3)?;
push_string(state, s, true)?; push_string(state, s, true)?;
Ok(String(self.pop_ref())) Ok(LuaString(self.pop_ref()))
}
/// Creates an external string, that is, a string that uses memory not managed by Lua.
///
/// Modifies the input data to add `\0` terminator.
#[cfg(feature = "lua55")]
pub(crate) unsafe fn create_external_string(&self, bytes: Vec<u8>) -> Result<LuaString> {
let state = self.state();
if self.unlikely_memory_error() {
crate::util::push_external_string(state, bytes, false)?;
return Ok(LuaString(self.pop_ref()));
}
let _sg = StackGuard::new(state);
check_stack(state, 3)?;
crate::util::push_external_string(state, bytes, true)?;
Ok(LuaString(self.pop_ref()))
} }
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
@@ -658,10 +681,10 @@ impl RawLua {
#[cfg(feature = "async")] #[cfg(feature = "async")]
pub(crate) unsafe fn recycle_thread(&self, thread: &mut Thread) { pub(crate) unsafe fn recycle_thread(&self, thread: &mut Thread) {
let extra = &mut *self.extra.get(); let extra = &mut *self.extra.get();
if extra.thread_pool.len() < extra.thread_pool.capacity() { if extra.thread_pool.len() < extra.thread_pool.capacity()
if let Some(index) = thread.0.index_count.take() { && let Some(index) = thread.0.index_count.take()
extra.thread_pool.push(index); {
} extra.thread_pool.push(index);
} }
} }
@@ -709,14 +732,14 @@ impl RawLua {
/// ///
/// Uses up to 2 stack spaces to push a single value, does not call `checkstack`. /// Uses up to 2 stack spaces to push a single value, does not call `checkstack`.
#[inline(always)] #[inline(always)]
pub(crate) unsafe fn push(&self, value: impl IntoLua) -> Result<()> { pub unsafe fn push(&self, value: impl IntoLua) -> Result<()> {
value.push_into_stack(self) value.push_into_stack(self)
} }
/// Pushes a `Value` (by reference) onto the Lua stack. /// Pushes a `Value` (by reference) onto the Lua stack.
/// ///
/// Uses 2 stack spaces, does not call `checkstack`. /// Uses 2 stack spaces, does not call `checkstack`.
pub(crate) unsafe fn push_value(&self, value: &Value) -> Result<()> { pub unsafe fn push_value(&self, value: &Value) -> Result<()> {
let state = self.state(); let state = self.state();
match value { match value {
Value::Nil => ffi::lua_pushnil(state), Value::Nil => ffi::lua_pushnil(state),
@@ -750,7 +773,8 @@ impl RawLua {
/// Pops a value from the Lua stack. /// Pops a value from the Lua stack.
/// ///
/// Uses up to 1 stack spaces, does not call `checkstack`. /// Uses up to 1 stack spaces, does not call `checkstack`.
pub(crate) unsafe fn pop_value(&self) -> Value { #[inline]
pub unsafe fn pop_value(&self) -> Value {
let value = self.stack_value(-1, None); let value = self.stack_value(-1, None);
ffi::lua_pop(self.state(), 1); ffi::lua_pop(self.state(), 1);
value value
@@ -768,7 +792,7 @@ impl RawLua {
ffi::LUA_TLIGHTUSERDATA => Value::LightUserData(LightUserData(ffi::lua_touserdata(state, idx))), ffi::LUA_TLIGHTUSERDATA => Value::LightUserData(LightUserData(ffi::lua_touserdata(state, idx))),
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
ffi::LUA_TNUMBER => { ffi::LUA_TNUMBER => {
if ffi::lua_isinteger(state, idx) != 0 { if ffi::lua_isinteger(state, idx) != 0 {
Value::Integer(ffi::lua_tointeger(state, idx)) Value::Integer(ffi::lua_tointeger(state, idx))
@@ -800,7 +824,7 @@ impl RawLua {
ffi::LUA_TSTRING => { ffi::LUA_TSTRING => {
ffi::lua_xpush(state, self.ref_thread(), idx); ffi::lua_xpush(state, self.ref_thread(), idx);
Value::String(String(self.pop_ref_thread())) Value::String(LuaString(self.pop_ref_thread()))
} }
ffi::LUA_TTABLE => { ffi::LUA_TTABLE => {
@@ -899,7 +923,7 @@ impl RawLua {
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))] #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
ffi::lua_xpush(self.ref_thread(), state, ExtraData::ERROR_TRACEBACK_IDX); ffi::lua_xpush(self.ref_thread(), state, ExtraData::ERROR_TRACEBACK_IDX);
// Lua 5.2+ support light C functions that does not require extra allocations // Lua 5.2+ support light C functions that does not require extra allocations
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
ffi::lua_pushcfunction(state, crate::util::error_traceback); ffi::lua_pushcfunction(state, crate::util::error_traceback);
} }
@@ -1102,7 +1126,7 @@ impl RawLua {
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
if registry.enable_namecall { if registry.enable_namecall {
let map: &mut rustc_hash::FxHashMap<_, crate::types::CallbackPtr> = let map: &mut rustc_hash::FxHashMap<_, crate::types::CallbackPtr> =
methods_map.get_or_insert_with(Default::default); methods_map.get_or_insert_default();
for (k, m) in &registry.methods { for (k, m) in &registry.methods {
map.insert(k.as_bytes().to_vec(), &**m); map.insert(k.as_bytes().to_vec(), &**m);
} }
@@ -1195,10 +1219,11 @@ impl RawLua {
Ok(type_id) => Ok(type_id), Ok(type_id) => Ok(type_id),
Err(Error::UserDataTypeMismatch) if ffi::lua_type(state, idx) != ffi::LUA_TUSERDATA => { Err(Error::UserDataTypeMismatch) if ffi::lua_type(state, idx) != ffi::LUA_TUSERDATA => {
// Report `FromLuaConversionError` instead // Report `FromLuaConversionError` instead
let idx_type_name = CStr::from_ptr(ffi::luaL_typename(state, idx)); let type_name = CStr::from_ptr(ffi::lua_typename(state, ffi::lua_type(state, idx)))
let idx_type_name = idx_type_name.to_str().unwrap(); .to_str()
.unwrap_or("unknown");
let message = format!("expected userdata of type '{}'", short_type_name::<T>()); let message = format!("expected userdata of type '{}'", short_type_name::<T>());
Err(Error::from_lua_conversion(idx_type_name, "userdata", message)) Err(Error::from_lua_conversion(type_name, "userdata", message))
} }
Err(err) => Err(err), Err(err) => Err(err),
} }
@@ -1279,7 +1304,13 @@ impl RawLua {
#[cfg(feature = "async")] #[cfg(feature = "async")]
pub(crate) fn create_async_callback(&self, func: AsyncCallback) -> Result<Function> { pub(crate) fn create_async_callback(&self, func: AsyncCallback) -> Result<Function> {
// Ensure that the coroutine library is loaded // Ensure that the coroutine library is loaded
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau"))] #[cfg(any(
feature = "lua55",
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luau"
))]
unsafe { unsafe {
if !(*self.extra.get()).libs.contains(StdLib::COROUTINE) { if !(*self.extra.get()).libs.contains(StdLib::COROUTINE) {
load_std_libs(self.main_state(), StdLib::COROUTINE)?; load_std_libs(self.main_state(), StdLib::COROUTINE)?;
@@ -1492,7 +1523,13 @@ unsafe fn load_std_libs(state: *mut ffi::lua_State, libs: StdLib) -> Result<()>
#[cfg(feature = "luajit")] #[cfg(feature = "luajit")]
let _gc_guard = GcGuard::new(state); let _gc_guard = GcGuard::new(state);
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau"))] #[cfg(any(
feature = "lua55",
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luau"
))]
{ {
if libs.contains(StdLib::COROUTINE) { if libs.contains(StdLib::COROUTINE) {
requiref(state, ffi::LUA_COLIBNAME, ffi::luaopen_coroutine, 1)?; requiref(state, ffi::LUA_COLIBNAME, ffi::luaopen_coroutine, 1)?;
@@ -1516,7 +1553,7 @@ unsafe fn load_std_libs(state: *mut ffi::lua_State, libs: StdLib) -> Result<()>
requiref(state, ffi::LUA_STRLIBNAME, ffi::luaopen_string, 1)?; requiref(state, ffi::LUA_STRLIBNAME, ffi::luaopen_string, 1)?;
} }
#[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "luau"))]
{ {
if libs.contains(StdLib::UTF8) { if libs.contains(StdLib::UTF8) {
requiref(state, ffi::LUA_UTF8LIBNAME, ffi::luaopen_utf8, 1)?; requiref(state, ffi::LUA_UTF8LIBNAME, ffi::luaopen_utf8, 1)?;
+2 -2
View File
@@ -1,11 +1,11 @@
use std::os::raw::c_int; use std::os::raw::c_int;
use std::panic::{catch_unwind, AssertUnwindSafe}; use std::panic::{AssertUnwindSafe, catch_unwind};
use std::ptr; use std::ptr;
use std::sync::Arc; use std::sync::Arc;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::state::{ExtraData, RawLua}; use crate::state::{ExtraData, RawLua};
use crate::util::{self, get_internal_metatable, WrappedFailure}; use crate::util::{self, WrappedFailure, get_internal_metatable};
struct StateGuard<'a>(&'a RawLua, *mut ffi::lua_State); struct StateGuard<'a>(&'a RawLua, *mut ffi::lua_State);
+19 -4
View File
@@ -6,10 +6,22 @@ pub struct StdLib(u32);
impl StdLib { impl StdLib {
/// [`coroutine`](https://www.lua.org/manual/5.4/manual.html#6.2) library /// [`coroutine`](https://www.lua.org/manual/5.4/manual.html#6.2) library
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau"))] #[cfg(any(
feature = "lua55",
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luau"
))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau"))) doc(cfg(any(
feature = "lua55",
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luau"
)))
)] )]
pub const COROUTINE: StdLib = StdLib(1); pub const COROUTINE: StdLib = StdLib(1);
@@ -28,8 +40,11 @@ impl StdLib {
pub const STRING: StdLib = StdLib(1 << 4); pub const STRING: StdLib = StdLib(1 << 4);
/// [`utf8`](https://www.lua.org/manual/5.4/manual.html#6.5) library /// [`utf8`](https://www.lua.org/manual/5.4/manual.html#6.5) library
#[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "luau"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))))] #[cfg_attr(
docsrs,
doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "luau")))
)]
pub const UTF8: StdLib = StdLib(1 << 5); pub const UTF8: StdLib = StdLib(1 << 5);
/// [`bit`](https://www.lua.org/manual/5.2/manual.html#6.7) library /// [`bit`](https://www.lua.org/manual/5.2/manual.html#6.7) library
+40 -44
View File
@@ -2,7 +2,6 @@ use std::borrow::{Borrow, Cow};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::ops::Deref; use std::ops::Deref;
use std::os::raw::{c_int, c_void}; use std::os::raw::{c_int, c_void};
use std::string::String as StdString;
use std::{cmp, fmt, slice, str}; use std::{cmp, fmt, slice, str};
use crate::error::{Error, Result}; use crate::error::{Error, Result};
@@ -21,23 +20,23 @@ use {
/// ///
/// Unlike Rust strings, Lua strings may not be valid UTF-8. /// Unlike Rust strings, Lua strings may not be valid UTF-8.
#[derive(Clone)] #[derive(Clone)]
pub struct String(pub(crate) ValueRef); pub struct LuaString(pub(crate) ValueRef);
impl String { impl LuaString {
/// Get a [`BorrowedStr`] if the Lua string is valid UTF-8. /// Get a [`BorrowedStr`] if the Lua string is valid UTF-8.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// # use mlua::{Lua, Result, String}; /// # use mlua::{Lua, LuaString, Result};
/// # fn main() -> Result<()> { /// # fn main() -> Result<()> {
/// # let lua = Lua::new(); /// # let lua = Lua::new();
/// let globals = lua.globals(); /// let globals = lua.globals();
/// ///
/// let version: String = globals.get("_VERSION")?; /// let version: LuaString = globals.get("_VERSION")?;
/// assert!(version.to_str()?.contains("Lua")); /// assert!(version.to_str()?.contains("Lua"));
/// ///
/// let non_utf8: String = lua.load(r#" "test\255" "#).eval()?; /// let non_utf8: LuaString = lua.load(r#" "test\255" "#).eval()?;
/// assert!(non_utf8.to_str().is_err()); /// assert!(non_utf8.to_str().is_err());
/// # Ok(()) /// # Ok(())
/// # } /// # }
@@ -47,11 +46,11 @@ impl String {
BorrowedStr::try_from(self) BorrowedStr::try_from(self)
} }
/// Converts this string to a [`StdString`]. /// Converts this Lua string to a [`String`].
/// ///
/// Any non-Unicode sequences are replaced with [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. /// Any non-Unicode sequences are replaced with [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD].
/// ///
/// This method returns [`StdString`] instead of [`Cow<'_, str>`] because lifetime cannot be /// This method returns [`String`] instead of [`Cow<'_, str>`] because lifetime cannot be
/// bound to a weak Lua object. /// bound to a weak Lua object.
/// ///
/// [U+FFFD]: std::char::REPLACEMENT_CHARACTER /// [U+FFFD]: std::char::REPLACEMENT_CHARACTER
@@ -70,11 +69,11 @@ impl String {
/// # } /// # }
/// ``` /// ```
#[inline] #[inline]
pub fn to_string_lossy(&self) -> StdString { pub fn to_string_lossy(&self) -> String {
StdString::from_utf8_lossy(&self.as_bytes()).into_owned() String::from_utf8_lossy(&self.as_bytes()).into_owned()
} }
/// Returns an object that implements [`Display`] for safely printing a Lua [`String`] that may /// Returns an object that implements [`Display`] for safely printing a [`LuaString`] that may
/// contain non-Unicode data. /// contain non-Unicode data.
/// ///
/// This may perform lossy conversion. /// This may perform lossy conversion.
@@ -92,10 +91,10 @@ impl String {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// # use mlua::{Lua, Result, String}; /// # use mlua::{Lua, LuaString, Result};
/// # fn main() -> Result<()> { /// # fn main() -> Result<()> {
/// # let lua = Lua::new(); /// # let lua = Lua::new();
/// let non_utf8: String = lua.load(r#" "test\255" "#).eval()?; /// let non_utf8: LuaString = lua.load(r#" "test\255" "#).eval()?;
/// assert!(non_utf8.to_str().is_err()); // oh no :( /// assert!(non_utf8.to_str().is_err()); // oh no :(
/// assert_eq!(non_utf8.as_bytes(), &b"test\xff"[..]); /// assert_eq!(non_utf8.as_bytes(), &b"test\xff"[..]);
/// # Ok(()) /// # Ok(())
@@ -135,7 +134,7 @@ impl String {
(slice, lua) (slice, lua)
} }
/// Converts this string to a generic C pointer. /// Converts this Lua string to a generic C pointer.
/// ///
/// There is no way to convert the pointer back to its original value. /// There is no way to convert the pointer back to its original value.
/// ///
@@ -146,7 +145,7 @@ impl String {
} }
} }
impl fmt::Debug for String { impl fmt::Debug for LuaString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let bytes = self.as_bytes(); let bytes = self.as_bytes();
// Check if the string is valid utf8 // Check if the string is valid utf8
@@ -162,12 +161,12 @@ impl fmt::Debug for String {
// Lua strings are basically `&[u8]` slices, so implement `PartialEq` for anything resembling that. // Lua strings are basically `&[u8]` slices, so implement `PartialEq` for anything resembling that.
// //
// This makes our `String` comparable with `Vec<u8>`, `[u8]`, `&str` and `String`. // This makes our `LuaString` comparable with `Vec<u8>`, `[u8]`, `&str` and `String`.
// //
// The only downside is that this disallows a comparison with `Cow<str>`, as that only implements // The only downside is that this disallows a comparison with `Cow<str>`, as that only implements
// `AsRef<str>`, which collides with this impl. Requiring `AsRef<str>` would fix that, but limit us // `AsRef<str>`, which collides with this impl. Requiring `AsRef<str>` would fix that, but limit us
// in other ways. // in other ways.
impl<T> PartialEq<T> for String impl<T> PartialEq<T> for LuaString
where where
T: AsRef<[u8]> + ?Sized, T: AsRef<[u8]> + ?Sized,
{ {
@@ -176,43 +175,43 @@ where
} }
} }
impl PartialEq for String { impl PartialEq for LuaString {
fn eq(&self, other: &String) -> bool { fn eq(&self, other: &LuaString) -> bool {
self.as_bytes() == other.as_bytes() self.as_bytes() == other.as_bytes()
} }
} }
impl Eq for String {} impl Eq for LuaString {}
impl<T> PartialOrd<T> for String impl<T> PartialOrd<T> for LuaString
where where
T: AsRef<[u8]> + ?Sized, T: AsRef<[u8]> + ?Sized,
{ {
fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> { fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
self.as_bytes().partial_cmp(&other.as_ref()) <[u8]>::partial_cmp(&self.as_bytes(), other.as_ref())
} }
} }
impl PartialOrd for String { impl PartialOrd for LuaString {
fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> { fn partial_cmp(&self, other: &LuaString) -> Option<cmp::Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))
} }
} }
impl Ord for String { impl Ord for LuaString {
fn cmp(&self, other: &String) -> cmp::Ordering { fn cmp(&self, other: &LuaString) -> cmp::Ordering {
self.as_bytes().cmp(&other.as_bytes()) self.as_bytes().cmp(&other.as_bytes())
} }
} }
impl Hash for String { impl Hash for LuaString {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
self.as_bytes().hash(state); self.as_bytes().hash(state);
} }
} }
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
impl Serialize for String { impl Serialize for LuaString {
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
where where
S: Serializer, S: Serializer,
@@ -224,7 +223,7 @@ impl Serialize for String {
} }
} }
struct Display<'a>(&'a String); struct Display<'a>(&'a LuaString);
impl fmt::Display for Display<'_> { impl fmt::Display for Display<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -237,7 +236,7 @@ impl fmt::Display for Display<'_> {
pub struct BorrowedStr<'a> { pub struct BorrowedStr<'a> {
// `buf` points to a readonly memory managed by Lua // `buf` points to a readonly memory managed by Lua
pub(crate) buf: &'a str, pub(crate) buf: &'a str,
pub(crate) borrow: Cow<'a, String>, pub(crate) borrow: Cow<'a, LuaString>,
pub(crate) _lua: Lua, pub(crate) _lua: Lua,
} }
@@ -302,17 +301,14 @@ impl Ord for BorrowedStr<'_> {
} }
} }
impl<'a> TryFrom<&'a String> for BorrowedStr<'a> { impl<'a> TryFrom<&'a LuaString> for BorrowedStr<'a> {
type Error = Error; type Error = Error;
#[inline] #[inline]
fn try_from(value: &'a String) -> Result<Self> { fn try_from(value: &'a LuaString) -> Result<Self> {
let BorrowedBytes { buf, borrow, _lua } = BorrowedBytes::from(value); let BorrowedBytes { buf, borrow, _lua } = BorrowedBytes::from(value);
let buf = str::from_utf8(buf).map_err(|e| Error::FromLuaConversionError { let buf =
from: "string", str::from_utf8(buf).map_err(|e| Error::from_lua_conversion("string", "&str", e.to_string()))?;
to: "&str".to_string(),
message: Some(e.to_string()),
})?;
Ok(Self { buf, borrow, _lua }) Ok(Self { buf, borrow, _lua })
} }
} }
@@ -321,7 +317,7 @@ impl<'a> TryFrom<&'a String> for BorrowedStr<'a> {
pub struct BorrowedBytes<'a> { pub struct BorrowedBytes<'a> {
// `buf` points to a readonly memory managed by Lua // `buf` points to a readonly memory managed by Lua
pub(crate) buf: &'a [u8], pub(crate) buf: &'a [u8],
pub(crate) borrow: Cow<'a, String>, pub(crate) borrow: Cow<'a, LuaString>,
pub(crate) _lua: Lua, pub(crate) _lua: Lua,
} }
@@ -389,9 +385,9 @@ impl<'a> IntoIterator for &'a BorrowedBytes<'_> {
} }
} }
impl<'a> From<&'a String> for BorrowedBytes<'a> { impl<'a> From<&'a LuaString> for BorrowedBytes<'a> {
#[inline] #[inline]
fn from(value: &'a String) -> Self { fn from(value: &'a LuaString) -> Self {
let (buf, _lua) = unsafe { value.to_slice() }; let (buf, _lua) = unsafe { value.to_slice() };
let borrow = Cow::Borrowed(value); let borrow = Cow::Borrowed(value);
Self { buf, borrow, _lua } Self { buf, borrow, _lua }
@@ -400,7 +396,7 @@ impl<'a> From<&'a String> for BorrowedBytes<'a> {
struct WrappedString<T: AsRef<[u8]>>(T); struct WrappedString<T: AsRef<[u8]>>(T);
impl String { impl LuaString {
/// Wraps bytes, returning an opaque type that implements [`IntoLua`] trait. /// Wraps bytes, returning an opaque type that implements [`IntoLua`] trait.
/// ///
/// This function uses [`Lua::create_string`] under the hood. /// This function uses [`Lua::create_string`] under the hood.
@@ -415,7 +411,7 @@ impl<T: AsRef<[u8]>> IntoLua for WrappedString<T> {
} }
} }
impl LuaType for String { impl LuaType for LuaString {
const TYPE_ID: c_int = ffi::LUA_TSTRING; const TYPE_ID: c_int = ffi::LUA_TSTRING;
} }
@@ -424,9 +420,9 @@ mod assertions {
use super::*; use super::*;
#[cfg(not(feature = "send"))] #[cfg(not(feature = "send"))]
static_assertions::assert_not_impl_any!(String: Send); static_assertions::assert_not_impl_any!(LuaString: Send);
#[cfg(feature = "send")] #[cfg(feature = "send")]
static_assertions::assert_impl_all!(String: Send, Sync); static_assertions::assert_impl_all!(LuaString: Send, Sync);
#[cfg(feature = "send")] #[cfg(feature = "send")]
static_assertions::assert_impl_all!(BorrowedBytes: Send, Sync); static_assertions::assert_impl_all!(BorrowedBytes: Send, Sync);
#[cfg(feature = "send")] #[cfg(feature = "send")]
+172 -14
View File
@@ -1,15 +1,173 @@
//! Lua table handling.
//!
//! Tables are Lua's primary data structure, used for arrays, dictionaries, objects, modules,
//! and more. This module provides types for creating and manipulating Lua tables from Rust.
//!
//! # Main Types
//!
//! - [`Table`] - A handle to a Lua table.
//! - [`TablePairs`] - An iterator over key-value pairs in a table.
//! - [`TableSequence`] - An iterator over the array (sequence) portion of a table.
//!
//! # Basic Operations
//!
//! Tables support key-value access similar to Rust's `HashMap`:
//!
//! ```
//! # use mlua::{Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//! let table = lua.create_table()?;
//!
//! // Set and get values
//! table.set("key", "value")?;
//! let value: String = table.get("key")?;
//! assert_eq!(value, "value");
//!
//! // Keys and values can be any Lua-compatible type
//! table.set(1, "first")?;
//! table.set("nested", lua.create_table()?)?;
//! # Ok(())
//! # }
//! ```
//!
//! # Array Operations
//!
//! Tables can be used as arrays with 1-based indexing:
//!
//! ```
//! # use mlua::{Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//! let array = lua.create_table()?;
//!
//! // Push values to the end (like Vec::push)
//! array.push("first")?;
//! array.push("second")?;
//! array.push("third")?;
//!
//! // Pop from the end
//! let last: String = array.pop()?;
//! assert_eq!(last, "third");
//!
//! // Get length
//! assert_eq!(array.raw_len(), 2);
//! # Ok(())
//! # }
//! ```
//!
//! # Iteration
//!
//! Iterate over all key-value pairs with [`Table::pairs`]:
//!
//! ```
//! # use mlua::{Lua, Result, Value};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//! let table = lua.create_table()?;
//! table.set("a", 1)?;
//! table.set("b", 2)?;
//!
//! for pair in table.pairs::<String, i32>() {
//! let (key, value) = pair?;
//! println!("{key} = {value}");
//! }
//! # Ok(())
//! # }
//! ```
//!
//! For array portions, use [`Table::sequence_values`]:
//!
//! ```
//! # use mlua::{Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//! let array = lua.create_sequence_from(["a", "b", "c"])?;
//!
//! for value in array.sequence_values::<String>() {
//! println!("{}", value?);
//! }
//! # Ok(())
//! # }
//! ```
//!
//! # Raw vs Normal Access
//!
//! Methods prefixed with `raw_` (like [`Table::raw_get`], [`Table::raw_set`]) bypass
//! metamethods, directly accessing the table's contents. Normal methods may trigger
//! `__index`, `__newindex`, and other metamethods:
//!
//! ```
//! # use mlua::{Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//!
//! // raw_set bypasses __newindex metamethod
//! let t = lua.create_table()?;
//! t.raw_set("key", "value")?;
//!
//! // raw_get bypasses __index metamethod
//! let v: String = t.raw_get("key")?;
//! # Ok(())
//! # }
//! ```
//!
//! # Metatables
//!
//! Tables can have metatables that customize their behavior:
//!
//! ```
//! # use mlua::{Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//!
//! let table = lua.create_table()?;
//! let metatable = lua.create_table()?;
//!
//! // Set a default value via __index
//! metatable.set("__index", lua.create_function(|_, _: ()| Ok("default"))?)?;
//! table.set_metatable(Some(metatable))?;
//!
//! // Accessing missing keys returns "default"
//! let value: String = table.get("missing")?;
//! assert_eq!(value, "default");
//! # Ok(())
//! # }
//! ```
//!
//! # Global Table
//!
//! The Lua global environment is itself a table, accessible via [`Lua::globals`]:
//!
//! ```
//! # use mlua::{Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//! let globals = lua.globals();
//!
//! // Set a global variable
//! globals.set("my_var", 42)?;
//!
//! // Now accessible from Lua code
//! let result: i32 = lua.load("my_var + 8").eval()?;
//! assert_eq!(result, 50);
//! # Ok(())
//! # }
//! ```
//!
//! [`Lua::globals`]: crate::Lua::globals
use std::collections::HashSet; use std::collections::HashSet;
use std::fmt; use std::fmt;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::string::String as StdString;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::function::Function; use crate::function::Function;
use crate::state::{LuaGuard, RawLua, WeakLua}; use crate::state::{LuaGuard, RawLua, WeakLua};
use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, ObjectLike}; use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, ObjectLike};
use crate::types::{Integer, ValueRef}; use crate::types::{Integer, ValueRef};
use crate::util::{assert_stack, check_stack, get_metatable_ptr, StackGuard}; use crate::util::{StackGuard, assert_stack, check_stack, get_metatable_ptr};
use crate::value::{Nil, Value}; use crate::value::{Nil, Value};
#[cfg(feature = "async")] #[cfg(feature = "async")]
@@ -226,15 +384,15 @@ impl Table {
// Compare using `__eq` metamethod if exists // Compare using `__eq` metamethod if exists
// First, check the self for the metamethod. // First, check the self for the metamethod.
// If self does not define it, then check the other table. // If self does not define it, then check the other table.
if let Some(mt) = self.metatable() { if let Some(mt) = self.metatable()
if mt.contains_key("__eq")? { && let Some(eq_func) = mt.get::<Option<Function>>("__eq")?
return mt.get::<Function>("__eq")?.call((self, other)); {
} return eq_func.call((self, other));
} }
if let Some(mt) = other.metatable() { if let Some(mt) = other.metatable()
if mt.contains_key("__eq")? { && let Some(eq_func) = mt.get::<Option<Function>>("__eq")?
return mt.get::<Function>("__eq")?.call((self, other)); {
} return eq_func.call((self, other));
} }
Ok(false) Ok(false)
@@ -1008,7 +1166,7 @@ impl ObjectLike for Table {
} }
#[inline] #[inline]
fn to_string(&self) -> Result<StdString> { fn to_string(&self) -> Result<String> {
Value::Table(Table(self.0.clone())).to_string() Value::Table(Table(self.0.clone())).to_string()
} }
@@ -1070,7 +1228,7 @@ impl Serialize for SerializableTable<'_> {
where where
S: Serializer, S: Serializer,
{ {
use crate::serde::de::{check_value_for_skip, MapPairs, RecursionGuard}; use crate::serde::de::{MapPairs, RecursionGuard, check_value_for_skip};
use crate::value::SerializableValue; use crate::value::SerializableValue;
let convert_result = |res: Result<()>, serialize_err: Option<S::Error>| match res { let convert_result = |res: Result<()>, serialize_err: Option<S::Error>| match res {
@@ -1098,7 +1256,7 @@ impl Serialize for SerializableTable<'_> {
seq.serialize_element(&SerializableValue::new(&value, options, Some(visited))) seq.serialize_element(&SerializableValue::new(&value, options, Some(visited)))
.map_err(|err| { .map_err(|err| {
serialize_err = Some(err); serialize_err = Some(err);
Error::SerializeError(StdString::new()) Error::SerializeError(String::new())
}) })
}); });
convert_result(res, serialize_err)?; convert_result(res, serialize_err)?;
@@ -1123,7 +1281,7 @@ impl Serialize for SerializableTable<'_> {
) )
.map_err(|err| { .map_err(|err| {
serialize_err = Some(err); serialize_err = Some(err);
Error::SerializeError(StdString::new()) Error::SerializeError(String::new())
}) })
}; };
+6 -5
View File
@@ -6,7 +6,7 @@ use crate::function::Function;
use crate::state::RawLua; use crate::state::RawLua;
use crate::traits::{FromLuaMulti, IntoLuaMulti}; use crate::traits::{FromLuaMulti, IntoLuaMulti};
use crate::types::{LuaType, ValueRef}; use crate::types::{LuaType, ValueRef};
use crate::util::{check_stack, error_traceback_thread, pop_error, StackGuard}; use crate::util::{StackGuard, check_stack, error_traceback_thread, pop_error};
#[cfg(not(feature = "luau"))] #[cfg(not(feature = "luau"))]
use crate::{ use crate::{
@@ -336,22 +336,22 @@ impl Thread {
} }
ThreadStatusInner::Running => Err(Error::runtime("cannot reset a running thread")), ThreadStatusInner::Running => Err(Error::runtime("cannot reset a running thread")),
ThreadStatusInner::Finished => Ok(()), ThreadStatusInner::Finished => Ok(()),
#[cfg(not(any(feature = "lua54", feature = "luau")))] #[cfg(not(any(feature = "lua55", feature = "lua54", feature = "luau")))]
ThreadStatusInner::Yielded(_) | ThreadStatusInner::Error => { ThreadStatusInner::Yielded(_) | ThreadStatusInner::Error => {
Err(Error::runtime("cannot reset non-finished thread")) Err(Error::runtime("cannot reset non-finished thread"))
} }
#[cfg(any(feature = "lua54", feature = "luau"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "luau"))]
ThreadStatusInner::Yielded(_) | ThreadStatusInner::Error => { ThreadStatusInner::Yielded(_) | ThreadStatusInner::Error => {
let thread_state = self.state(); let thread_state = self.state();
#[cfg(all(feature = "lua54", not(feature = "vendored")))] #[cfg(all(feature = "lua54", not(feature = "vendored")))]
let status = ffi::lua_resetthread(thread_state); let status = ffi::lua_resetthread(thread_state);
#[cfg(all(feature = "lua54", feature = "vendored"))] #[cfg(any(feature = "lua55", all(feature = "lua54", feature = "vendored")))]
let status = { let status = {
let lua = self.0.lua.lock(); let lua = self.0.lua.lock();
ffi::lua_closethread(thread_state, lua.state()) ffi::lua_closethread(thread_state, lua.state())
}; };
#[cfg(feature = "lua54")] #[cfg(any(feature = "lua55", feature = "lua54"))]
if status != ffi::LUA_OK { if status != ffi::LUA_OK {
return Err(pop_error(thread_state, status)); return Err(pop_error(thread_state, status));
} }
@@ -523,6 +523,7 @@ impl<R> AsyncThread<R> {
#[cfg(feature = "async")] #[cfg(feature = "async")]
impl<R> Drop for AsyncThread<R> { impl<R> Drop for AsyncThread<R> {
fn drop(&mut self) { fn drop(&mut self) {
#[allow(clippy::collapsible_if)]
if self.recycle { if self.recycle {
if let Some(lua) = self.thread.0.lua.try_lock() { if let Some(lua) = self.thread.0.lua.try_lock() {
unsafe { unsafe {
+2 -3
View File
@@ -1,5 +1,4 @@
use std::os::raw::c_int; use std::os::raw::c_int;
use std::string::String as StdString;
use std::sync::Arc; use std::sync::Arc;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
@@ -236,7 +235,7 @@ pub trait ObjectLike: Sealed {
/// Converts the object to a string in a human-readable format. /// Converts the object to a string in a human-readable format.
/// ///
/// This might invoke the `__tostring` metamethod. /// This might invoke the `__tostring` metamethod.
fn to_string(&self) -> Result<StdString>; fn to_string(&self) -> Result<String>;
/// Converts the object to a Lua value. /// Converts the object to a Lua value.
fn to_value(&self) -> Value; fn to_value(&self) -> Value;
@@ -339,7 +338,7 @@ impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
pub(crate) trait ShortTypeName { pub(crate) trait ShortTypeName {
#[inline(always)] #[inline(always)]
fn type_name() -> StdString { fn type_name() -> String {
short_type_name::<Self>() short_type_name::<Self>()
} }
} }
+4 -2
View File
@@ -108,10 +108,12 @@ pub(crate) type ThreadCollectionCallback = XRc<dyn Fn(crate::LightUserData) + Se
#[cfg(all(not(feature = "send"), feature = "luau"))] #[cfg(all(not(feature = "send"), feature = "luau"))]
pub(crate) type ThreadCollectionCallback = XRc<dyn Fn(crate::LightUserData)>; pub(crate) type ThreadCollectionCallback = XRc<dyn Fn(crate::LightUserData)>;
#[cfg(all(feature = "send", feature = "lua54"))] #[cfg(feature = "send")]
#[cfg(any(feature = "lua55", feature = "lua54"))]
pub(crate) type WarnCallback = XRc<dyn Fn(&Lua, &str, bool) -> Result<()> + Send>; pub(crate) type WarnCallback = XRc<dyn Fn(&Lua, &str, bool) -> Result<()> + Send>;
#[cfg(all(not(feature = "send"), feature = "lua54"))] #[cfg(not(feature = "send"))]
#[cfg(any(feature = "lua55", feature = "lua54"))]
pub(crate) type WarnCallback = XRc<dyn Fn(&Lua, &str, bool) -> Result<()>>; pub(crate) type WarnCallback = XRc<dyn Fn(&Lua, &str, bool) -> Result<()>>;
/// A trait that adds `Send` requirement if `send` feature is enabled. /// A trait that adds `Send` requirement if `send` feature is enabled.
+1 -1
View File
@@ -69,7 +69,7 @@ mod inner {
#[inline(always)] #[inline(always)]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 .0 &self.0.0
} }
} }
} }
+4 -4
View File
@@ -55,10 +55,10 @@ impl Drop for ValueRef {
if let Some(ValueRefIndex(index)) = self.index_count.take() { if let Some(ValueRefIndex(index)) = self.index_count.take() {
// It's guaranteed that the inner value returns exactly once. // It's guaranteed that the inner value returns exactly once.
// This means in particular that the value is not dropped. // This means in particular that the value is not dropped.
if XRc::into_inner(index).is_some() { if XRc::into_inner(index).is_some()
if let Some(lua) = self.lua.try_lock() { && let Some(lua) = self.lua.try_lock()
unsafe { lua.drop_ref(self) }; {
} unsafe { lua.drop_ref(self) }
} }
} }
} }
+107 -61
View File
@@ -3,16 +3,15 @@ use std::ffi::CStr;
use std::fmt; use std::fmt;
use std::hash::Hash; use std::hash::Hash;
use std::os::raw::{c_char, c_void}; use std::os::raw::{c_char, c_void};
use std::string::String as StdString;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::function::Function; use crate::function::Function;
use crate::state::Lua; use crate::state::Lua;
use crate::string::String; use crate::string::LuaString;
use crate::table::{Table, TablePairs}; use crate::table::{Table, TablePairs};
use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti}; use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti};
use crate::types::{MaybeSend, ValueRef}; use crate::types::{MaybeSend, ValueRef};
use crate::util::{check_stack, get_userdata, push_string, short_type_name, take_userdata, StackGuard}; use crate::util::{StackGuard, check_stack, get_userdata, push_string, short_type_name, take_userdata};
use crate::value::Value; use crate::value::Value;
#[cfg(feature = "async")] #[cfg(feature = "async")]
@@ -30,8 +29,8 @@ pub use r#ref::{UserDataRef, UserDataRefMut};
pub use registry::UserDataRegistry; pub use registry::UserDataRegistry;
pub(crate) use registry::{RawUserDataRegistry, UserDataProxy}; pub(crate) use registry::{RawUserDataRegistry, UserDataProxy};
pub(crate) use util::{ pub(crate) use util::{
borrow_userdata_scoped, borrow_userdata_scoped_mut, collect_userdata, init_userdata_metatable, TypeIdHints, borrow_userdata_scoped, borrow_userdata_scoped_mut, collect_userdata,
TypeIdHints, init_userdata_metatable,
}; };
/// Kinds of metamethods that can be overridden. /// Kinds of metamethods that can be overridden.
@@ -56,32 +55,53 @@ pub enum MetaMethod {
/// The unary minus (`-`) operator. /// The unary minus (`-`) operator.
Unm, Unm,
/// The floor division (//) operator. /// The floor division (//) operator.
#[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "luau"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))))] #[cfg_attr(
docsrs,
doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "luau")))
)]
IDiv, IDiv,
/// The bitwise AND (&) operator. /// The bitwise AND (&) operator.
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53"))))] #[cfg_attr(
docsrs,
doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53")))
)]
BAnd, BAnd,
/// The bitwise OR (|) operator. /// The bitwise OR (|) operator.
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53"))))] #[cfg_attr(
docsrs,
doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53")))
)]
BOr, BOr,
/// The bitwise XOR (binary ~) operator. /// The bitwise XOR (binary ~) operator.
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53"))))] #[cfg_attr(
docsrs,
doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53")))
)]
BXor, BXor,
/// The bitwise NOT (unary ~) operator. /// The bitwise NOT (unary ~) operator.
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53"))))] #[cfg_attr(
docsrs,
doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53")))
)]
BNot, BNot,
/// The bitwise left shift (<<) operator. /// The bitwise left shift (<<) operator.
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53"))))] #[cfg_attr(
docsrs,
doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53")))
)]
Shl, Shl,
/// The bitwise right shift (>>) operator. /// The bitwise right shift (>>) operator.
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "lua53"))))] #[cfg_attr(
docsrs,
doc(cfg(any(feature = "lua55", feature = "lua54", feature = "lua53")))
)]
Shr, Shr,
/// The string concatenation operator `..`. /// The string concatenation operator `..`.
Concat, Concat,
@@ -106,10 +126,22 @@ pub enum MetaMethod {
/// The `__pairs` metamethod. /// The `__pairs` metamethod.
/// ///
/// This is not an operator, but it will be called by the built-in `pairs` function. /// This is not an operator, but it will be called by the built-in `pairs` function.
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luajit52"))] #[cfg(any(
feature = "lua55",
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luajit52"
))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luajit52"))) doc(cfg(any(
feature = "lua55",
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luajit52"
)))
)] )]
Pairs, Pairs,
/// The `__ipairs` metamethod. /// The `__ipairs` metamethod.
@@ -135,8 +167,8 @@ pub enum MetaMethod {
/// [documentation][lua_doc]. /// [documentation][lua_doc].
/// ///
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#3.3.8 /// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#3.3.8
#[cfg(feature = "lua54")] #[cfg(any(feature = "lua55", feature = "lua54"))]
#[cfg_attr(docsrs, doc(cfg(feature = "lua54")))] #[cfg_attr(docsrs, doc(cfg(any(feature = "lua55", feature = "lua54"))))]
Close, Close,
/// The `__name`/`__type` metafield. /// The `__name`/`__type` metafield.
/// ///
@@ -152,7 +184,7 @@ impl PartialEq<MetaMethod> for &str {
} }
} }
impl PartialEq<MetaMethod> for StdString { impl PartialEq<MetaMethod> for String {
fn eq(&self, other: &MetaMethod) -> bool { fn eq(&self, other: &MetaMethod) -> bool {
self == other.name() self == other.name()
} }
@@ -176,19 +208,19 @@ impl MetaMethod {
MetaMethod::Pow => "__pow", MetaMethod::Pow => "__pow",
MetaMethod::Unm => "__unm", MetaMethod::Unm => "__unm",
#[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "luau"))]
MetaMethod::IDiv => "__idiv", MetaMethod::IDiv => "__idiv",
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
MetaMethod::BAnd => "__band", MetaMethod::BAnd => "__band",
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
MetaMethod::BOr => "__bor", MetaMethod::BOr => "__bor",
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
MetaMethod::BXor => "__bxor", MetaMethod::BXor => "__bxor",
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
MetaMethod::BNot => "__bnot", MetaMethod::BNot => "__bnot",
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
MetaMethod::Shl => "__shl", MetaMethod::Shl => "__shl",
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
MetaMethod::Shr => "__shr", MetaMethod::Shr => "__shr",
MetaMethod::Concat => "__concat", MetaMethod::Concat => "__concat",
@@ -201,14 +233,20 @@ impl MetaMethod {
MetaMethod::Call => "__call", MetaMethod::Call => "__call",
MetaMethod::ToString => "__tostring", MetaMethod::ToString => "__tostring",
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luajit52"))] #[cfg(any(
feature = "lua55",
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luajit52"
))]
MetaMethod::Pairs => "__pairs", MetaMethod::Pairs => "__pairs",
#[cfg(any(feature = "lua52", feature = "luajit52"))] #[cfg(any(feature = "lua52", feature = "luajit52"))]
MetaMethod::IPairs => "__ipairs", MetaMethod::IPairs => "__ipairs",
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
MetaMethod::Iter => "__iter", MetaMethod::Iter => "__iter",
#[cfg(feature = "lua54")] #[cfg(any(feature = "lua55", feature = "lua54"))]
MetaMethod::Close => "__close", MetaMethod::Close => "__close",
#[rustfmt::skip] #[rustfmt::skip]
@@ -240,7 +278,7 @@ impl AsRef<str> for MetaMethod {
} }
} }
impl From<MetaMethod> for StdString { impl From<MetaMethod> for String {
#[inline] #[inline]
fn from(method: MetaMethod) -> Self { fn from(method: MetaMethod) -> Self {
method.name().to_owned() method.name().to_owned()
@@ -256,7 +294,7 @@ pub trait UserDataMethods<T> {
/// ///
/// If `add_meta_method` is used to set the `__index` metamethod, the `__index` metamethod will /// If `add_meta_method` is used to set the `__index` metamethod, the `__index` metamethod will
/// be used as a fall-back if no regular method is found. /// be used as a fall-back if no regular method is found.
fn add_method<M, A, R>(&mut self, name: impl Into<StdString>, method: M) fn add_method<M, A, R>(&mut self, name: impl Into<String>, method: M)
where where
M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static, M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -267,7 +305,7 @@ pub trait UserDataMethods<T> {
/// Refer to [`add_method`] for more information about the implementation. /// Refer to [`add_method`] for more information about the implementation.
/// ///
/// [`add_method`]: UserDataMethods::add_method /// [`add_method`]: UserDataMethods::add_method
fn add_method_mut<M, A, R>(&mut self, name: impl Into<StdString>, method: M) fn add_method_mut<M, A, R>(&mut self, name: impl Into<String>, method: M)
where where
M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -281,7 +319,7 @@ pub trait UserDataMethods<T> {
/// The method can be called only once per userdata instance, subsequent calls will result in a /// The method can be called only once per userdata instance, subsequent calls will result in a
/// [`Error::UserDataDestructed`] error. /// [`Error::UserDataDestructed`] error.
#[doc(hidden)] #[doc(hidden)]
fn add_method_once<M, A, R>(&mut self, name: impl Into<StdString>, method: M) fn add_method_once<M, A, R>(&mut self, name: impl Into<String>, method: M)
where where
T: 'static, T: 'static,
M: Fn(&Lua, T, A) -> Result<R> + MaybeSend + 'static, M: Fn(&Lua, T, A) -> Result<R> + MaybeSend + 'static,
@@ -303,7 +341,7 @@ pub trait UserDataMethods<T> {
/// [`add_method`]: UserDataMethods::add_method /// [`add_method`]: UserDataMethods::add_method
#[cfg(feature = "async")] #[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))] #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_method<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M) fn add_async_method<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where where
T: 'static, T: 'static,
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static, M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
@@ -318,7 +356,7 @@ pub trait UserDataMethods<T> {
/// [`add_method`]: UserDataMethods::add_method /// [`add_method`]: UserDataMethods::add_method
#[cfg(feature = "async")] #[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))] #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M) fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where where
T: 'static, T: 'static,
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static, M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
@@ -336,7 +374,7 @@ pub trait UserDataMethods<T> {
#[cfg(feature = "async")] #[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))] #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
#[doc(hidden)] #[doc(hidden)]
fn add_async_method_once<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M) fn add_async_method_once<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where where
T: 'static, T: 'static,
M: Fn(Lua, T, A) -> MR + MaybeSend + 'static, M: Fn(Lua, T, A) -> MR + MaybeSend + 'static,
@@ -359,7 +397,7 @@ pub trait UserDataMethods<T> {
/// The first argument will be a [`AnyUserData`] of type `T` if the method is called with Lua /// The first argument will be a [`AnyUserData`] of type `T` if the method is called with Lua
/// method syntax: `my_userdata:my_method(arg1, arg2)`, or it is passed in as the first /// method syntax: `my_userdata:my_method(arg1, arg2)`, or it is passed in as the first
/// argument: `my_userdata.my_method(my_userdata, arg1, arg2)`. /// argument: `my_userdata.my_method(my_userdata, arg1, arg2)`.
fn add_function<F, A, R>(&mut self, name: impl Into<StdString>, function: F) fn add_function<F, A, R>(&mut self, name: impl Into<String>, function: F)
where where
F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static, F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -370,7 +408,7 @@ pub trait UserDataMethods<T> {
/// This is a version of [`add_function`] that accepts a `FnMut` argument. /// This is a version of [`add_function`] that accepts a `FnMut` argument.
/// ///
/// [`add_function`]: UserDataMethods::add_function /// [`add_function`]: UserDataMethods::add_function
fn add_function_mut<F, A, R>(&mut self, name: impl Into<StdString>, function: F) fn add_function_mut<F, A, R>(&mut self, name: impl Into<String>, function: F)
where where
F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static, F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -384,7 +422,7 @@ pub trait UserDataMethods<T> {
/// [`add_function`]: UserDataMethods::add_function /// [`add_function`]: UserDataMethods::add_function
#[cfg(feature = "async")] #[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))] #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_function<F, A, FR, R>(&mut self, name: impl Into<StdString>, function: F) fn add_async_function<F, A, FR, R>(&mut self, name: impl Into<String>, function: F)
where where
F: Fn(Lua, A) -> FR + MaybeSend + 'static, F: Fn(Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -399,7 +437,7 @@ pub trait UserDataMethods<T> {
/// side has a metatable. To prevent this, use [`add_meta_function`]. /// side has a metatable. To prevent this, use [`add_meta_function`].
/// ///
/// [`add_meta_function`]: UserDataMethods::add_meta_function /// [`add_meta_function`]: UserDataMethods::add_meta_function
fn add_meta_method<M, A, R>(&mut self, name: impl Into<StdString>, method: M) fn add_meta_method<M, A, R>(&mut self, name: impl Into<String>, method: M)
where where
M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static, M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -413,7 +451,7 @@ pub trait UserDataMethods<T> {
/// side has a metatable. To prevent this, use [`add_meta_function`]. /// side has a metatable. To prevent this, use [`add_meta_function`].
/// ///
/// [`add_meta_function`]: UserDataMethods::add_meta_function /// [`add_meta_function`]: UserDataMethods::add_meta_function
fn add_meta_method_mut<M, A, R>(&mut self, name: impl Into<StdString>, method: M) fn add_meta_method_mut<M, A, R>(&mut self, name: impl Into<String>, method: M)
where where
M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -429,7 +467,7 @@ pub trait UserDataMethods<T> {
docsrs, docsrs,
doc(cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))) doc(cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau")))))
)] )]
fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M) fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where where
T: 'static, T: 'static,
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static, M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
@@ -445,7 +483,7 @@ pub trait UserDataMethods<T> {
/// [`add_meta_method_mut`]: UserDataMethods::add_meta_method_mut /// [`add_meta_method_mut`]: UserDataMethods::add_meta_method_mut
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))] #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_meta_method_mut<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M) fn add_async_meta_method_mut<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where where
T: 'static, T: 'static,
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static, M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
@@ -458,7 +496,7 @@ pub trait UserDataMethods<T> {
/// Metamethods for binary operators can be triggered if either the left or right argument to /// Metamethods for binary operators can be triggered if either the left or right argument to
/// the binary operator has a metatable, so the first argument here is not necessarily a /// the binary operator has a metatable, so the first argument here is not necessarily a
/// userdata of type `T`. /// userdata of type `T`.
fn add_meta_function<F, A, R>(&mut self, name: impl Into<StdString>, function: F) fn add_meta_function<F, A, R>(&mut self, name: impl Into<String>, function: F)
where where
F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static, F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -469,7 +507,7 @@ pub trait UserDataMethods<T> {
/// This is a version of [`add_meta_function`] that accepts a `FnMut` argument. /// This is a version of [`add_meta_function`] that accepts a `FnMut` argument.
/// ///
/// [`add_meta_function`]: UserDataMethods::add_meta_function /// [`add_meta_function`]: UserDataMethods::add_meta_function
fn add_meta_function_mut<F, A, R>(&mut self, name: impl Into<StdString>, function: F) fn add_meta_function_mut<F, A, R>(&mut self, name: impl Into<String>, function: F)
where where
F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static, F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -485,7 +523,7 @@ pub trait UserDataMethods<T> {
docsrs, docsrs,
doc(cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))) doc(cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau")))))
)] )]
fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl Into<StdString>, function: F) fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl Into<String>, function: F)
where where
F: Fn(Lua, A) -> FR + MaybeSend + 'static, F: Fn(Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -504,7 +542,7 @@ pub trait UserDataFields<T> {
/// ///
/// If `add_meta_method` is used to set the `__index` metamethod, it will /// If `add_meta_method` is used to set the `__index` metamethod, it will
/// be used as a fall-back if no regular field or method are found. /// be used as a fall-back if no regular field or method are found.
fn add_field<V>(&mut self, name: impl Into<StdString>, value: V) fn add_field<V>(&mut self, name: impl Into<String>, value: V)
where where
V: IntoLua + 'static; V: IntoLua + 'static;
@@ -515,7 +553,7 @@ pub trait UserDataFields<T> {
/// ///
/// If `add_meta_method` is used to set the `__index` metamethod, the `__index` metamethod will /// If `add_meta_method` is used to set the `__index` metamethod, the `__index` metamethod will
/// be used as a fall-back if no regular field or method are found. /// be used as a fall-back if no regular field or method are found.
fn add_field_method_get<M, R>(&mut self, name: impl Into<StdString>, method: M) fn add_field_method_get<M, R>(&mut self, name: impl Into<String>, method: M)
where where
M: Fn(&Lua, &T) -> Result<R> + MaybeSend + 'static, M: Fn(&Lua, &T) -> Result<R> + MaybeSend + 'static,
R: IntoLua; R: IntoLua;
@@ -528,21 +566,21 @@ pub trait UserDataFields<T> {
/// ///
/// If `add_meta_method` is used to set the `__newindex` metamethod, the `__newindex` metamethod /// If `add_meta_method` is used to set the `__newindex` metamethod, the `__newindex` metamethod
/// will be used as a fall-back if no regular field is found. /// will be used as a fall-back if no regular field is found.
fn add_field_method_set<M, A>(&mut self, name: impl Into<StdString>, method: M) fn add_field_method_set<M, A>(&mut self, name: impl Into<String>, method: M)
where where
M: FnMut(&Lua, &mut T, A) -> Result<()> + MaybeSend + 'static, M: FnMut(&Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
A: FromLua; A: FromLua;
/// Add a regular field getter as a function which accepts a generic [`AnyUserData`] of type `T` /// Add a regular field getter as a function which accepts a generic [`AnyUserData`] of type `T`
/// argument. /// argument.
fn add_field_function_get<F, R>(&mut self, name: impl Into<StdString>, function: F) fn add_field_function_get<F, R>(&mut self, name: impl Into<String>, function: F)
where where
F: Fn(&Lua, AnyUserData) -> Result<R> + MaybeSend + 'static, F: Fn(&Lua, AnyUserData) -> Result<R> + MaybeSend + 'static,
R: IntoLua; R: IntoLua;
/// Add a regular field setter as a function which accepts a generic [`AnyUserData`] of type `T` /// Add a regular field setter as a function which accepts a generic [`AnyUserData`] of type `T`
/// first argument. /// first argument.
fn add_field_function_set<F, A>(&mut self, name: impl Into<StdString>, function: F) fn add_field_function_set<F, A>(&mut self, name: impl Into<String>, function: F)
where where
F: FnMut(&Lua, AnyUserData, A) -> Result<()> + MaybeSend + 'static, F: FnMut(&Lua, AnyUserData, A) -> Result<()> + MaybeSend + 'static,
A: FromLua; A: FromLua;
@@ -555,7 +593,7 @@ pub trait UserDataFields<T> {
/// ///
/// `mlua` will trigger an error on an attempt to define a protected metamethod, /// `mlua` will trigger an error on an attempt to define a protected metamethod,
/// like `__gc` or `__metatable`. /// like `__gc` or `__metatable`.
fn add_meta_field<V>(&mut self, name: impl Into<StdString>, value: V) fn add_meta_field<V>(&mut self, name: impl Into<String>, value: V)
where where
V: IntoLua + 'static; V: IntoLua + 'static;
@@ -567,7 +605,7 @@ pub trait UserDataFields<T> {
/// ///
/// `mlua` will trigger an error on an attempt to define a protected metamethod, /// `mlua` will trigger an error on an attempt to define a protected metamethod,
/// like `__gc` or `__metatable`. /// like `__gc` or `__metatable`.
fn add_meta_field_with<F, R>(&mut self, name: impl Into<StdString>, f: F) fn add_meta_field_with<F, R>(&mut self, name: impl Into<String>, f: F)
where where
F: FnOnce(&Lua) -> Result<R> + 'static, F: FnOnce(&Lua) -> Result<R> + 'static,
R: IntoLua; R: IntoLua;
@@ -679,6 +717,14 @@ impl AnyUserData {
matches!(type_id, Some(type_id) if type_id == TypeId::of::<T>()) matches!(type_id, Some(type_id) if type_id == TypeId::of::<T>())
} }
/// Checks whether the type of this userdata is a [proxy object] for `T`.
///
/// [proxy object]: crate::Lua::create_proxy
#[inline]
pub fn is_proxy<T: 'static>(&self) -> bool {
self.is::<UserDataProxy<T>>()
}
/// Borrow this userdata immutably if it is of type `T`. /// Borrow this userdata immutably if it is of type `T`.
/// ///
/// # Errors /// # Errors
@@ -975,7 +1021,7 @@ impl AnyUserData {
/// Returns a type name of this userdata (from a metatable field). /// Returns a type name of this userdata (from a metatable field).
/// ///
/// If no type name is set, returns `None`. /// If no type name is set, returns `None`.
pub fn type_name(&self) -> Result<Option<StdString>> { pub fn type_name(&self) -> Result<Option<String>> {
let lua = self.0.lua.lock(); let lua = self.0.lua.lock();
let state = lua.state(); let state = lua.state();
unsafe { unsafe {
@@ -992,7 +1038,7 @@ impl AnyUserData {
ffi::luaL_getmetafield(state, -1, MetaMethod::Type.as_cstr().as_ptr()) ffi::luaL_getmetafield(state, -1, MetaMethod::Type.as_cstr().as_ptr())
}; };
match name_type { match name_type {
ffi::LUA_TSTRING => Ok(Some(String(lua.pop_ref()).to_str()?.to_owned())), ffi::LUA_TSTRING => Ok(Some(LuaString(lua.pop_ref()).to_str()?.to_owned())),
_ => Ok(None), _ => Ok(None),
} }
} }
@@ -1079,13 +1125,13 @@ impl UserDataMetatable {
/// It skips restricted metamethods, such as `__gc` or `__metatable`. /// It skips restricted metamethods, such as `__gc` or `__metatable`.
/// ///
/// This struct is created by the [`UserDataMetatable::pairs`] method. /// This struct is created by the [`UserDataMetatable::pairs`] method.
pub struct UserDataMetatablePairs<'a, V>(TablePairs<'a, StdString, V>); pub struct UserDataMetatablePairs<'a, V>(TablePairs<'a, String, V>);
impl<V> Iterator for UserDataMetatablePairs<'_, V> impl<V> Iterator for UserDataMetatablePairs<'_, V>
where where
V: FromLua, V: FromLua,
{ {
type Item = Result<(StdString, V)>; type Item = Result<(String, V)>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
+4 -4
View File
@@ -173,10 +173,10 @@ pub(crate) enum ScopedUserDataVariant<T> {
impl<T> Drop for ScopedUserDataVariant<T> { impl<T> Drop for ScopedUserDataVariant<T> {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
if let Self::Boxed(value) = self { if let Self::Boxed(value) = self
if let Ok(value) = value.try_borrow_mut() { && let Ok(value) = value.try_borrow_mut()
unsafe { drop(Box::from_raw(*value)) }; {
} unsafe { drop(Box::from_raw(*value)) }
} }
} }
} }
+2 -4
View File
@@ -1,12 +1,10 @@
use std::string::String as StdString; use crate::Function;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::state::WeakLua; use crate::state::WeakLua;
use crate::table::Table; use crate::table::Table;
use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, ObjectLike}; use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, ObjectLike};
use crate::userdata::AnyUserData; use crate::userdata::AnyUserData;
use crate::value::Value; use crate::value::Value;
use crate::Function;
#[cfg(feature = "async")] #[cfg(feature = "async")]
use crate::function::AsyncCallFuture; use crate::function::AsyncCallFuture;
@@ -88,7 +86,7 @@ impl ObjectLike for AnyUserData {
} }
#[inline] #[inline]
fn to_string(&self) -> Result<StdString> { fn to_string(&self) -> Result<String> {
Value::UserData(self.clone()).to_string() Value::UserData(self.clone()).to_string()
} }
+6 -6
View File
@@ -1,4 +1,4 @@
use std::any::{type_name, TypeId}; use std::any::{TypeId, type_name};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::os::raw::c_int; use std::os::raw::c_int;
use std::{fmt, mem}; use std::{fmt, mem};
@@ -446,11 +446,11 @@ impl<T> DerefMut for UserDataRefMutInner<T> {
fn try_value_to_userdata<T>(value: Value) -> Result<AnyUserData> { fn try_value_to_userdata<T>(value: Value) -> Result<AnyUserData> {
match value { match value {
Value::UserData(ud) => Ok(ud), Value::UserData(ud) => Ok(ud),
_ => Err(Error::FromLuaConversionError { _ => Err(Error::from_lua_conversion(
from: value.type_name(), value.type_name(),
to: "userdata".to_string(), "userdata",
message: Some(format!("expected userdata of type {}", type_name::<T>())), format!("expected userdata of type {}", type_name::<T>()),
}), )),
} }
} }
+26 -27
View File
@@ -4,15 +4,14 @@ use std::any::TypeId;
use std::cell::RefCell; use std::cell::RefCell;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::string::String as StdString;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::state::{Lua, LuaGuard}; use crate::state::{Lua, LuaGuard};
use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti}; use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti};
use crate::types::{Callback, MaybeSend}; use crate::types::{Callback, MaybeSend};
use crate::userdata::{ use crate::userdata::{
borrow_userdata_scoped, borrow_userdata_scoped_mut, AnyUserData, MetaMethod, TypeIdHints, UserData, AnyUserData, MetaMethod, TypeIdHints, UserData, UserDataFields, UserDataMethods, UserDataStorage,
UserDataFields, UserDataMethods, UserDataStorage, borrow_userdata_scoped, borrow_userdata_scoped_mut,
}; };
use crate::util::short_type_name; use crate::util::short_type_name;
use crate::value::Value; use crate::value::Value;
@@ -55,7 +54,7 @@ pub(crate) struct RawUserDataRegistry {
pub(crate) destructor: ffi::lua_CFunction, pub(crate) destructor: ffi::lua_CFunction,
pub(crate) type_id: Option<TypeId>, pub(crate) type_id: Option<TypeId>,
pub(crate) type_name: StdString, pub(crate) type_name: String,
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
pub(crate) enable_namecall: bool, pub(crate) enable_namecall: bool,
@@ -368,7 +367,7 @@ impl<T> UserDataRegistry<T> {
method: name.to_string(), method: name.to_string(),
type_name: value.type_name(), type_name: value.type_name(),
message: Some("expected nil, table or function".to_string()), message: Some("expected nil, table or function".to_string()),
}) });
} }
} }
} }
@@ -382,12 +381,12 @@ impl<T> UserDataRegistry<T> {
} }
// Returns function name for the type `T`, without the module path // Returns function name for the type `T`, without the module path
fn get_function_name<T>(name: &str) -> StdString { fn get_function_name<T>(name: &str) -> String {
format!("{}.{name}", short_type_name::<T>()) format!("{}.{name}", short_type_name::<T>())
} }
impl<T> UserDataFields<T> for UserDataRegistry<T> { impl<T> UserDataFields<T> for UserDataRegistry<T> {
fn add_field<V>(&mut self, name: impl Into<StdString>, value: V) fn add_field<V>(&mut self, name: impl Into<String>, value: V)
where where
V: IntoLua + 'static, V: IntoLua + 'static,
{ {
@@ -395,7 +394,7 @@ impl<T> UserDataFields<T> for UserDataRegistry<T> {
self.raw.fields.push((name, value.into_lua(self.lua.lua()))); self.raw.fields.push((name, value.into_lua(self.lua.lua())));
} }
fn add_field_method_get<M, R>(&mut self, name: impl Into<StdString>, method: M) fn add_field_method_get<M, R>(&mut self, name: impl Into<String>, method: M)
where where
M: Fn(&Lua, &T) -> Result<R> + MaybeSend + 'static, M: Fn(&Lua, &T) -> Result<R> + MaybeSend + 'static,
R: IntoLua, R: IntoLua,
@@ -405,7 +404,7 @@ impl<T> UserDataFields<T> for UserDataRegistry<T> {
self.raw.field_getters.push((name, callback)); self.raw.field_getters.push((name, callback));
} }
fn add_field_method_set<M, A>(&mut self, name: impl Into<StdString>, method: M) fn add_field_method_set<M, A>(&mut self, name: impl Into<String>, method: M)
where where
M: FnMut(&Lua, &mut T, A) -> Result<()> + MaybeSend + 'static, M: FnMut(&Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
A: FromLua, A: FromLua,
@@ -415,7 +414,7 @@ impl<T> UserDataFields<T> for UserDataRegistry<T> {
self.raw.field_setters.push((name, callback)); self.raw.field_setters.push((name, callback));
} }
fn add_field_function_get<F, R>(&mut self, name: impl Into<StdString>, function: F) fn add_field_function_get<F, R>(&mut self, name: impl Into<String>, function: F)
where where
F: Fn(&Lua, AnyUserData) -> Result<R> + MaybeSend + 'static, F: Fn(&Lua, AnyUserData) -> Result<R> + MaybeSend + 'static,
R: IntoLua, R: IntoLua,
@@ -425,7 +424,7 @@ impl<T> UserDataFields<T> for UserDataRegistry<T> {
self.raw.field_getters.push((name, callback)); self.raw.field_getters.push((name, callback));
} }
fn add_field_function_set<F, A>(&mut self, name: impl Into<StdString>, mut function: F) fn add_field_function_set<F, A>(&mut self, name: impl Into<String>, mut function: F)
where where
F: FnMut(&Lua, AnyUserData, A) -> Result<()> + MaybeSend + 'static, F: FnMut(&Lua, AnyUserData, A) -> Result<()> + MaybeSend + 'static,
A: FromLua, A: FromLua,
@@ -435,7 +434,7 @@ impl<T> UserDataFields<T> for UserDataRegistry<T> {
self.raw.field_setters.push((name, callback)); self.raw.field_setters.push((name, callback));
} }
fn add_meta_field<V>(&mut self, name: impl Into<StdString>, value: V) fn add_meta_field<V>(&mut self, name: impl Into<String>, value: V)
where where
V: IntoLua + 'static, V: IntoLua + 'static,
{ {
@@ -445,7 +444,7 @@ impl<T> UserDataFields<T> for UserDataRegistry<T> {
self.raw.meta_fields.push((name, field)); self.raw.meta_fields.push((name, field));
} }
fn add_meta_field_with<F, R>(&mut self, name: impl Into<StdString>, f: F) fn add_meta_field_with<F, R>(&mut self, name: impl Into<String>, f: F)
where where
F: FnOnce(&Lua) -> Result<R> + 'static, F: FnOnce(&Lua) -> Result<R> + 'static,
R: IntoLua, R: IntoLua,
@@ -458,7 +457,7 @@ impl<T> UserDataFields<T> for UserDataRegistry<T> {
} }
impl<T> UserDataMethods<T> for UserDataRegistry<T> { impl<T> UserDataMethods<T> for UserDataRegistry<T> {
fn add_method<M, A, R>(&mut self, name: impl Into<StdString>, method: M) fn add_method<M, A, R>(&mut self, name: impl Into<String>, method: M)
where where
M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static, M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -469,7 +468,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
self.raw.methods.push((name, callback)); self.raw.methods.push((name, callback));
} }
fn add_method_mut<M, A, R>(&mut self, name: impl Into<StdString>, method: M) fn add_method_mut<M, A, R>(&mut self, name: impl Into<String>, method: M)
where where
M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -481,7 +480,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
} }
#[cfg(feature = "async")] #[cfg(feature = "async")]
fn add_async_method<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M) fn add_async_method<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where where
T: 'static, T: 'static,
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static, M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
@@ -495,7 +494,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
} }
#[cfg(feature = "async")] #[cfg(feature = "async")]
fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M) fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where where
T: 'static, T: 'static,
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static, M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
@@ -508,7 +507,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
self.raw.async_methods.push((name, callback)); self.raw.async_methods.push((name, callback));
} }
fn add_function<F, A, R>(&mut self, name: impl Into<StdString>, function: F) fn add_function<F, A, R>(&mut self, name: impl Into<String>, function: F)
where where
F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static, F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -519,7 +518,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
self.raw.methods.push((name, callback)); self.raw.methods.push((name, callback));
} }
fn add_function_mut<F, A, R>(&mut self, name: impl Into<StdString>, function: F) fn add_function_mut<F, A, R>(&mut self, name: impl Into<String>, function: F)
where where
F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static, F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -531,7 +530,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
} }
#[cfg(feature = "async")] #[cfg(feature = "async")]
fn add_async_function<F, A, FR, R>(&mut self, name: impl Into<StdString>, function: F) fn add_async_function<F, A, FR, R>(&mut self, name: impl Into<String>, function: F)
where where
F: Fn(Lua, A) -> FR + MaybeSend + 'static, F: Fn(Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -543,7 +542,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
self.raw.async_methods.push((name, callback)); self.raw.async_methods.push((name, callback));
} }
fn add_meta_method<M, A, R>(&mut self, name: impl Into<StdString>, method: M) fn add_meta_method<M, A, R>(&mut self, name: impl Into<String>, method: M)
where where
M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static, M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -554,7 +553,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
self.raw.meta_methods.push((name, callback)); self.raw.meta_methods.push((name, callback));
} }
fn add_meta_method_mut<M, A, R>(&mut self, name: impl Into<StdString>, method: M) fn add_meta_method_mut<M, A, R>(&mut self, name: impl Into<String>, method: M)
where where
M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -566,7 +565,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
} }
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M) fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where where
T: 'static, T: 'static,
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static, M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
@@ -580,7 +579,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
} }
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
fn add_async_meta_method_mut<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M) fn add_async_meta_method_mut<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where where
T: 'static, T: 'static,
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static, M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
@@ -593,7 +592,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
self.raw.async_meta_methods.push((name, callback)); self.raw.async_meta_methods.push((name, callback));
} }
fn add_meta_function<F, A, R>(&mut self, name: impl Into<StdString>, function: F) fn add_meta_function<F, A, R>(&mut self, name: impl Into<String>, function: F)
where where
F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static, F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -604,7 +603,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
self.raw.meta_methods.push((name, callback)); self.raw.meta_methods.push((name, callback));
} }
fn add_meta_function_mut<F, A, R>(&mut self, name: impl Into<StdString>, function: F) fn add_meta_function_mut<F, A, R>(&mut self, name: impl Into<String>, function: F)
where where
F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static, F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
@@ -616,7 +615,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
} }
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))] #[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl Into<StdString>, function: F) fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl Into<String>, function: F)
where where
F: Fn(Lua, A) -> FR + MaybeSend + 'static, F: Fn(Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti, A: FromLuaMulti,
+20 -14
View File
@@ -2,15 +2,15 @@ use std::any::Any;
use std::fmt::Write as _; use std::fmt::Write as _;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::os::raw::{c_int, c_void}; use std::os::raw::{c_int, c_void};
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
use std::ptr; use std::ptr;
use std::sync::Arc; use std::sync::Arc;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::memory::MemoryState; use crate::memory::MemoryState;
use crate::util::{ use crate::util::{
check_stack, get_internal_userdata, init_internal_metatable, push_internal_userdata, push_string, DESTRUCTED_USERDATA_METATABLE, TypeKey, check_stack, get_internal_userdata, init_internal_metatable,
push_table, rawset_field, to_string, TypeKey, DESTRUCTED_USERDATA_METATABLE, push_internal_userdata, push_string, push_table, rawset_field, to_string,
}; };
static WRAPPED_FAILURE_TYPE_KEY: u8 = 0; static WRAPPED_FAILURE_TYPE_KEY: u8 = 0;
@@ -208,7 +208,7 @@ where
F: FnOnce(*mut ffi::lua_State) -> R, F: FnOnce(*mut ffi::lua_State) -> R,
R: Copy, R: Copy,
{ {
let params = ffi::lua_touserdata(state, -1) as *mut Params<F, R>; let params = ffi::lua_tolightuserdata(state, -1) as *mut Params<F, R>;
ffi::lua_pop(state, 1); ffi::lua_pop(state, 1);
let f = (*params).function.take().unwrap(); let f = (*params).function.take().unwrap();
@@ -239,7 +239,7 @@ where
ffi::lua_pushlightuserdata(state, &mut params as *mut Params<F, R> as *mut c_void); ffi::lua_pushlightuserdata(state, &mut params as *mut Params<F, R> as *mut c_void);
let ret = ffi::lua_pcall(state, nargs + 1, nresults, stack_start + 1); let ret = ffi::lua_pcall(state, nargs + 1, nresults, stack_start + 1);
ffi::lua_remove(state, stack_start + 1); ffi::lua_remove(state, stack_start + 1); // remove error handler
if ret == ffi::LUA_OK { if ret == ffi::LUA_OK {
// `LUA_OK` is only returned when the `do_call` function has completed successfully, so // `LUA_OK` is only returned when the `do_call` function has completed successfully, so
@@ -373,19 +373,19 @@ pub(crate) unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<(
"__mod", "__mod",
"__pow", "__pow",
"__unm", "__unm",
#[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "luau"))]
"__idiv", "__idiv",
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
"__band", "__band",
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
"__bor", "__bor",
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
"__bxor", "__bxor",
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
"__bnot", "__bnot",
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
"__shl", "__shl",
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
"__shr", "__shr",
"__concat", "__concat",
"__len", "__len",
@@ -396,7 +396,13 @@ pub(crate) unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<(
"__newindex", "__newindex",
"__call", "__call",
"__tostring", "__tostring",
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luajit52"))] #[cfg(any(
feature = "lua55",
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luajit52"
))]
"__pairs", "__pairs",
#[cfg(any(feature = "lua53", feature = "lua52", feature = "luajit52"))] #[cfg(any(feature = "lua53", feature = "lua52", feature = "luajit52"))]
"__ipairs", "__ipairs",
@@ -404,7 +410,7 @@ pub(crate) unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<(
"__iter", "__iter",
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
"__namecall", "__namecall",
#[cfg(feature = "lua54")] #[cfg(any(feature = "lua55", feature = "lua54"))]
"__close", "__close",
] { ] {
ffi::lua_pushvalue(state, -1); ffi::lua_pushvalue(state, -1);
+39 -11
View File
@@ -6,16 +6,16 @@ use std::{ptr, slice, str};
use crate::error::{Error, Result}; use crate::error::{Error, Result};
pub(crate) use error::{ pub(crate) use error::{
error_traceback, error_traceback_thread, init_error_registry, pop_error, protect_lua_call, WrappedFailure, error_traceback, error_traceback_thread, init_error_registry, pop_error,
protect_lua_closure, WrappedFailure, protect_lua_call, protect_lua_closure,
}; };
pub(crate) use path::parse_path as parse_lookup_path; pub(crate) use path::parse_path as parse_lookup_path;
pub(crate) use short_names::short_type_name; pub(crate) use short_names::short_type_name;
pub(crate) use types::TypeKey; pub(crate) use types::TypeKey;
pub(crate) use userdata::{ pub(crate) use userdata::{
get_destructed_userdata_metatable, get_internal_metatable, get_internal_userdata, get_userdata, DESTRUCTED_USERDATA_METATABLE, get_destructed_userdata_metatable, get_internal_metatable,
init_internal_metatable, push_internal_userdata, push_userdata, take_userdata, get_internal_userdata, get_userdata, init_internal_metatable, push_internal_userdata, push_userdata,
DESTRUCTED_USERDATA_METATABLE, take_userdata,
}; };
#[cfg(not(feature = "luau"))] #[cfg(not(feature = "luau"))]
@@ -99,6 +99,38 @@ pub(crate) unsafe fn push_string(state: *mut ffi::lua_State, s: &[u8], protect:
} }
} }
// Uses 3 (or 1 if unprotected) stack spaces, does not call checkstack.
#[cfg(feature = "lua55")]
pub(crate) unsafe fn push_external_string(
state: *mut ffi::lua_State,
mut bytes: Vec<u8>,
protect: bool,
) -> Result<()> {
bytes.push(0);
let s_len = bytes.len() - 1; // exclude null terminator
let s_ptr = bytes.as_ptr() as *const c_char;
let bytes_ud = Box::into_raw(Box::new(bytes));
unsafe extern "C" fn dealloc(ud: *mut c_void, _: *mut c_void, _: usize, _: usize) -> *mut c_void {
drop(Box::from_raw(ud as *mut Vec<u8>));
ptr::null_mut()
}
if protect {
let res = protect_lua!(state, 0, 1, move |state| {
ffi::lua_pushexternalstring(state, s_ptr, s_len, Some(dealloc), bytes_ud as *mut _);
});
if res.is_err() {
// Deallocate on error
drop(Box::from_raw(bytes_ud));
return res;
}
} else {
ffi::lua_pushexternalstring(state, s_ptr, s_len, Some(dealloc), bytes_ud as *mut _);
}
Ok(())
}
// Uses 3 stack spaces (when protect), does not call checkstack. // Uses 3 stack spaces (when protect), does not call checkstack.
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
#[inline(always)] #[inline(always)]
@@ -220,7 +252,7 @@ pub(crate) unsafe extern "C-unwind" fn safe_xpcall(state: *mut ffi::lua_State) -
// Returns Lua main thread for Lua >= 5.2 or checks that the passed thread is main for Lua 5.1. // Returns Lua main thread for Lua >= 5.2 or checks that the passed thread is main for Lua 5.1.
// Does not call lua_checkstack, uses 1 stack space. // Does not call lua_checkstack, uses 1 stack space.
pub(crate) unsafe fn get_main_state(state: *mut ffi::lua_State) -> Option<*mut ffi::lua_State> { pub(crate) unsafe fn get_main_state(state: *mut ffi::lua_State) -> Option<*mut ffi::lua_State> {
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
{ {
ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_MAINTHREAD); ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_MAINTHREAD);
let main_state = ffi::lua_tothread(state, -1); let main_state = ffi::lua_tothread(state, -1);
@@ -232,11 +264,7 @@ pub(crate) unsafe fn get_main_state(state: *mut ffi::lua_State) -> Option<*mut f
// Check the current state first // Check the current state first
let is_main_state = ffi::lua_pushthread(state) == 1; let is_main_state = ffi::lua_pushthread(state) == 1;
ffi::lua_pop(state, 1); ffi::lua_pop(state, 1);
if is_main_state { if is_main_state { Some(state) } else { None }
Some(state)
} else {
None
}
} }
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
Some(ffi::lua_mainthread(state)) Some(ffi::lua_mainthread(state))
+1 -1
View File
@@ -196,7 +196,7 @@ fn unquote_string<'a>(path: &'a str, chars: &mut Peekable<CharIndices<'a>>) -> R
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{parse_path, PathKey}; use super::{PathKey, parse_path};
#[test] #[test]
fn test_parse_path() { fn test_parse_path() {
+1 -1
View File
@@ -3,7 +3,7 @@ use std::{mem, ptr};
use crate::error::Result; use crate::error::Result;
use crate::userdata::collect_userdata; use crate::userdata::collect_userdata;
use crate::util::{check_stack, get_metatable_ptr, push_table, rawset_field, TypeKey}; use crate::util::{TypeKey, check_stack, get_metatable_ptr, push_table, rawset_field};
// Pushes the userdata and attaches a metatable with __gc method. // Pushes the userdata and attaches a metatable with __gc method.
// Internally uses 3 stack spaces, does not call checkstack. // Internally uses 3 stack spaces, does not call checkstack.
+15 -16
View File
@@ -1,19 +1,18 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::HashSet; use std::collections::HashSet;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::string::String as StdString;
use std::{fmt, ptr, str}; use std::{fmt, ptr, str};
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::function::Function; use crate::function::Function;
use crate::string::{BorrowedStr, String}; use crate::string::{BorrowedStr, LuaString};
use crate::table::Table; use crate::table::Table;
use crate::thread::Thread; use crate::thread::Thread;
use crate::types::{Integer, LightUserData, Number, ValueRef}; use crate::types::{Integer, LightUserData, Number, ValueRef};
use crate::userdata::AnyUserData; use crate::userdata::AnyUserData;
use crate::util::{check_stack, StackGuard}; use crate::util::{StackGuard, check_stack};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use { use {
@@ -50,7 +49,7 @@ pub enum Value {
/// An interned string, managed by Lua. /// An interned string, managed by Lua.
/// ///
/// Unlike Rust strings, Lua strings may not be valid UTF-8. /// Unlike Rust strings, Lua strings may not be valid UTF-8.
String(String), String(LuaString),
/// Reference to a Lua table. /// Reference to a Lua table.
Table(Table), Table(Table),
/// Reference to a Lua function (or closure). /// Reference to a Lua function (or closure).
@@ -129,7 +128,7 @@ impl Value {
#[inline] #[inline]
pub fn to_pointer(&self) -> *const c_void { pub fn to_pointer(&self) -> *const c_void {
match self { match self {
Value::String(String(vref)) => { Value::String(LuaString(vref)) => {
// In Lua < 5.4 (excluding Luau), string pointers are NULL // In Lua < 5.4 (excluding Luau), string pointers are NULL
// Use alternative approach // Use alternative approach
let lua = vref.lua.lock(); let lua = vref.lua.lock();
@@ -151,8 +150,8 @@ impl Value {
/// ///
/// This might invoke the `__tostring` metamethod for non-primitive types (eg. tables, /// This might invoke the `__tostring` metamethod for non-primitive types (eg. tables,
/// functions). /// functions).
pub fn to_string(&self) -> Result<StdString> { pub fn to_string(&self) -> Result<String> {
unsafe fn invoke_to_string(vref: &ValueRef) -> Result<StdString> { unsafe fn invoke_to_string(vref: &ValueRef) -> Result<String> {
let lua = vref.lua.lock(); let lua = vref.lua.lock();
let state = lua.state(); let state = lua.state();
let _guard = StackGuard::new(state); let _guard = StackGuard::new(state);
@@ -162,7 +161,7 @@ impl Value {
protect_lua!(state, 1, 1, fn(state) { protect_lua!(state, 1, 1, fn(state) {
ffi::luaL_tolstring(state, -1, ptr::null_mut()); ffi::luaL_tolstring(state, -1, ptr::null_mut());
})?; })?;
Ok(String(lua.pop_ref()).to_str()?.to_string()) Ok(LuaString(lua.pop_ref()).to_str()?.to_string())
} }
match self { match self {
@@ -336,17 +335,17 @@ impl Value {
self.as_number() self.as_number()
} }
/// Returns `true` if the value is a Lua [`String`]. /// Returns `true` if the value is a [`LuaString`].
#[inline] #[inline]
pub fn is_string(&self) -> bool { pub fn is_string(&self) -> bool {
self.as_string().is_some() self.as_string().is_some()
} }
/// Cast the value to Lua [`String`]. /// Cast the value to a [`LuaString`].
/// ///
/// If the value is a Lua [`String`], returns it or `None` otherwise. /// If the value is a [`LuaString`], returns it or `None` otherwise.
#[inline] #[inline]
pub fn as_string(&self) -> Option<&String> { pub fn as_string(&self) -> Option<&LuaString> {
match self { match self {
Value::String(s) => Some(s), Value::String(s) => Some(s),
_ => None, _ => None,
@@ -355,7 +354,7 @@ impl Value {
/// Cast the value to [`BorrowedStr`]. /// Cast the value to [`BorrowedStr`].
/// ///
/// If the value is a Lua [`String`], try to convert it to [`BorrowedStr`] or return `None` /// If the value is a [`LuaString`], try to convert it to [`BorrowedStr`] or return `None`
/// otherwise. /// otherwise.
#[deprecated( #[deprecated(
since = "0.11.0", since = "0.11.0",
@@ -366,15 +365,15 @@ impl Value {
self.as_string().and_then(|s| s.to_str().ok()) self.as_string().and_then(|s| s.to_str().ok())
} }
/// Cast the value to [`StdString`]. /// Cast the value to [`String`].
/// ///
/// If the value is a Lua [`String`], converts it to [`StdString`] or returns `None` otherwise. /// If the value is a [`LuaString`], converts it to [`String`] or returns `None` otherwise.
#[deprecated( #[deprecated(
since = "0.11.0", since = "0.11.0",
note = "This method does not follow Rust naming convention. Use `as_string().map(|s| s.to_string_lossy())` instead." note = "This method does not follow Rust naming convention. Use `as_string().map(|s| s.to_string_lossy())` instead."
)] )]
#[inline] #[inline]
pub fn as_string_lossy(&self) -> Option<StdString> { pub fn as_string_lossy(&self) -> Option<String> {
self.as_string().map(|s| s.to_string_lossy()) self.as_string().map(|s| s.to_string_lossy())
} }
+6 -6
View File
@@ -1,11 +1,11 @@
[lua54] [lua55]
features = "lua54,vendored,async,send,serde,macros,anyhow,userdata-wrappers" features = "lua55,vendored,async,send,serde,macros,anyhow,userdata-wrappers"
[lua54_non_send] [lua55_non_send]
features = "lua54,vendored,async,serde,macros,anyhow,userdata-wrappers" features = "lua55,vendored,async,serde,macros,anyhow,userdata-wrappers"
[lua54_with_memory_limit] [lua55_with_memory_limit]
features = "lua54,vendored,async,send,serde,macros,anyhow,userdata-wrappers" features = "lua55,vendored,async,send,serde,macros,anyhow,userdata-wrappers"
rustflags = "--cfg force_memory_limit" rustflags = "--cfg force_memory_limit"
[lua51] [lua51]
+4 -5
View File
@@ -1,6 +1,5 @@
#![cfg(feature = "async")] #![cfg(feature = "async")]
use std::string::String as StdString;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
@@ -40,7 +39,7 @@ async fn test_async_function() -> Result<()> {
async fn test_async_function_wrap() -> Result<()> { async fn test_async_function_wrap() -> Result<()> {
let lua = Lua::new(); let lua = Lua::new();
let f = Function::wrap_async(|s: StdString| async move { let f = Function::wrap_async(|s: String| async move {
tokio::task::yield_now().await; tokio::task::yield_now().await;
Ok(s) Ok(s)
}); });
@@ -68,7 +67,7 @@ async fn test_async_function_wrap() -> Result<()> {
async fn test_async_function_wrap_raw() -> Result<()> { async fn test_async_function_wrap_raw() -> Result<()> {
let lua = Lua::new(); let lua = Lua::new();
let f = Function::wrap_raw_async(|s: StdString| async move { let f = Function::wrap_raw_async(|s: String| async move {
tokio::task::yield_now().await; tokio::task::yield_now().await;
s s
}); });
@@ -249,7 +248,7 @@ async fn test_async_return_async_closure() -> Result<()> {
Ok(()) Ok(())
} }
#[cfg(feature = "lua54")] #[cfg(any(feature = "lua55", feature = "lua54"))]
#[tokio::test] #[tokio::test]
async fn test_async_lua54_to_be_closed() -> Result<()> { async fn test_async_lua54_to_be_closed() -> Result<()> {
let lua = Lua::new(); let lua = Lua::new();
@@ -670,7 +669,7 @@ async fn test_async_hook() -> Result<()> {
static HOOK_CALLED: AtomicBool = AtomicBool::new(false); static HOOK_CALLED: AtomicBool = AtomicBool::new(false);
lua.set_global_hook(mlua::HookTriggers::new().every_line(), move |_, _| { lua.set_global_hook(mlua::HookTriggers::new().every_line(), move |_, _| {
if !HOOK_CALLED.swap(true, Ordering::Relaxed) { if !HOOK_CALLED.swap(true, Ordering::Relaxed) {
#[cfg(any(feature = "lu53", feature = "lua54"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
return Ok(mlua::VmState::Yield); return Ok(mlua::VmState::Yield);
} }
Ok(mlua::VmState::Continue) Ok(mlua::VmState::Continue)
+22 -12
View File
@@ -1,15 +1,19 @@
error[E0596]: cannot borrow `s` as mutable, as it is a captured variable in a `Fn` closure error[E0596]: cannot borrow `s` as mutable, as it is a captured variable in a `Fn` closure
--> tests/compile/async_any_userdata_method.rs:9:49 --> tests/compile/async_any_userdata_method.rs:9:49
| |
9 | reg.add_async_method("t", |_, this, ()| async { 8 | let mut s = &s;
| ^^^^^ cannot borrow as mutable | ----- `s` declared here, outside the closure
9 | reg.add_async_method("t", |_, this, ()| async {
| ------------- ^^^^^ cannot borrow as mutable
| |
| in this closure
10 | s = &*this; 10 | s = &*this;
| - mutable borrow occurs due to use of `s` in closure | - mutable borrow occurs due to use of `s` in closure
error[E0373]: async block may outlive the current function, but it borrows `this`, which is owned by the current function error[E0373]: async block may outlive the current function, but it borrows `this`, which is owned by the current function
--> tests/compile/async_any_userdata_method.rs:9:49 --> tests/compile/async_any_userdata_method.rs:9:49
| |
9 | reg.add_async_method("t", |_, this, ()| async { 9 | reg.add_async_method("t", |_, this, ()| async {
| ^^^^^ may outlive borrowed value `this` | ^^^^^ may outlive borrowed value `this`
10 | s = &*this; 10 | s = &*this;
| ---- `this` is borrowed here | ---- `this` is borrowed here
@@ -17,7 +21,7 @@ error[E0373]: async block may outlive the current function, but it borrows `this
note: async block is returned here note: async block is returned here
--> tests/compile/async_any_userdata_method.rs:9:49 --> tests/compile/async_any_userdata_method.rs:9:49
| |
9 | reg.add_async_method("t", |_, this, ()| async { 9 | reg.add_async_method("t", |_, this, ()| async {
| _________________________________________________^ | _________________________________________________^
10 | | s = &*this; 10 | | s = &*this;
11 | | Ok(()) 11 | | Ok(())
@@ -25,13 +29,13 @@ note: async block is returned here
| |_________^ | |_________^
help: to force the async block to take ownership of `this` (and any other referenced variables), use the `move` keyword help: to force the async block to take ownership of `this` (and any other referenced variables), use the `move` keyword
| |
9 | reg.add_async_method("t", |_, this, ()| async move { 9 | reg.add_async_method("t", |_, this, ()| async move {
| ++++ | ++++
error: lifetime may not live long enough error: lifetime may not live long enough
--> tests/compile/async_any_userdata_method.rs:9:49 --> tests/compile/async_any_userdata_method.rs:9:49
| |
9 | reg.add_async_method("t", |_, this, ()| async { 9 | reg.add_async_method("t", |_, this, ()| async {
| ___________________________________-------------_^ | ___________________________________-------------_^
| | | | | | | |
| | | return type of closure `{async block@$DIR/tests/compile/async_any_userdata_method.rs:9:49: 9:54}` contains a lifetime `'2` | | | return type of closure `{async block@$DIR/tests/compile/async_any_userdata_method.rs:9:49: 9:54}` contains a lifetime `'2`
@@ -46,22 +50,28 @@ error: lifetime may not live long enough
error[E0597]: `s` does not live long enough error[E0597]: `s` does not live long enough
--> tests/compile/async_any_userdata_method.rs:8:21 --> tests/compile/async_any_userdata_method.rs:8:21
| |
7 | let s = String::new(); 7 | let s = String::new();
| - binding `s` declared here | - binding `s` declared here
8 | let mut s = &s; 8 | let mut s = &s;
| ^^ borrowed value does not live long enough | ^^ borrowed value does not live long enough
9 | / reg.add_async_method("t", |_, this, ()| async { 9 | / reg.add_async_method("t", |_, this, ()| async {
10 | | s = &*this; 10 | | s = &*this;
11 | | Ok(()) 11 | | Ok(())
12 | | }); 12 | | });
| |__________- argument requires that `s` is borrowed for `'static` | |__________- argument requires that `s` is borrowed for `'static`
13 | }) 13 | })
| - `s` dropped here while still borrowed | - `s` dropped here while still borrowed
|
note: requirement that the value outlives `'static` introduced here
--> src/userdata.rs
|
| M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
| ^^^^^^^
error[E0373]: closure may outlive the current function, but it borrows `s`, which is owned by the current function error[E0373]: closure may outlive the current function, but it borrows `s`, which is owned by the current function
--> tests/compile/async_any_userdata_method.rs:9:35 --> tests/compile/async_any_userdata_method.rs:9:35
| |
9 | reg.add_async_method("t", |_, this, ()| async { 9 | reg.add_async_method("t", |_, this, ()| async {
| ^^^^^^^^^^^^^ may outlive borrowed value `s` | ^^^^^^^^^^^^^ may outlive borrowed value `s`
10 | s = &*this; 10 | s = &*this;
| - `s` is borrowed here | - `s` is borrowed here
@@ -69,12 +79,12 @@ error[E0373]: closure may outlive the current function, but it borrows `s`, whic
note: function requires argument type to outlive `'static` note: function requires argument type to outlive `'static`
--> tests/compile/async_any_userdata_method.rs:9:9 --> tests/compile/async_any_userdata_method.rs:9:9
| |
9 | / reg.add_async_method("t", |_, this, ()| async { 9 | / reg.add_async_method("t", |_, this, ()| async {
10 | | s = &*this; 10 | | s = &*this;
11 | | Ok(()) 11 | | Ok(())
12 | | }); 12 | | });
| |__________^ | |__________^
help: to force the closure to take ownership of `s` (and any other referenced variables), use the `move` keyword help: to force the closure to take ownership of `s` (and any other referenced variables), use the `move` keyword
| |
9 | reg.add_async_method("t", move |_, this, ()| async { 9 | reg.add_async_method("t", move |_, this, ()| async {
| ++++ | ++++
@@ -1,10 +1,10 @@
error: lifetime may not live long enough error: lifetime may not live long enough
--> tests/compile/async_nonstatic_userdata.rs:9:13 --> tests/compile/async_nonstatic_userdata.rs:9:13
| |
7 | impl UserData for MyUserData<'_> { 7 | impl UserData for MyUserData<'_> {
| -- lifetime `'1` appears in the `impl`'s self type | -- lifetime `'1` appears in the `impl`'s self type
8 | fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) { 8 | fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
9 | / methods.add_async_method("print", |_, data, ()| async move { 9 | / methods.add_async_method("print", |_, data, ()| async move {
10 | | println!("{}", data.0); 10 | | println!("{}", data.0);
11 | | Ok(()) 11 | | Ok(())
12 | | }); 12 | | });
+51 -29
View File
@@ -1,28 +1,32 @@
error[E0277]: the type `UnsafeCell<*mut lua_State>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary error[E0277]: the type `UnsafeCell<mlua::state::raw::RawLua>` may contain interior mutability and a reference may not be safely transferable across a catch_unwind boundary
--> tests/compile/lua_norefunwindsafe.rs:7:18 --> tests/compile/lua_norefunwindsafe.rs:7:18
| |
7 | catch_unwind(|| lua.create_table().unwrap()); 7 | catch_unwind(|| lua.create_table().unwrap());
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<*mut lua_State>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<mlua::state::raw::RawLua>` may contain interior mutability and a reference may not be safely transferable across a catch_unwind boundary
| | | |
| required by a bound introduced by this call | required by a bound introduced by this call
| |
= help: within `mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<*mut lua_State>` = help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::state::raw::RawLua>`
note: required because it appears within the type `Cell<*mut lua_State>` note: required because it appears within the type `lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>`
--> $RUST/core/src/cell.rs --> $CARGO/lock_api-$VERSION/src/remutex.rs
| |
| pub struct Cell<T: ?Sized> { | pub struct ReentrantMutex<R, G, T: ?Sized> {
| ^^^^ | ^^^^^^^^^^^^^^
note: required because it appears within the type `mlua::state::raw::RawLua` note: required because it appears within the type `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
--> src/state/raw.rs --> $RUST/alloc/src/sync.rs
| |
| pub struct RawLua { | struct ArcInner<T: ?Sized> {
| ^^^^^^ | ^^^^^^^^
note: required because it appears within the type `mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>` note: required because it appears within the type `PhantomData<alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>>`
--> src/types/sync.rs --> $RUST/core/src/marker.rs
| |
| pub(crate) struct ReentrantMutex<T>(T); | pub struct PhantomData<T: PointeeSized>;
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^
= note: required for `Rc<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>` to implement `RefUnwindSafe` note: required because it appears within the type `Arc<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
--> $RUST/alloc/src/sync.rs
|
| pub struct Arc<
| ^^^
note: required because it appears within the type `Lua` note: required because it appears within the type `Lua`
--> src/state.rs --> src/state.rs
| |
@@ -40,27 +44,45 @@ note: required by a bound in `std::panic::catch_unwind`
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> { | pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
| ^^^^^^^^^^ required by this bound in `catch_unwind` | ^^^^^^^^^^ required by this bound in `catch_unwind`
error[E0277]: the type `UnsafeCell<mlua::state::extra::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary error[E0277]: the type `UnsafeCell<usize>` may contain interior mutability and a reference may not be safely transferable across a catch_unwind boundary
--> tests/compile/lua_norefunwindsafe.rs:7:18 --> tests/compile/lua_norefunwindsafe.rs:7:18
| |
7 | catch_unwind(|| lua.create_table().unwrap()); 7 | catch_unwind(|| lua.create_table().unwrap());
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<mlua::state::extra::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<usize>` may contain interior mutability and a reference may not be safely transferable across a catch_unwind boundary
| | | |
| required by a bound introduced by this call | required by a bound introduced by this call
| |
= help: the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::state::extra::ExtraData>` = help: within `Lua`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<usize>`
= note: required for `Rc<UnsafeCell<mlua::state::extra::ExtraData>>` to implement `RefUnwindSafe` note: required because it appears within the type `Cell<usize>`
note: required because it appears within the type `mlua::state::raw::RawLua` --> $RUST/core/src/cell.rs
--> src/state/raw.rs
| |
| pub struct RawLua { | pub struct Cell<T: ?Sized> {
| ^^^^^^ | ^^^^
note: required because it appears within the type `mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>` note: required because it appears within the type `lock_api::remutex::RawReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId>`
--> src/types/sync.rs --> $CARGO/lock_api-$VERSION/src/remutex.rs
| |
| pub(crate) struct ReentrantMutex<T>(T); | pub struct RawReentrantMutex<R, G> {
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
= note: required for `Rc<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>` to implement `RefUnwindSafe` note: required because it appears within the type `lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>`
--> $CARGO/lock_api-$VERSION/src/remutex.rs
|
| pub struct ReentrantMutex<R, G, T: ?Sized> {
| ^^^^^^^^^^^^^^
note: required because it appears within the type `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
--> $RUST/alloc/src/sync.rs
|
| struct ArcInner<T: ?Sized> {
| ^^^^^^^^
note: required because it appears within the type `PhantomData<alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>>`
--> $RUST/core/src/marker.rs
|
| pub struct PhantomData<T: PointeeSized>;
| ^^^^^^^^^^^
note: required because it appears within the type `Arc<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
--> $RUST/alloc/src/sync.rs
|
| pub struct Arc<
| ^^^
note: required because it appears within the type `Lua` note: required because it appears within the type `Lua`
--> src/state.rs --> src/state.rs
| |
+71 -128
View File
@@ -1,143 +1,86 @@
error[E0277]: the type `UnsafeCell<usize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary error[E0277]: the type `UnsafeCell<mlua::state::raw::RawLua>` may contain interior mutability and a reference may not be safely transferable across a catch_unwind boundary
--> tests/compile/ref_nounwindsafe.rs:8:18 --> tests/compile/ref_nounwindsafe.rs:8:18
| |
8 | catch_unwind(move || table.set("a", "b").unwrap()); 8 | catch_unwind(move || table.set("a", "b").unwrap());
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<usize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<mlua::state::raw::RawLua>` may contain interior mutability and a reference may not be safely transferable across a catch_unwind boundary
| | | |
| required by a bound introduced by this call | required by a bound introduced by this call
| |
= help: within `rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<usize>` = help: within `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::state::raw::RawLua>`
note: required because it appears within the type `lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>`
--> $CARGO/lock_api-$VERSION/src/remutex.rs
|
| pub struct ReentrantMutex<R, G, T: ?Sized> {
| ^^^^^^^^^^^^^^
note: required because it appears within the type `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
--> $RUST/alloc/src/sync.rs
|
| struct ArcInner<T: ?Sized> {
| ^^^^^^^^
= note: required for `NonNull<alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>>` to implement `UnwindSafe`
note: required because it appears within the type `std::sync::Weak<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
--> $RUST/alloc/src/sync.rs
|
| pub struct Weak<
| ^^^^
note: required because it appears within the type `WeakLua`
--> src/state.rs
|
| pub struct WeakLua(XWeak<ReentrantMutex<RawLua>>);
| ^^^^^^^
note: required because it appears within the type `mlua::types::value_ref::ValueRef`
--> src/types/value_ref.rs
|
| pub struct ValueRef {
| ^^^^^^^^
note: required because it appears within the type `LuaTable`
--> src/table.rs
|
| pub struct Table(pub(crate) ValueRef);
| ^^^^^
note: required because it's used within this closure
--> tests/compile/ref_nounwindsafe.rs:8:18
|
8 | catch_unwind(move || table.set("a", "b").unwrap());
| ^^^^^^^
note: required by a bound in `std::panic::catch_unwind`
--> $RUST/std/src/panic.rs
|
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
| ^^^^^^^^^^ required by this bound in `catch_unwind`
error[E0277]: the type `UnsafeCell<usize>` may contain interior mutability and a reference may not be safely transferable across a catch_unwind boundary
--> tests/compile/ref_nounwindsafe.rs:8:18
|
8 | catch_unwind(move || table.set("a", "b").unwrap());
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<usize>` may contain interior mutability and a reference may not be safely transferable across a catch_unwind boundary
| |
| required by a bound introduced by this call
|
= help: within `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<usize>`
note: required because it appears within the type `Cell<usize>` note: required because it appears within the type `Cell<usize>`
--> $RUST/core/src/cell.rs --> $RUST/core/src/cell.rs
| |
| pub struct Cell<T: ?Sized> { | pub struct Cell<T: ?Sized> {
| ^^^^ | ^^^^
note: required because it appears within the type `rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>` note: required because it appears within the type `lock_api::remutex::RawReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId>`
--> $RUST/alloc/src/rc.rs --> $CARGO/lock_api-$VERSION/src/remutex.rs
| |
| struct RcInner<T: ?Sized> { | pub struct RawReentrantMutex<R, G> {
| ^^^^^^^ | ^^^^^^^^^^^^^^^^^
= note: required for `NonNull<rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>>` to implement `UnwindSafe` note: required because it appears within the type `lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>`
note: required because it appears within the type `std::rc::Weak<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>` --> $CARGO/lock_api-$VERSION/src/remutex.rs
--> $RUST/alloc/src/rc.rs |
| | pub struct ReentrantMutex<R, G, T: ?Sized> {
| pub struct Weak< | ^^^^^^^^^^^^^^
| ^^^^ note: required because it appears within the type `alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
note: required because it appears within the type `WeakLua` --> $RUST/alloc/src/sync.rs
--> src/state.rs |
| | struct ArcInner<T: ?Sized> {
| pub struct WeakLua(XWeak<ReentrantMutex<RawLua>>); | ^^^^^^^^
| ^^^^^^^ = note: required for `NonNull<alloc::sync::ArcInner<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>>` to implement `UnwindSafe`
note: required because it appears within the type `mlua::types::value_ref::ValueRef` note: required because it appears within the type `std::sync::Weak<lock_api::remutex::ReentrantMutex<parking_lot::raw_mutex::RawMutex, parking_lot::remutex::RawThreadId, mlua::state::raw::RawLua>>`
--> src/types/value_ref.rs --> $RUST/alloc/src/sync.rs
|
| pub struct ValueRef {
| ^^^^^^^^
note: required because it appears within the type `LuaTable`
--> src/table.rs
|
| pub struct Table(pub(crate) ValueRef);
| ^^^^^
note: required because it's used within this closure
--> tests/compile/ref_nounwindsafe.rs:8:18
|
8 | catch_unwind(move || table.set("a", "b").unwrap());
| ^^^^^^^
note: required by a bound in `std::panic::catch_unwind`
--> $RUST/std/src/panic.rs
|
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
| ^^^^^^^^^^ required by this bound in `catch_unwind`
error[E0277]: the type `UnsafeCell<*mut lua_State>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
--> tests/compile/ref_nounwindsafe.rs:8:18
|
8 | catch_unwind(move || table.set("a", "b").unwrap());
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<*mut lua_State>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
| |
| required by a bound introduced by this call
|
= help: within `rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<*mut lua_State>`
note: required because it appears within the type `Cell<*mut lua_State>`
--> $RUST/core/src/cell.rs
|
| pub struct Cell<T: ?Sized> {
| ^^^^
note: required because it appears within the type `mlua::state::raw::RawLua`
--> src/state/raw.rs
|
| pub struct RawLua {
| ^^^^^^
note: required because it appears within the type `mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>`
--> src/types/sync.rs
|
| pub(crate) struct ReentrantMutex<T>(T);
| ^^^^^^^^^^^^^^
note: required because it appears within the type `rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
--> $RUST/alloc/src/rc.rs
|
| struct RcInner<T: ?Sized> {
| ^^^^^^^
= note: required for `NonNull<rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>>` to implement `UnwindSafe`
note: required because it appears within the type `std::rc::Weak<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
--> $RUST/alloc/src/rc.rs
|
| pub struct Weak<
| ^^^^
note: required because it appears within the type `WeakLua`
--> src/state.rs
|
| pub struct WeakLua(XWeak<ReentrantMutex<RawLua>>);
| ^^^^^^^
note: required because it appears within the type `mlua::types::value_ref::ValueRef`
--> src/types/value_ref.rs
|
| pub struct ValueRef {
| ^^^^^^^^
note: required because it appears within the type `LuaTable`
--> src/table.rs
|
| pub struct Table(pub(crate) ValueRef);
| ^^^^^
note: required because it's used within this closure
--> tests/compile/ref_nounwindsafe.rs:8:18
|
8 | catch_unwind(move || table.set("a", "b").unwrap());
| ^^^^^^^
note: required by a bound in `std::panic::catch_unwind`
--> $RUST/std/src/panic.rs
|
| pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
| ^^^^^^^^^^ required by this bound in `catch_unwind`
error[E0277]: the type `UnsafeCell<mlua::state::extra::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
--> tests/compile/ref_nounwindsafe.rs:8:18
|
8 | catch_unwind(move || table.set("a", "b").unwrap());
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<mlua::state::extra::ExtraData>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
| |
| required by a bound introduced by this call
|
= help: the trait `RefUnwindSafe` is not implemented for `UnsafeCell<mlua::state::extra::ExtraData>`
= note: required for `Rc<UnsafeCell<mlua::state::extra::ExtraData>>` to implement `RefUnwindSafe`
note: required because it appears within the type `mlua::state::raw::RawLua`
--> src/state/raw.rs
|
| pub struct RawLua {
| ^^^^^^
note: required because it appears within the type `mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>`
--> src/types/sync.rs
|
| pub(crate) struct ReentrantMutex<T>(T);
| ^^^^^^^^^^^^^^
note: required because it appears within the type `rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
--> $RUST/alloc/src/rc.rs
|
| struct RcInner<T: ?Sized> {
| ^^^^^^^
= note: required for `NonNull<rc::RcInner<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>>` to implement `UnwindSafe`
note: required because it appears within the type `std::rc::Weak<mlua::types::sync::inner::ReentrantMutex<mlua::state::raw::RawLua>>`
--> $RUST/alloc/src/rc.rs
| |
| pub struct Weak< | pub struct Weak<
| ^^^^ | ^^^^
+8 -8
View File
@@ -1,24 +1,24 @@
error[E0373]: closure may outlive the current function, but it borrows `inner`, which is owned by the current function error[E0373]: closure may outlive the current function, but it borrows `inner`, which is owned by the current function
--> tests/compile/scope_callback_capture.rs:7:43 --> tests/compile/scope_callback_capture.rs:7:43
| |
5 | lua.scope(|scope| { 5 | lua.scope(|scope| {
| ----- has type `&'1 mlua::Scope<'1, '_>` | ----- has type `&'1 mlua::Scope<'1, '_>`
6 | let mut inner: Option<Table> = None; 6 | let mut inner: Option<Table> = None;
7 | let f = scope.create_function_mut(|_, t: Table| { 7 | let f = scope.create_function_mut(|_, t: Table| {
| ^^^^^^^^^^^^^ may outlive borrowed value `inner` | ^^^^^^^^^^^^^ may outlive borrowed value `inner`
8 | inner = Some(t); 8 | inner = Some(t);
| ----- `inner` is borrowed here | ----- `inner` is borrowed here
| |
note: function requires argument type to outlive `'1` note: function requires argument type to outlive `'1`
--> tests/compile/scope_callback_capture.rs:7:17 --> tests/compile/scope_callback_capture.rs:7:17
| |
7 | let f = scope.create_function_mut(|_, t: Table| { 7 | let f = scope.create_function_mut(|_, t: Table| {
| _________________^ | _________________^
8 | | inner = Some(t); 8 | | inner = Some(t);
9 | | Ok(()) 9 | | Ok(())
10 | | })?; 10 | | })?;
| |__________^ | |__________^
help: to force the closure to take ownership of `inner` (and any other referenced variables), use the `move` keyword help: to force the closure to take ownership of `inner` (and any other referenced variables), use the `move` keyword
| |
7 | let f = scope.create_function_mut(move |_, t: Table| { 7 | let f = scope.create_function_mut(move |_, t: Table| {
| ++++ | ++++
+1 -1
View File
@@ -1,7 +1,7 @@
error[E0373]: closure may outlive the current function, but it borrows `test.field`, which is owned by the current function error[E0373]: closure may outlive the current function, but it borrows `test.field`, which is owned by the current function
--> tests/compile/scope_invariance.rs:13:39 --> tests/compile/scope_invariance.rs:13:39
| |
9 | lua.scope(|scope| { 9 | lua.scope(|scope| {
| ----- has type `&'1 mlua::Scope<'1, '_>` | ----- has type `&'1 mlua::Scope<'1, '_>`
... ...
13 | scope.create_function_mut(|_, ()| { 13 | scope.create_function_mut(|_, ()| {
@@ -10,3 +10,9 @@ error[E0499]: cannot borrow `i` as mutable more than once at a time
| argument requires that `i` is borrowed for `'1` | argument requires that `i` is borrowed for `'1`
12 | let _b = scope.create_userdata(MyUserData(&mut i)).unwrap(); 12 | let _b = scope.create_userdata(MyUserData(&mut i)).unwrap();
| ^^^^^^ second mutable borrow occurs here | ^^^^^^ second mutable borrow occurs here
|
note: requirement that the value outlives `'1` introduced here
--> src/scope.rs
|
| T: UserData + 'env,
| ^^^^
@@ -13,3 +13,9 @@ error[E0597]: `ibad` does not live long enough
| argument requires that `ibad` is borrowed for `'1` | argument requires that `ibad` is borrowed for `'1`
16 | }; 16 | };
| - `ibad` dropped here while still borrowed | - `ibad` dropped here while still borrowed
|
note: requirement that the value outlives `'1` introduced here
--> src/scope.rs
|
| T: UserData + 'env,
| ^^^^
+17 -13
View File
@@ -49,7 +49,7 @@ fn test_string_from_lua() -> Result<()> {
let lua = Lua::new(); let lua = Lua::new();
// From stack // From stack
let f = lua.create_function(|_, s: mlua::String| Ok(s))?; let f = lua.create_function(|_, s: mlua::LuaString| Ok(s))?;
let s = f.call::<String>("hello, world!")?; let s = f.call::<String>("hello, world!")?;
assert_eq!(s, "hello, world!"); assert_eq!(s, "hello, world!");
@@ -708,9 +708,10 @@ fn test_either_from_lua() -> Result<()> {
}, },
err => panic!("expected `Error::BadArgument`, got {err:?}"), err => panic!("expected `Error::BadArgument`, got {err:?}"),
} }
assert!(err assert!(
.to_string() err.to_string()
.starts_with("bad argument #1: error converting Lua string to Either<i32, Table>"),); .starts_with("bad argument #1: error converting Lua string to Either<i32, Table>"),
);
} }
err => panic!("expected `Error::CallbackError`, got {err:?}"), err => panic!("expected `Error::CallbackError`, got {err:?}"),
} }
@@ -736,15 +737,18 @@ fn test_char_from_lua() -> Result<()> {
assert_eq!(lua.convert::<char>("A")?, 'A'); assert_eq!(lua.convert::<char>("A")?, 'A');
assert_eq!(lua.convert::<char>(65)?, 'A'); assert_eq!(lua.convert::<char>(65)?, 'A');
assert_eq!(lua.convert::<char>(128175)?, '💯'); assert_eq!(lua.convert::<char>(128175)?, '💯');
assert!(lua assert!(
.convert::<char>(5456324) lua.convert::<char>(5456324)
.is_err_and(|e| e.to_string().contains("integer out of range"))); .is_err_and(|e| e.to_string().contains("integer out of range"))
assert!(lua );
.convert::<char>("hello") assert!(
.is_err_and(|e| e.to_string().contains("expected string to have exactly one char"))); lua.convert::<char>("hello")
assert!(lua .is_err_and(|e| e.to_string().contains("expected string to have exactly one char"))
.convert::<char>(HashMap::<String, String>::new()) );
.is_err_and(|e| e.to_string().contains("expected string or integer"))); assert!(
lua.convert::<char>(HashMap::<String, String>::new())
.is_err_and(|e| e.to_string().contains("expected string or integer"))
);
Ok(()) Ok(())
} }
+25 -6
View File
@@ -1,4 +1,4 @@
use mlua::{Error, Function, Lua, Result, String, Table, Variadic}; use mlua::{Error, Function, Lua, LuaString, Result, Table, Variadic};
#[test] #[test]
fn test_function_call() -> Result<()> { fn test_function_call() -> Result<()> {
@@ -194,6 +194,25 @@ fn test_function_info() -> Result<()> {
assert_eq!(print_info.what, "C"); assert_eq!(print_info.what, "C");
assert_eq!(print_info.line_defined, None); assert_eq!(print_info.line_defined, None);
// Function with upvalues and params
#[cfg(not(any(feature = "lua51", feature = "luajit")))]
{
let func_with_upvalues = lua
.load(
r#"
local x, y = ...
return function(a, ...)
return a*x + y
end
"#,
)
.call::<Function>((10, 20))?;
let func_with_upvalues_info = func_with_upvalues.info();
assert_eq!(func_with_upvalues_info.num_upvalues, 2);
assert_eq!(func_with_upvalues_info.num_params, 1);
assert_eq!(func_with_upvalues_info.is_vararg, true);
}
Ok(()) Ok(())
} }
@@ -248,7 +267,7 @@ fn test_function_coverage() -> Result<()> {
assert_eq!( assert_eq!(
report[0], report[0],
mlua::CoverageInfo { mlua::function::CoverageInfo {
function: None, function: None,
line_defined: 1, line_defined: 1,
depth: 0, depth: 0,
@@ -257,7 +276,7 @@ fn test_function_coverage() -> Result<()> {
); );
assert_eq!( assert_eq!(
report[1], report[1],
mlua::CoverageInfo { mlua::function::CoverageInfo {
function: Some("abc".into()), function: Some("abc".into()),
line_defined: 4, line_defined: 4,
depth: 1, depth: 1,
@@ -266,7 +285,7 @@ fn test_function_coverage() -> Result<()> {
); );
assert_eq!( assert_eq!(
report[2], report[2],
mlua::CoverageInfo { mlua::function::CoverageInfo {
function: None, function: None,
line_defined: 12, line_defined: 12,
depth: 1, depth: 1,
@@ -275,7 +294,7 @@ fn test_function_coverage() -> Result<()> {
); );
assert_eq!( assert_eq!(
report[3], report[3],
mlua::CoverageInfo { mlua::function::CoverageInfo {
function: None, function: None,
line_defined: 13, line_defined: 13,
depth: 2, depth: 2,
@@ -324,7 +343,7 @@ fn test_function_deep_clone() -> Result<()> {
fn test_function_wrap() -> Result<()> { fn test_function_wrap() -> Result<()> {
let lua = Lua::new(); let lua = Lua::new();
let f = Function::wrap(|s: String, n| Ok(s.to_str().unwrap().repeat(n))); let f = Function::wrap(|s: LuaString, n| Ok(s.to_str().unwrap().repeat(n)));
lua.globals().set("f", f)?; lua.globals().set("f", f)?;
lua.load(r#"assert(f("hello", 2) == "hellohello")"#) lua.load(r#"assert(f("hello", 2) == "hellohello")"#)
.exec() .exec()
+1 -1
View File
@@ -274,7 +274,7 @@ fn test_hook_yield() -> Result<()> {
co.set_hook(HookTriggers::EVERY_LINE, move |_lua, _debug| Ok(VmState::Yield))?; co.set_hook(HookTriggers::EVERY_LINE, move |_lua, _debug| Ok(VmState::Yield))?;
#[cfg(any(feature = "lua54", feature = "lua53"))] #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53"))]
{ {
assert!(co.resume::<()>(()).is_ok()); assert!(co.resume::<()>(()).is_ok());
assert!(co.resume::<()>(()).is_ok()); assert!(co.resume::<()>(()).is_ok());
+2 -2
View File
@@ -3,8 +3,8 @@
use std::cell::Cell; use std::cell::Cell;
use std::fmt::Debug; use std::fmt::Debug;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicU64, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicU64, Ordering};
use mlua::{ use mlua::{
Compiler, Error, Function, Lua, LuaOptions, Result, StdLib, Table, ThreadStatus, Value, Vector, VmState, Compiler, Error, Function, Lua, LuaOptions, Result, StdLib, Table, ThreadStatus, Value, Vector, VmState,
@@ -448,7 +448,7 @@ fn test_loadstring() -> Result<()> {
assert_eq!(f.call::<i32>(())?, 123); assert_eq!(f.call::<i32>(())?, 123);
let err = lua let err = lua
.load(r#"loadstring("retur 123", "chunk")"#) .load(r#"loadstring("retur 123", "chunk")"#) // typos:ignore
.exec() .exec()
.err() .err()
.unwrap(); .unwrap();
+12 -6
View File
@@ -42,8 +42,10 @@ fn test_require_errors() {
// Pass non-string to require // Pass non-string to require
let res = run_require(&lua, true); let res = run_require(&lua, true);
assert!(res.is_err()); assert!(res.is_err());
assert!((res.unwrap_err().to_string()) assert!(
.contains("bad argument #1 to 'require' (string expected, got boolean)")); (res.unwrap_err().to_string())
.contains("bad argument #1 to 'require' (string expected, got boolean)")
);
// Require from loadstring // Require from loadstring
let res = lua let res = lua
@@ -169,8 +171,10 @@ fn test_require_without_config() {
"./tests/luau/require/without_config/ambiguous_file_requirer", "./tests/luau/require/without_config/ambiguous_file_requirer",
); );
assert!(res.is_err()); assert!(res.is_err());
assert!((res.unwrap_err().to_string()) assert!(
.contains("could not resolve child component \"dependency\" (ambiguous)")); (res.unwrap_err().to_string())
.contains("could not resolve child component \"dependency\" (ambiguous)")
);
// RequireWithDirectoryAmbiguity // RequireWithDirectoryAmbiguity
let res = run_require( let res = run_require(
@@ -178,8 +182,10 @@ fn test_require_without_config() {
"./tests/luau/require/without_config/ambiguous_directory_requirer", "./tests/luau/require/without_config/ambiguous_directory_requirer",
); );
assert!(res.is_err()); assert!(res.is_err());
assert!((res.unwrap_err().to_string()) assert!(
.contains("could not resolve child component \"dependency\" (ambiguous)")); (res.unwrap_err().to_string())
.contains("could not resolve child component \"dependency\" (ambiguous)")
);
// CheckCachedResult // CheckCachedResult
let res = run_require(&lua, "./tests/luau/require/without_config/validate_cache").unwrap(); let res = run_require(&lua, "./tests/luau/require/without_config/validate_cache").unwrap();
+8 -2
View File
@@ -72,13 +72,19 @@ fn test_gc_control() -> Result<()> {
let lua = Lua::new(); let lua = Lua::new();
let globals = lua.globals(); let globals = lua.globals();
#[cfg(feature = "lua54")] #[cfg(any(feature = "lua55", feature = "lua54"))]
{ {
assert_eq!(lua.gc_gen(0, 0), GCMode::Incremental); assert_eq!(lua.gc_gen(0, 0), GCMode::Incremental);
assert_eq!(lua.gc_inc(0, 0, 0), GCMode::Generational); assert_eq!(lua.gc_inc(0, 0, 0), GCMode::Generational);
} }
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52", feature = "luau"))] #[cfg(any(
feature = "lua55",
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luau"
))]
{ {
assert!(lua.gc_is_running()); assert!(lua.gc_is_running());
lua.gc_stop(); lua.gc_stop();
+1
View File
@@ -13,6 +13,7 @@ members = [
] ]
[features] [features]
lua55 = ["mlua/lua55"]
lua54 = ["mlua/lua54"] lua54 = ["mlua/lua54"]
lua53 = ["mlua/lua53"] lua53 = ["mlua/lua53"]
lua52 = ["mlua/lua52"] lua52 = ["mlua/lua52"]
+1
View File
@@ -5,6 +5,7 @@ authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
edition = "2021" edition = "2021"
[features] [features]
lua55 = ["mlua/lua55"]
lua54 = ["mlua/lua54"] lua54 = ["mlua/lua54"]
lua53 = ["mlua/lua53"] lua53 = ["mlua/lua53"]
lua52 = ["mlua/lua52"] lua52 = ["mlua/lua52"]
+2
View File
@@ -42,6 +42,7 @@ fn test_module_error() -> Result<()> {
} }
#[cfg(any( #[cfg(any(
feature = "lua55",
feature = "lua54", feature = "lua54",
feature = "lua53", feature = "lua53",
feature = "lua52", feature = "lua52",
@@ -70,6 +71,7 @@ fn test_module_from_thread() -> Result<()> {
} }
#[cfg(any( #[cfg(any(
feature = "lua55",
feature = "lua54", feature = "lua54",
feature = "lua53", feature = "lua53",
feature = "lua52", feature = "lua52",
+4 -2
View File
@@ -1,4 +1,6 @@
use mlua::{Error, ExternalError, Integer, IntoLuaMulti, Lua, MultiValue, Result, String, Value, Variadic}; use mlua::{
Error, ExternalError, Integer, IntoLuaMulti, Lua, LuaString, MultiValue, Result, Value, Variadic,
};
#[test] #[test]
fn test_result_conversions() -> Result<()> { fn test_result_conversions() -> Result<()> {
@@ -81,7 +83,7 @@ fn test_multivalue_by_ref() -> Result<()> {
Value::Boolean(true), Value::Boolean(true),
]); ]);
let f = lua.create_function(|_, (i, s, b): (i32, String, bool)| { let f = lua.create_function(|_, (i, s, b): (i32, LuaString, bool)| {
assert_eq!(i, 3); assert_eq!(i, 3);
assert_eq!(s.to_str()?, "hello"); assert_eq!(s.to_str()?, "hello");
assert_eq!(b, true); assert_eq!(b, true);
+7 -8
View File
@@ -1,10 +1,9 @@
use std::cell::Cell; use std::cell::Cell;
use std::rc::Rc; use std::rc::Rc;
use std::string::String as StdString;
use std::sync::Arc; use std::sync::Arc;
use mlua::{ use mlua::{
AnyUserData, Error, Function, Lua, MetaMethod, ObjectLike, Result, String, UserData, UserDataFields, AnyUserData, Error, Function, Lua, LuaString, MetaMethod, ObjectLike, Result, UserData, UserDataFields,
UserDataMethods, UserDataRegistry, UserDataMethods, UserDataRegistry,
}; };
@@ -437,15 +436,15 @@ fn test_scope_userdata_ref_mut() -> Result<()> {
fn test_scope_any_userdata() -> Result<()> { fn test_scope_any_userdata() -> Result<()> {
let lua = Lua::new(); let lua = Lua::new();
fn register(reg: &mut UserDataRegistry<&mut StdString>) { fn register(reg: &mut UserDataRegistry<&mut String>) {
reg.add_method_mut("push", |_, this, s: String| { reg.add_method_mut("push", |_, this, s: LuaString| {
this.push_str(&s.to_str()?); this.push_str(&s.to_str()?);
Ok(()) Ok(())
}); });
reg.add_meta_method("__tostring", |_, data, ()| Ok((*data).clone())); reg.add_meta_method("__tostring", |_, data, ()| Ok((*data).clone()));
} }
let mut data = StdString::from("foo"); let mut data = String::from("foo");
lua.scope(|scope| { lua.scope(|scope| {
let ud = scope.create_any_userdata(&mut data, register)?; let ud = scope.create_any_userdata(&mut data, register)?;
lua.globals().set("ud", ud)?; lua.globals().set("ud", ud)?;
@@ -527,11 +526,11 @@ fn test_scope_any_userdata_ref_mut() -> Result<()> {
fn test_scope_destructors() -> Result<()> { fn test_scope_destructors() -> Result<()> {
let lua = Lua::new(); let lua = Lua::new();
lua.register_userdata_type::<Arc<StdString>>(|reg| { lua.register_userdata_type::<Arc<String>>(|reg| {
reg.add_meta_method("__tostring", |_, data, ()| Ok(data.to_string())); reg.add_meta_method("__tostring", |_, data, ()| Ok(data.to_string()));
})?; })?;
let arc_str = Arc::new(StdString::from("foo")); let arc_str = Arc::new(String::from("foo"));
let ud = lua.create_any_userdata(arc_str.clone())?; let ud = lua.create_any_userdata(arc_str.clone())?;
lua.scope(|scope| { lua.scope(|scope| {
@@ -544,7 +543,7 @@ fn test_scope_destructors() -> Result<()> {
// Try destructing the userdata while it's borrowed // Try destructing the userdata while it's borrowed
let ud = lua.create_any_userdata(arc_str.clone())?; let ud = lua.create_any_userdata(arc_str.clone())?;
ud.borrow_scoped::<Arc<StdString>, _>(|arc_str| { ud.borrow_scoped::<Arc<String>, _>(|arc_str| {
assert_eq!(arc_str.as_str(), "foo"); assert_eq!(arc_str.as_str(), "foo");
lua.scope(|scope| { lua.scope(|scope| {
scope.add_destructor(|| { scope.add_destructor(|| {
+6 -6
View File
@@ -2,7 +2,6 @@
use std::cell::UnsafeCell; use std::cell::UnsafeCell;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::string::String as StdString;
use mlua::{AnyUserData, Error, Lua, ObjectLike, Result, UserData, UserDataMethods, UserDataRef}; use mlua::{AnyUserData, Error, Lua, ObjectLike, Result, UserData, UserDataMethods, UserDataRef};
use static_assertions::{assert_impl_all, assert_not_impl_all}; use static_assertions::{assert_impl_all, assert_not_impl_all};
@@ -12,7 +11,7 @@ fn test_userdata_multithread_access_send_only() -> Result<()> {
let lua = Lua::new(); let lua = Lua::new();
// This type is `Send` but not `Sync`. // This type is `Send` but not `Sync`.
struct MyUserData(StdString, PhantomData<UnsafeCell<()>>); struct MyUserData(String, PhantomData<UnsafeCell<()>>);
assert_impl_all!(MyUserData: Send); assert_impl_all!(MyUserData: Send);
assert_not_impl_all!(MyUserData: Sync); assert_not_impl_all!(MyUserData: Sync);
@@ -47,13 +46,12 @@ fn test_userdata_multithread_access_send_only() -> Result<()> {
Ok(()) Ok(())
} }
#[rustversion::stable]
#[test] #[test]
fn test_userdata_multithread_access_sync() -> Result<()> { fn test_userdata_multithread_access_sync() -> Result<()> {
let lua = Lua::new(); let lua = Lua::new();
// This type is `Send` and `Sync`. // This type is `Send` and `Sync`.
struct MyUserData(StdString); struct MyUserData(String);
assert_impl_all!(MyUserData: Send, Sync); assert_impl_all!(MyUserData: Send, Sync);
impl UserData for MyUserData { impl UserData for MyUserData {
@@ -76,11 +74,13 @@ fn test_userdata_multithread_access_sync() -> Result<()> {
std::thread::scope(|s| { std::thread::scope(|s| {
s.spawn(|| { s.spawn(|| {
// Getting another shared reference for `Sync` type is allowed. // Getting another shared reference for `Sync` type is allowed.
let _ = lua.globals().get::<UserDataRef<MyUserData>>("ud").unwrap(); // FIXME: does not work due to https://github.com/rust-lang/rust/pull/135634
// let _ = lua.globals().get::<UserDataRef<MyUserData>>("ud").unwrap();
}); });
}); });
lua.load("ud:method()").exec().unwrap(); // FIXME: does not work due to https://github.com/rust-lang/rust/pull/135634
// lua.load("ud:method()").exec().unwrap();
Ok(()) Ok(())
} }
+4 -4
View File
@@ -36,7 +36,7 @@ fn test_serialize() -> Result<(), Box<dyn StdError>> {
_integer = 123, _integer = 123,
_number = 321.99, _number = 321.99,
_string = "test string serialization", _string = "test string serialization",
_table_arr = {nil, "value 1", nil, "value 2", {}}, _table_arr = {null, "value 1", 2, "value 3", {}},
_table_map = {["table"] = "map", ["null"] = null}, _table_map = {["table"] = "map", ["null"] = null},
_bytes = "\240\040\140\040", _bytes = "\240\040\140\040",
_userdata = ud, _userdata = ud,
@@ -53,7 +53,7 @@ fn test_serialize() -> Result<(), Box<dyn StdError>> {
"_integer": 123, "_integer": 123,
"_number": 321.99, "_number": 321.99,
"_string": "test string serialization", "_string": "test string serialization",
"_table_arr": [null, "value 1", null, "value 2", {}], "_table_arr": [null, "value 1", 2, "value 3", {}],
"_table_map": {"table": "map", "null": null}, "_table_map": {"table": "map", "null": null},
"_bytes": [240, 40, 140, 40], "_bytes": [240, 40, 140, 40],
"_userdata": [123, "test userdata"], "_userdata": [123, "test userdata"],
@@ -184,7 +184,7 @@ fn test_serialize_sorted() -> LuaResult<()> {
_integer = 123, _integer = 123,
_number = 321.99, _number = 321.99,
_string = "test string serialization", _string = "test string serialization",
_table_arr = {nil, "value 1", nil, "value 2", {}}, _table_arr = {null, "value 1", 2, "value 3", {}},
_table_map = {["table"] = "map", ["null"] = null}, _table_map = {["table"] = "map", ["null"] = null},
_bytes = "\240\040\140\040", _bytes = "\240\040\140\040",
_null = null, _null = null,
@@ -198,7 +198,7 @@ fn test_serialize_sorted() -> LuaResult<()> {
let json = serde_json::to_string(&value.to_serializable().sort_keys(true)).unwrap(); let json = serde_json::to_string(&value.to_serializable().sort_keys(true)).unwrap();
assert_eq!( assert_eq!(
json, json,
r#"{"_bool":true,"_bytes":[240,40,140,40],"_empty_array":[],"_empty_map":{},"_integer":123,"_null":null,"_number":321.99,"_string":"test string serialization","_table_arr":[null,"value 1",null,"value 2",{}],"_table_map":{"null":null,"table":"map"}}"# r#"{"_bool":true,"_bytes":[240,40,140,40],"_empty_array":[],"_empty_map":{},"_integer":123,"_null":null,"_number":321.99,"_string":"test string serialization","_table_arr":[null,"value 1",2,"value 3",{}],"_table_map":{"null":null,"table":"map"}}"#
); );
Ok(()) Ok(())
+25 -10
View File
@@ -1,11 +1,11 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashSet; use std::collections::HashSet;
use mlua::{Lua, Result, String}; use mlua::{Lua, LuaString, Result};
#[test] #[test]
fn test_string_compare() { fn test_string_compare() {
fn with_str<F: FnOnce(String)>(s: &str, f: F) { fn with_str<F: FnOnce(LuaString)>(s: &str, f: F) {
f(Lua::new().create_string(s).unwrap()); f(Lua::new().create_string(s).unwrap());
} }
@@ -42,9 +42,9 @@ fn test_string_views() -> Result<()> {
.exec()?; .exec()?;
let globals = lua.globals(); let globals = lua.globals();
let ok: String = globals.get("ok")?; let ok: LuaString = globals.get("ok")?;
let err: String = globals.get("err")?; let err: LuaString = globals.get("err")?;
let empty: String = globals.get("empty")?; let empty: LuaString = globals.get("empty")?;
assert_eq!(ok.to_str()?, "null bytes are valid utf-8, wh\0 knew?"); assert_eq!(ok.to_str()?, "null bytes are valid utf-8, wh\0 knew?");
assert_eq!(ok.to_string_lossy(), "null bytes are valid utf-8, wh\0 knew?"); assert_eq!(ok.to_string_lossy(), "null bytes are valid utf-8, wh\0 knew?");
@@ -74,7 +74,7 @@ fn test_string_from_bytes() -> Result<()> {
fn test_string_hash() -> Result<()> { fn test_string_hash() -> Result<()> {
let lua = Lua::new(); let lua = Lua::new();
let set: HashSet<String> = lua.load(r#"{"hello", "world", "abc", 321}"#).eval()?; let set: HashSet<LuaString> = lua.load(r#"{"hello", "world", "abc", 321}"#).eval()?;
assert_eq!(set.len(), 4); assert_eq!(set.len(), 4);
assert!(set.contains(&lua.create_string("hello")?)); assert!(set.contains(&lua.create_string("hello")?));
assert!(set.contains(&lua.create_string("world")?)); assert!(set.contains(&lua.create_string("world")?));
@@ -133,13 +133,13 @@ fn test_string_display() -> Result<()> {
fn test_string_wrap() -> Result<()> { fn test_string_wrap() -> Result<()> {
let lua = Lua::new(); let lua = Lua::new();
let s = String::wrap("hello, world"); let s = LuaString::wrap("hello, world");
lua.globals().set("s", s)?; lua.globals().set("s", s)?;
assert_eq!(lua.globals().get::<String>("s")?, "hello, world"); assert_eq!(lua.globals().get::<LuaString>("s")?, "hello, world");
let s2 = String::wrap("hello, world (owned)".to_string()); let s2 = LuaString::wrap("hello, world (owned)".to_string());
lua.globals().set("s2", s2)?; lua.globals().set("s2", s2)?;
assert_eq!(lua.globals().get::<String>("s2")?, "hello, world (owned)"); assert_eq!(lua.globals().get::<LuaString>("s2")?, "hello, world (owned)");
Ok(()) Ok(())
} }
@@ -157,3 +157,18 @@ fn test_bytes_into_iter() -> Result<()> {
Ok(()) Ok(())
} }
#[cfg(feature = "lua55")]
#[test]
fn test_external_string() -> Result<()> {
let lua = Lua::new();
let s = lua.create_external_string(b"abc\0")?;
assert_eq!(
s.as_bytes(),
b"abc\0",
"Trailing null byte should be preserved if present explicitly"
);
Ok(())
}

Some files were not shown because too many files have changed in this diff Show More