Compare commits

...

20 Commits

Author SHA1 Message Date
Alex Orlenko cdc1c8415e v0.9.0-rc.2 2023-07-28 00:24:37 +01:00
Alex Orlenko f2142731fd mlua-sys: v0.3.0 2023-07-28 00:23:49 +01:00
Alex Orlenko 1dd62c5ffc mlua_derive: v0.9.0-rc.2 2023-07-28 00:23:04 +01:00
Alex Orlenko 95d8b2fd0f Update v0.9 release notes 2023-07-28 00:22:28 +01:00
Alex Orlenko 51a2959312 Add v0.9 release notes
Prepare v0.9-rc.2 release
2023-07-28 00:07:31 +01:00
Alex Orlenko 28bcc73f2c Move impl IntoLua for WrappedFunction to the function.rs file 2023-07-27 15:19:34 +01:00
Alex Orlenko 8b71f94141 Fix AsChunk trait to support capturing wrapped Lua types (AnyUserData::wrap() and Function::wrap()).
This is a breaking change, the `'lua` lifetime used to in environment moved to the trait declaration.
2023-07-27 13:56:48 +01:00
Alex Orlenko 3bda1351c3 Fix lua51/52 case in userdata tests 2023-07-26 23:18:30 +01:00
Alex Orlenko 4daa631178 Set __type metatable field for Luau instead of __name.
Other Lua versions continue to use `__name` field.
Also make `MetaMethod` enum non-exhaustive (and add `Type` variant)
Closes #295
2023-07-26 21:43:26 +01:00
Alex Orlenko 9f5325ef2f Use c-unwind ABI (Rust 1.71+) 2023-07-22 23:54:30 +01:00
Alex Orlenko 6fb65a8fbe Fix loading luau code starting with \t 2023-07-22 18:44:44 +01:00
Alex Orlenko f6dff65d9b Do not rely on vendored feature when testing luajit memory limit 2023-07-21 23:25:28 +01:00
Alex Orlenko 4fa9aa1e5b Pin lua-src and luajit-src versions 2023-07-21 23:22:47 +01:00
Alex Orlenko e1c075fa51 Use giraffate/clippy-action 2023-07-21 10:34:29 +01:00
Alex Orlenko df9251fb52 Support LUA_LIB_NAME in module mode for windows.
In this mode we will link with the particular lua library.
2023-07-21 10:34:26 +01:00
Alex Orlenko ead6be4a52 Make module and vendored features mutually exclusive 2023-07-20 23:23:03 +01:00
Alex Orlenko 4f48c7e5dc Update README 2023-07-20 21:58:01 +01:00
Alex Orlenko fac39a2f46 Drop openresty specific luajit extensions 2023-07-20 01:02:23 +01:00
Alex Orlenko 483e6be207 Support vendored module mode for windows (raw-dylib linking)
This is requires Rust 1.71+
2023-07-20 00:43:57 +01:00
Alex Orlenko 0e030d21b0 Add #[derive(FromLua)] macro to opt-in into FromLua<T> where T: 'static + Clone (userdata type).
Future macro implementations will allow making T from Lua tables/other values.
Relates to #291.
2023-07-16 01:57:28 +01:00
51 changed files with 837 additions and 393 deletions
+4 -4
View File
@@ -218,7 +218,7 @@ jobs:
- run: cargo fmt -- --check
clippy:
name: Clippy check
name: Clippy
runs-on: ubuntu-22.04
strategy:
matrix:
@@ -229,7 +229,7 @@ jobs:
with:
toolchain: nightly
components: clippy
- uses: actions-rs/clippy-check@v1
- uses: giraffate/clippy-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot,unstable"
reporter: 'github-pr-review'
clippy_flags: --features "${{ matrix.lua }},vendored,async,send,serialize,macros,parking_lot,unstable"
+8
View File
@@ -1,3 +1,11 @@
## v0.9.0-rc.2
- Added `#[derive(FromLua)]` macro to opt-in into `FromLua<T> where T: 'static + Clone` (userdata type).
- Support vendored module mode for windows (raw-dylib linking, Rust 1.71+)
- `module` and `vendored` features are now mutually exclusive
- Use `C-unwind` ABI (Rust 1.71+)
- Changed `AsChunk` trait to support capturing wrapped Lua types
## v0.9.0-rc.1
- `UserDataMethods::add_async_method()` takes `&T` instead of cloning `T`
+4 -3
View File
@@ -1,7 +1,8 @@
[package]
name = "mlua"
version = "0.9.0-rc.1" # remember to update mlua_derive
version = "0.9.0-rc.2" # remember to update mlua_derive
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@chucklefish.org>"]
rust-version = "1.71"
edition = "2021"
repository = "https://github.com/khvzak/mlua"
documentation = "https://docs.rs/mlua"
@@ -43,7 +44,7 @@ macros = ["mlua_derive/macros"]
unstable = []
[dependencies]
mlua_derive = { version = "=0.9.0-rc.1", optional = true, path = "mlua_derive" }
mlua_derive = { version = "=0.9.0-rc.2", optional = true, path = "mlua_derive" }
bstr = { version = "1.0", features = ["std"], default_features = false }
once_cell = { version = "1.0" }
num-traits = { version = "0.2.14" }
@@ -54,7 +55,7 @@ erased-serde = { version = "0.3", optional = true }
serde-value = { version = "0.7", optional = true }
parking_lot = { version = "0.12", optional = true }
ffi = { package = "mlua-sys", version = "0.2.1", path = "mlua-sys" }
ffi = { package = "mlua-sys", version = "0.3.0", path = "mlua-sys" }
[dev-dependencies]
rustyline = "12.0"
+10 -10
View File
@@ -9,7 +9,7 @@
[docs.rs]: https://docs.rs/mlua
[Coverage Status]: https://codecov.io/gh/khvzak/mlua/branch/master/graph/badge.svg?token=99339FS1CG
[codecov.io]: https://codecov.io/gh/khvzak/mlua
[MSRV]: https://img.shields.io/badge/rust-1.63+-brightgreen.svg?&logo=rust
[MSRV]: https://img.shields.io/badge/rust-1.71+-brightgreen.svg?&logo=rust
[Guided Tour] | [Benchmarks] | [FAQ]
@@ -20,6 +20,8 @@
> **Note**
>
> Please see the [v0.8](https://github.com/khvzak/mlua/tree/v0.8) branch for the stable versions of `mlua` released to crates.io.
>
> v0.9 release notes can be found [here](docs/release_notes/v0.9.md).
`mlua` is bindings to [Lua](https://www.lua.org) programming language for Rust with a goal to provide
_safe_ (as far as it's possible), high level, easy to use, practical and flexible API.
@@ -98,12 +100,12 @@ You have to enable one of the features: `lua54`, `lua53`, `lua52`, `lua51`, `lua
By default `mlua` uses `pkg-config` tool to find lua includes and libraries for the chosen Lua version.
In most cases it works as desired, although sometimes could be more preferable to use a custom lua library.
To achieve this, mlua supports `LUA_INC`, `LUA_LIB`, `LUA_LIB_NAME` and `LUA_LINK` environment variables.
To achieve this, mlua supports `LUA_LIB`, `LUA_LIB_NAME` and `LUA_LINK` environment variables.
`LUA_LINK` is optional and may be `dylib` (a dynamic library) or `static` (a static library, `.a` archive).
An example how to use them:
``` sh
my_project $ LUA_INC=$HOME/tmp/lua-5.2.4/src LUA_LIB=$HOME/tmp/lua-5.2.4/src LUA_LIB_NAME=lua LUA_LINK=static cargo build
my_project $ LUA_LIB=$HOME/tmp/lua-5.2.4/src LUA_LIB_NAME=lua LUA_LINK=static cargo build
```
`mlua` also supports vendored lua/luajit using the auxiliary crates [lua-src](https://crates.io/crates/lua-src) and
@@ -117,7 +119,7 @@ Add to `Cargo.toml` :
``` toml
[dependencies]
mlua = { version = "0.8", features = ["lua54", "vendored"] }
mlua = { version = "0.9.0-rc.2", features = ["lua54", "vendored"] }
```
`main.rs`
@@ -152,7 +154,7 @@ Add to `Cargo.toml` :
crate-type = ["cdylib"]
[dependencies]
mlua = { version = "0.8", features = ["lua54", "vendored", "module"] }
mlua = { version = "0.9.0-rc.2", features = ["lua54", "vendored", "module"] }
```
`lib.rs` :
@@ -197,13 +199,11 @@ rustflags = [
]
```
On Linux you can build modules normally with `cargo build --release`.
Vendored and non-vendored builds are supported for these OS.
On Windows `vendored` mode for modules is not supported since you need to link to a Lua dll.
Easiest way is to use either MinGW64 (as part of [MSYS2](https://github.com/msys2/msys2) package) with `pkg-config` or
MSVC with `LUA_INC` / `LUA_LIB` / `LUA_LIB_NAME` environment variables.
On Windows the target module will be linked with `lua5x.dll` library (depending on your feature flags).
Your main application should provide this library.
More details about compiling and linking Lua modules can be found on the [Building Modules](http://lua-users.org/wiki/BuildingModules) page.
Module builds don't require Lua lib or headers to be installed on the system.
### Publishing to luarocks.org
+364
View File
@@ -0,0 +1,364 @@
## mlua v0.9 release notes
The v0.9 version of mlua is a major release that includes a number of API changes and improvements. This release is a stepping stone towards the v1.0.
This document highlights the most important changes. For a full list of changes, see the [CHANGELOG].
[CHANGELOG]: https://github.com/khvzak/mlua/blob/master/CHANGELOG.md
### New features
#### 1. New Any UserData API
This is a long awaited feature that allows to register in Lua foreign types that cannot implement `UserData` trait because of the Rust orphan rules.
Now you can register any type that implements [`Any`] trait as a userdata type.
Consider the following example:
```rust
lua.register_userdata_type::<std::string::String>(|reg| {
reg.add_method("len", |_, this, ()| Ok(this.len()));
reg.add_method_mut("push", |_, this, s: String| {
this.push_str(&s);
Ok(())
});
reg.add_meta_method(MetaMethod::ToString, |lua, this, ()| lua.create_string(this));
})?;
let s = lua.create_any_userdata("hello".to_string())?;
lua.load(chunk! {
print("s:len() is " .. $s:len())
$s:push(" world")
// Prints: hello, world
print($s)
})
.exec()?;
```
In this example we registered [`std::string::String`] as a userdata type with a set of methods and then created an instance of this type in Lua.
It's _not_ required to register a type before using the `Lua::create_any_userdata()` method, instead an empty metatable will be created for you.
You can also register the same type multiple times with different methods. Any previously created instances will share the old metatable, while new instances will have the new one.
The new set of API is called `any_userdata` because it allows to register types that implements [`Any`] trait.
[`std::string::String`]: https://doc.rust-lang.org/stable/std/string/struct.String.html
[`Any`]: https://doc.rust-lang.org/stable/std/any/trait.Any.html
#### 2. Scope support for the new any userdata types
When you need to create non-static userdata instances in Lua, the usual way is use `Lua::scope()` helper to make them scoped. When out of scope, any scoped objects will be automatically
dropped. The only downside of this approach is that every new instance will have a new metatable. This is not very fast if you need to create a lot of instances.
With the new Any UserData API, you can place non-static references `&T` where `T: 'static` into a scope and they will share a single static metatable.
```rust
lua.register_userdata_type::<std::string::String>(|reg| {
reg.add_method_mut("replace", |_, this, (pat, to): (String, String)| {
*this = this.replace(&pat, &to);
Ok(())
});
reg.add_meta_method(MetaMethod::ToString, |lua, this, ()| lua.create_string(this));
})?;
let mut s = "hello, world".to_string();
lua.scope(|scope| {
// This userdata instance holds only a mutable reference to our string
let ud = scope.create_any_userdata_ref_mut(&mut s)?;
lua.load(chunk! {
$ud:replace("world", "user")
})
.exec()
})?;
// Prints: hello, user!
println!("{s}!");
```
#### 3. Owned types (`unstable`)
One of the common questions was how to embed a Lua type into Rust struct to use it later. It was non-trivial to do because of the `'lua` lifetime attached to every Lua value.
In v0.9 mlua introduces "owned" types `OwnedTable`/`OwnedFunction`/`OwnedString`/`OwnedAnyUserData` that are `'static` (no lifetime attached).
```rust
let lua = Lua::new();
struct MyStruct {
table: OwnedTable,
func: OwnedFunction,
}
let my_struct = MyStruct {
table: lua.globals().into_owned(),
func: lua
.create_function(|_, t: Table| Ok(format!("{t:#?}")))?
.into_owned(),
};
// It's safe to drop Lua!
drop(lua);
let result = my_struct.func.call::<_, String>(my_struct.table)?;
println!("{result}");
```
Prior to v0.9, it was possible to do by creating a reference to the Lua value in registry using `Lua::create_registry_value()`
and retrieving value later using `Lua::registry_value()` method.
All owned handles hold a *strong* reference to the current Lua instance.
Be warned, if you place them into a Lua type (eg. `UserData` or a Rust callback), it is *very easy*
to accidentally cause reference cycles that would prevent destroying Lua instance.
Please note this functionality is available under the `unstable` feature flag and not available when the `send` feature is enabled.
#### New ffi module
In v0.9 release the internal `ffi` module has been moved into the new [`mlua-sys`] crate and became available for public use.
This crate provides unified Lua FFI API (targeting Lua 5.4) using a (limited) compatibility layer for older versions.
mlua re-exports the `ffi` module aliasing the `mlua-sys` crate and provides (unsafe) functionality to work with raw Lua state:
```rust
unsafe {
unsafe extern "C-unwind" fn lua_add(state: *mut mlua::lua_State) -> i32 {
let a = mlua::ffi::luaL_checkinteger(state, 1);
let b = mlua::ffi::luaL_checkinteger(state, 2);
mlua::ffi::lua_pushinteger(state, a + b);
1
}
let add = lua.create_c_function(lua_add)?;
assert_eq!(add.call::<_, i32>((2, 3))?, 5);
}
```
[`mlua-sys`]: https://crates.io/crates/mlua-sys
#### Luau JIT support
mlua brings support for the new experimental [Luau] JIT backend under the `luau-jit` feature flag. This backend is still under development and not yet ready for production use.
To enable it, just call `lua.enable_jit(true)` before loading Lua code. mlua will automatically trigger JIT compilation for new Lua chunks.
When calling this function with `false` argument, mlua will disable JIT compilation but any previously compiled chunks will remain JIT-compiled.
[Luau]: https://luau-lang.org
### Improvements
#### 1. Better error reporting
When calling a Rust function from Lua and passing wrong arguments, previous mlua versions reported a error message without any context or reference to the particular argument.
In v0.9 it reports a error message with the argument index and expected type:
```rust
let func = lua.create_function(|_, _a: i32| Ok(()))?;
lua.load(chunk! {
local ok, err = pcall($func, "not a number")
// Prints: bad argument #1: error converting Lua string to i32 (expected number or string coercible to number)
print(err)
})
.exec()?;
```
Similar changes have been made for userdata functions and methods:
```rust
lua.register_userdata_type::<&'static str>(|reg| {
reg.add_method("len", |_, this, ()| Ok(this.len()));
})?;
let s = lua.create_any_userdata("hello")?;
lua.load(chunk! {
local ok, err = pcall($s.len, 123)
// Prints: bad argument `self` to `&str.len`: error converting Lua integer to userdata
print(err)
})
.exec()?;
```
#### 2. Error context
Similar to the [`anyhow`] Error type, now it's possible to attach context to Lua errors:
```rust
let read = lua.create_function(|lua, path: String| {
let bytes = std::fs::read(&path)
.into_lua_err()
.context(format!("Failed to open `{path}`"))?;
Ok(lua.create_string(bytes))
})?;
lua.load(chunk! {
local ok, err = pcall($read, "/nonexistent")
print(err)
})
.exec()?;
Prints:
```text
Failed to open /nonexistent
No such file or directory (os error 2)
stack traceback:
...
```
[`anyhow`]: https://crates.io/crates/anyhow
#### 4. New methods `Function::wrap`/`AnyUserData::wrap`
Sometimes it's useful to have `IntoLua` trait implementation for a Rust function or type `T: Any` without needing to call `Lua::create_function()`/`Lua::create_any_userdata()` methods.
Since v0.9 you can call the new methods `Function::wrap()`/`AnyUserData::wrap()` that allows to do this. They return an abstract type that `impl IntoLua`:
```rust
lua.globals().set("print_rust", Function::wrap(|_, s: String| Ok(println!("{}", s))))?;
lua.globals().set("rust_ud", AnyUserData::wrap("hello"))?;
```
In addition there are also `Function::wrap_mut()`/`Function::wrap_async()` methods that allow to wrap mutable and async functions respectively.
For a `T: 'UserData + 'static` the `IntoLua` trait is still always implemented.
#### `UserDataRef` and `UserDataRefMut` type wrappers
The new wrappers `UserDataRef` and `UserDataRefMut` are receivers for userdata type `T` and borrow underlying instance for the lifetime of the wrapper.
```rust
lua.globals()
.set("ud", AnyUserData::wrap("hello".to_string()))?;
let mut ud_mut: UserDataRefMut<String> = lua.globals().get("ud")?;
ud_mut.push_str(", Rust");
drop(ud_mut);
let ud_ref: UserDataRef<String> = lua.globals().get("ud")?;
// Prints: hello, Rust
println!("{}", *ud_ref);
```
In the previous mlua versions the same functionality can be achieved by receiving `AnyUserData` and calling `AnyUserData::borrow()`/`AnyUserData::borrow_mut()` methods.
The new wrappers are identical to Rust [`Ref`]/[`RefMut`] types.
[`Ref`]: https://doc.rust-lang.org/std/cell/struct.Ref.html
[`RefMut`]: https://doc.rust-lang.org/std/cell/struct.RefMut.html
#### New `AnyUserDataExt` trait
Similar to the `TableExt` trait, the `AnyUserDataExt` provides a set of extra methods for the `AnyUserData` type.
1) `AnyUserDataExt::get()/set()` to get/set a value by key from the userdata, assuming it has `__index` metamethod.
2) `AnyUserDataExt::call()` to call the userdata as a function assuming it has `__call` metamethod.
3) `AnyUserData::call_method(name, ...)` to call the userdata method, assuming it has `__index` metamethod and the associated function.
#### Pretty formatting Lua values
`mlua::Value` implements a new format `:#?` that allows to (recursively) pretty print Lua values:
```rust
println!("{:#?}", lua.globals());
```
Prints:
```
{
["_G"] = table: 0x7fa2d0706260,
["_VERSION"] = "Lua 5.4",
["assert"] = function: 0x10451d11d,
["collectgarbage"] = function: 0x10451d198,
["coroutine"] = {
["close"] = function: 0x10451e28f,
...
},
["dofile"] = function: 0x10451d37c,
...
}
```
In addition a new method `Value::to_string()` has been added to convert `Value` to a string (using `__tostring` metamethod if available).
#### Environment for Lua functions
Any Lua functions have an associated environment table that is used to resolve global variables. By default it sets to a Lua globals table.
In the new release it's possible to get or update a function environment using `Function::environment()` or `Function::set_environment()` methods respectively.
```rust
let f = lua.load("return a").into_function()?;
assert_eq!(f.environment(), Some(lua.globals()));
lua.globals().set("a", 1)?;
assert_eq!(f.call::<_, i32>(())?, 1);
f.set_environment(lua.create_table_from([("a", "hello")])?)?;
assert_eq!(f.call::<_, mlua::String>(())?, "hello");
```
#### Performance optimizations
The new mlua version has a number of performance improvements. Please check the [benchmarks results] to see how mlua compares to rlua and rhai.
[benchmarks results]: https://github.com/khvzak/script-bench-rs
### Changes in `module` mode
#### New attributes
The `lua_module` macro now support the following attributes:
- `name=...` - sets name of the module (defaults to the name of the function).
Eg.:
```rust
#[mlua::lua_module(name = "alt_module")]
fn my_module(lua: &Lua) -> LuaResult<LuaTable> {
lua.create_table()
}
```
Under the hood a new function `luaopen_alt_module` will be created for the Lua module loader.
- `skip_memory_check` - skip memory allocation checks for some operations.
In module mode, mlua runs in unknown environment and cannot say are there any memory limits or not. As result, some operations that require memory allocation runs in
protected mode. Setting this attribute will improve performance of such operations with risk of having uncaught exceptions and memory leaks.
#### Improved Windows target
In previous mlua versions, building a Lua module for Windows requires having Lua development libraries installed on the system.
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
`lua54.dll`/`lua53.dll`/`lua52.dll`/`lua51.dll` depending on the enabled Lua version.
You still need to have the dll although, linked to application where the module will be loaded.
### Breaking changes
1) `ToLua`/`ToLuaMulti` traits have been renamed to `IntoLua`/`IntoLuaMulti` respectively (with the methods called `into_lua`/`into_lua_multi`).
The main reason for this change is following the Rust self [convention](https://rust-lang.github.io/rust-clippy/master/index.html#/wrong_self_convention).
2) Removed `FromLua` implementation for `T: UserData + Clone`.
During the usage of mlua, it was found that this implementation is not very useful and prevents custom `FromLua` implementations for `T: UserData`.
It should be a developer decision to opt-in `FromLua` for their `T` if needed rather than having enabled it unconditionally.
To opt-in `FromLua` for `T: Clone` you can use a simple `#[derive(FromLua)]` macro (requires `feature = "macros"`):
```rust
#[derive(Clone, Copy, mlua::FromLua)]
struct MyUserData(i32);
```
`T` is not required to implement `UserData` because of the new relaxed restrictions on userdata types.
+3 -3
View File
@@ -1,6 +1,6 @@
[package]
name = "mlua-sys"
version = "0.2.1"
version = "0.3.0"
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
edition = "2021"
repository = "https://github.com/khvzak/mlua"
@@ -37,6 +37,6 @@ module = []
cc = "1.0"
cfg-if = "1.0"
pkg-config = "0.3.17"
lua-src = { version = ">= 546.0.0, < 550.0.0", optional = true }
luajit-src = { version = ">= 210.4.5, < 220.0.0", optional = true }
lua-src = { version = ">= 546.0.0, < 546.1.0", optional = true }
luajit-src = { version = ">= 210.4.6, < 210.6.0", optional = true }
luau0-src = { version = "0.5.11", optional = true }
+30 -69
View File
@@ -1,91 +1,52 @@
#![allow(dead_code)]
use std::env;
use std::ops::Bound;
use std::path::PathBuf;
fn get_env_var(name: &str) -> String {
match env::var(name) {
Ok(val) => val,
Err(env::VarError::NotPresent) => String::new(),
Err(err) => panic!("cannot get {name}: {err}"),
}
}
pub fn probe_lua() {
let lib_dir = env::var("LUA_LIB").unwrap_or_default();
let lua_lib = env::var("LUA_LIB_NAME").unwrap_or_default();
pub fn probe_lua() -> Option<PathBuf> {
let include_dir = get_env_var("LUA_INC");
let lib_dir = get_env_var("LUA_LIB");
let lua_lib = get_env_var("LUA_LIB_NAME");
println!("cargo:rerun-if-env-changed=LUA_INC");
println!("cargo:rerun-if-env-changed=LUA_LIB");
println!("cargo:rerun-if-env-changed=LUA_LIB_NAME");
println!("cargo:rerun-if-env-changed=LUA_LINK");
let need_lua_lib = cfg!(any(not(feature = "module"), target_os = "windows"));
if !include_dir.is_empty() {
if need_lua_lib {
if lib_dir.is_empty() {
panic!("LUA_LIB is not set");
}
if lua_lib.is_empty() {
panic!("LUA_LIB_NAME is not set");
}
let mut link_lib = "";
if get_env_var("LUA_LINK") == "static" {
link_lib = "static=";
};
if !lua_lib.is_empty() {
if !lib_dir.is_empty() {
println!("cargo:rustc-link-search=native={lib_dir}");
println!("cargo:rustc-link-lib={link_lib}{lua_lib}");
}
return Some(PathBuf::from(include_dir));
let mut link_lib = "";
if env::var("LUA_LINK").as_deref() == Ok("static") {
link_lib = "static=";
};
println!("cargo:rustc-link-lib={link_lib}{lua_lib}");
return;
}
// Find using `pkg-config`
#[cfg(feature = "lua54")]
let (incl_bound, excl_bound, alt_probe, ver) = ("5.4", "5.5", "lua5.4", "5.4");
let (incl_bound, excl_bound, alt_probe, ver) = ("5.4", "5.5", Some("lua5.4"), "5.4");
#[cfg(feature = "lua53")]
let (incl_bound, excl_bound, alt_probe, ver) = ("5.3", "5.4", "lua5.3", "5.3");
let (incl_bound, excl_bound, alt_probe, ver) = ("5.3", "5.4", Some("lua5.3"), "5.3");
#[cfg(feature = "lua52")]
let (incl_bound, excl_bound, alt_probe, ver) = ("5.2", "5.3", "lua5.2", "5.2");
let (incl_bound, excl_bound, alt_probe, ver) = ("5.2", "5.3", Some("lua5.2"), "5.2");
#[cfg(feature = "lua51")]
let (incl_bound, excl_bound, alt_probe, ver) = ("5.1", "5.2", "lua5.1", "5.1");
#[cfg(any(
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "lua51"
))]
{
let mut lua = pkg_config::Config::new()
.range_version((Bound::Included(incl_bound), Bound::Excluded(excl_bound)))
.cargo_metadata(need_lua_lib)
.probe("lua");
if lua.is_err() {
lua = pkg_config::Config::new()
.cargo_metadata(need_lua_lib)
.probe(alt_probe);
}
lua.unwrap_or_else(|_| panic!("cannot find Lua {ver} using `pkg-config`"))
.include_paths
.get(0)
.cloned()
}
let (incl_bound, excl_bound, alt_probe, ver) = ("5.1", "5.2", Some("lua5.1"), "5.1");
#[cfg(feature = "luajit")]
{
let lua = pkg_config::Config::new()
.range_version((Bound::Included("2.0.4"), Bound::Unbounded))
.cargo_metadata(need_lua_lib)
.probe("luajit");
let (incl_bound, excl_bound, alt_probe, ver) = ("2.0.4", "2.2", None, "JIT");
lua.expect("cannot find LuaJIT using `pkg-config`")
.include_paths
.get(0)
.cloned()
#[rustfmt::skip]
let mut lua = pkg_config::Config::new()
.range_version((Bound::Included(incl_bound), Bound::Excluded(excl_bound)))
.cargo_metadata(true)
.probe(if cfg!(feature = "luajit") { "luajit" } else { "lua" });
if lua.is_err() && alt_probe.is_some() {
lua = pkg_config::Config::new()
.cargo_metadata(true)
.probe(alt_probe.unwrap());
}
lua.unwrap_or_else(|err| panic!("cannot find Lua{ver} using `pkg-config`: {err}"));
}
+2 -4
View File
@@ -1,6 +1,6 @@
use std::path::PathBuf;
#![allow(dead_code)]
pub fn probe_lua() -> Option<PathBuf> {
pub fn probe_lua() {
#[cfg(feature = "lua54")]
let artifacts = lua_src::Build::new().build(lua_src::Lua54);
@@ -25,6 +25,4 @@ pub fn probe_lua() -> Option<PathBuf> {
.build();
artifacts.print_cargo_metadata();
Some(artifacts.include_dir().to_owned())
}
+17 -10
View File
@@ -9,18 +9,25 @@ cfg_if::cfg_if! {
}
fn main() {
// We don't support "vendored module" mode on windows
#[cfg(all(feature = "vendored", feature = "module", target_os = "windows"))]
compile_error!(
"Vendored (static) builds are not supported for modules on Windows.\n"
+ "Please, use `pkg-config` or custom mode to link to a Lua dll."
);
#[cfg(all(feature = "luau", feature = "module"))]
compile_error!("Luau does not support module mode");
compile_error!("Luau does not support `module` mode");
#[cfg(any(not(feature = "module"), target_os = "windows"))]
find::probe_lua();
#[cfg(all(feature = "module", feature = "vendored"))]
compile_error!("`vendored` and `module` features are mutually exclusive");
println!("cargo:rerun-if-changed=build");
#[cfg(windows)]
if cfg!(feature = "module") {
if !std::env::var("LUA_LIB_NAME").unwrap_or_default().is_empty() {
// Don't use raw-dylib linking
find::probe_lua();
return;
}
println!("cargo:rustc-cfg=raw_dylib");
}
#[cfg(not(feature = "module"))]
find::probe_lua();
}
+1 -5
View File
@@ -26,14 +26,10 @@ pub use luau::*;
#[doc(hidden)]
pub const LUA_MAX_UPVALUES: c_int = 255;
#[cfg(any(feature = "lua51", all(feature = "luajit", not(feature = "vendored"))))]
#[cfg(any(feature = "lua51", feature = "luajit"))]
#[doc(hidden)]
pub const LUA_MAX_UPVALUES: c_int = 60;
#[cfg(all(feature = "luajit", feature = "vendored"))]
#[doc(hidden)]
pub const LUA_MAX_UPVALUES: c_int = 120;
#[cfg(feature = "luau")]
#[doc(hidden)]
pub const LUA_MAX_UPVALUES: c_int = 200;
+4 -2
View File
@@ -14,7 +14,8 @@ pub struct luaL_Reg {
pub func: lua_CFunction,
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))]
extern "C-unwind" {
pub fn luaL_register(L: *mut lua_State, libname: *const c_char, l: *const luaL_Reg);
#[link_name = "luaL_getmetafield"]
pub fn luaL_getmetafield_(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
@@ -56,7 +57,8 @@ extern "C" {
pub const LUA_NOREF: c_int = -2;
pub const LUA_REFNIL: c_int = -1;
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))]
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);
+17 -17
View File
@@ -73,23 +73,23 @@ pub type lua_Integer = i32;
pub type lua_Integer = i64;
/// Type for native C functions that can be passed to Lua.
pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int;
pub type lua_CFunction = unsafe extern "C-unwind" fn(L: *mut lua_State) -> c_int;
// Type for functions that read/write blocks when loading/dumping Lua chunks
#[rustfmt::skip]
pub type lua_Reader =
unsafe extern "C" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char;
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" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int;
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
pub type lua_Alloc = unsafe extern "C" fn(
ud: *mut c_void,
ptr: *mut c_void,
osize: usize,
nsize: usize,
) -> *mut c_void;
#[rustfmt::skip]
pub type lua_Alloc =
unsafe extern "C-unwind" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void;
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))]
extern "C-unwind" {
//
// State manipulation
//
@@ -97,9 +97,6 @@ extern "C" {
pub fn lua_close(L: *mut lua_State);
pub fn lua_newthread(L: *mut lua_State) -> *mut lua_State;
#[cfg(all(feature = "luajit", feature = "vendored"))]
pub fn lua_resetthread(L: *mut lua_State, th: *mut lua_State);
pub fn lua_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction;
//
@@ -221,14 +218,16 @@ pub const LUA_GCSTEP: c_int = 5;
pub const LUA_GCSETPAUSE: c_int = 6;
pub const LUA_GCSETSTEPMUL: c_int = 7;
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))]
extern "C-unwind" {
pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int;
}
//
// Miscellaneous functions
//
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))]
extern "C-unwind" {
pub fn lua_error(L: *mut lua_State) -> !;
pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_concat(L: *mut lua_State, n: c_int);
@@ -351,9 +350,10 @@ pub const LUA_MASKLINE: c_int = 1 << (LUA_HOOKLINE as usize);
pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
/// Type for functions to be called on debug events.
pub type lua_Hook = unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug);
pub type lua_Hook = unsafe extern "C-unwind" fn(L: *mut lua_State, ar: *mut lua_Debug);
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))]
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;
+2 -1
View File
@@ -20,7 +20,8 @@ pub const LUA_JITLIBNAME: &str = "jit";
#[cfg(feature = "luajit")]
pub const LUA_FFILIBNAME: &str = "ffi";
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua51", kind = "raw-dylib"))]
extern "C-unwind" {
pub fn luaopen_base(L: *mut lua_State) -> c_int;
pub fn luaopen_table(L: *mut lua_State) -> c_int;
pub fn luaopen_io(L: *mut lua_State) -> c_int;
+6 -3
View File
@@ -14,7 +14,8 @@ pub struct luaL_Reg {
pub func: lua_CFunction,
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
extern "C-unwind" {
pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number);
#[link_name = "luaL_getmetafield"]
@@ -65,7 +66,8 @@ extern "C" {
pub const LUA_NOREF: c_int = -2;
pub const LUA_REFNIL: c_int = -1;
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
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);
@@ -78,7 +80,8 @@ pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
luaL_loadfilex(L, f, ptr::null())
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
extern "C-unwind" {
pub fn luaL_loadbufferx(
L: *mut lua_State,
buff: *const c_char,
+24 -21
View File
@@ -78,23 +78,23 @@ pub type lua_Integer = i64;
pub type lua_Unsigned = c_uint;
/// Type for native C functions that can be passed to Lua
pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int;
pub type lua_CFunction = unsafe extern "C-unwind" fn(L: *mut lua_State) -> c_int;
// Type for functions that read/write blocks when loading/dumping Lua chunks
#[rustfmt::skip]
pub type lua_Reader =
unsafe extern "C" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char;
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" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int;
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
pub type lua_Alloc = unsafe extern "C" fn(
ud: *mut c_void,
ptr: *mut c_void,
osize: usize,
nsize: usize,
) -> *mut c_void;
#[rustfmt::skip]
pub type lua_Alloc =
unsafe extern "C-unwind" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void;
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
extern "C-unwind" {
//
// State manipulation
//
@@ -155,20 +155,19 @@ pub const LUA_OPMOD: c_int = 4;
pub const LUA_OPPOW: c_int = 5;
pub const LUA_OPUNM: c_int = 6;
extern "C" {
pub fn lua_arith(L: *mut lua_State, op: c_int);
}
pub const LUA_OPEQ: c_int = 0;
pub const LUA_OPLT: c_int = 1;
pub const LUA_OPLE: c_int = 2;
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
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;
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
extern "C-unwind" {
//
// Push functions (C -> stack)
//
@@ -262,7 +261,8 @@ pub unsafe fn lua_pcall(L: *mut lua_State, n: c_int, r: c_int, f: c_int) -> c_in
lua_pcallk(L, n, r, f, 0, None)
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
extern "C-unwind" {
//
// Coroutine functions
//
@@ -298,11 +298,13 @@ pub const LUA_GCISRUNNING: c_int = 9;
pub const LUA_GCGEN: c_int = 10;
pub const LUA_GCINC: c_int = 11;
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
extern "C-unwind" {
pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int;
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
extern "C-unwind" {
//
// Miscellaneous functions
//
@@ -437,9 +439,10 @@ pub const LUA_MASKLINE: c_int = 1 << (LUA_HOOKLINE as usize);
pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
/// Type for functions to be called on debug events.
pub type lua_Hook = unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug);
pub type lua_Hook = unsafe extern "C-unwind" fn(L: *mut lua_State, ar: *mut lua_Debug);
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
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;
+2 -1
View File
@@ -14,7 +14,8 @@ pub const LUA_MATHLIBNAME: &str = "math";
pub const LUA_DBLIBNAME: &str = "debug";
pub const LUA_LOADLIBNAME: &str = "package";
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua52", kind = "raw-dylib"))]
extern "C-unwind" {
pub fn luaopen_base(L: *mut lua_State) -> c_int;
pub fn luaopen_coroutine(L: *mut lua_State) -> c_int;
pub fn luaopen_table(L: *mut lua_State) -> c_int;
+6 -3
View File
@@ -20,7 +20,8 @@ pub struct luaL_Reg {
pub func: lua_CFunction,
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
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;
@@ -67,7 +68,8 @@ extern "C" {
pub const LUA_NOREF: c_int = -2;
pub const LUA_REFNIL: c_int = -1;
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
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);
@@ -80,7 +82,8 @@ pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
luaL_loadfilex(L, f, ptr::null())
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
extern "C-unwind" {
pub fn luaL_loadbufferx(
L: *mut lua_State,
buff: *const c_char,
+25 -22
View File
@@ -82,27 +82,27 @@ pub type lua_Unsigned = u64;
pub type lua_KContext = isize;
/// Type for native C functions that can be passed to Lua
pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int;
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" fn(L: *mut lua_State, status: c_int, ctx: lua_KContext) -> c_int;
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" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char;
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" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int;
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
pub type lua_Alloc = unsafe extern "C" fn(
ud: *mut c_void,
ptr: *mut c_void,
osize: usize,
nsize: usize,
) -> *mut c_void;
#[rustfmt::skip]
pub type lua_Alloc =
unsafe extern "C-unwind" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void;
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
extern "C-unwind" {
//
// State manipulation
//
@@ -167,20 +167,19 @@ pub const LUA_OPSHR: c_int = 11;
pub const LUA_OPUNM: c_int = 12;
pub const LUA_OPBNOT: c_int = 13;
extern "C" {
pub fn lua_arith(L: *mut lua_State, op: c_int);
}
pub const LUA_OPEQ: c_int = 0;
pub const LUA_OPLT: c_int = 1;
pub const LUA_OPLE: c_int = 2;
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
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;
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
extern "C-unwind" {
//
// Push functions (C -> stack)
//
@@ -270,7 +269,8 @@ pub unsafe fn lua_pcall(L: *mut lua_State, n: c_int, r: c_int, f: c_int) -> c_in
lua_pcallk(L, n, r, f, 0, None)
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
extern "C-unwind" {
//
// Coroutine functions
//
@@ -304,11 +304,13 @@ pub const LUA_GCSETPAUSE: c_int = 6;
pub const LUA_GCSETSTEPMUL: c_int = 7;
pub const LUA_GCISRUNNING: c_int = 9;
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
extern "C-unwind" {
pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int;
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
extern "C-unwind" {
//
// Miscellaneous functions
//
@@ -461,9 +463,10 @@ pub const LUA_MASKLINE: c_int = 1 << (LUA_HOOKLINE as usize);
pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
/// Type for functions to be called on debug events.
pub type lua_Hook = unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug);
pub type lua_Hook = unsafe extern "C-unwind" fn(L: *mut lua_State, ar: *mut lua_Debug);
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
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;
+2 -1
View File
@@ -15,7 +15,8 @@ pub const LUA_MATHLIBNAME: &str = "math";
pub const LUA_DBLIBNAME: &str = "debug";
pub const LUA_LOADLIBNAME: &str = "package";
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua53", kind = "raw-dylib"))]
extern "C-unwind" {
pub fn luaopen_base(L: *mut lua_State) -> c_int;
pub fn luaopen_coroutine(L: *mut lua_State) -> c_int;
pub fn luaopen_table(L: *mut lua_State) -> c_int;
+6 -3
View File
@@ -20,7 +20,8 @@ pub struct luaL_Reg {
pub func: lua_CFunction,
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
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;
@@ -66,7 +67,8 @@ extern "C" {
pub const LUA_NOREF: c_int = -2;
pub const LUA_REFNIL: c_int = -1;
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
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);
@@ -79,7 +81,8 @@ pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
luaL_loadfilex(L, f, ptr::null())
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
extern "C-unwind" {
pub fn luaL_loadbufferx(
L: *mut lua_State,
buff: *const c_char,
+28 -24
View File
@@ -81,31 +81,31 @@ pub type lua_Unsigned = u64;
pub type lua_KContext = isize;
/// Type for native C functions that can be passed to Lua
pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int;
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" fn(L: *mut lua_State, status: c_int, ctx: lua_KContext) -> c_int;
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" fn(L: *mut lua_State, ud: *mut c_void, sz: *mut usize) -> *const c_char;
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" fn(L: *mut lua_State, p: *const c_void, sz: usize, ud: *mut c_void) -> c_int;
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
pub type lua_Alloc = unsafe extern "C" fn(
ud: *mut c_void,
ptr: *mut c_void,
osize: usize,
nsize: usize,
) -> *mut c_void;
#[rustfmt::skip]
pub type lua_Alloc =
unsafe extern "C-unwind" fn(ud: *mut c_void, ptr: *mut c_void, osize: usize, nsize: usize) -> *mut c_void;
/// Type for warning functions
pub type lua_WarnFunction =
unsafe extern "C" fn(ud: *mut c_void, msg: *const c_char, tocont: c_int);
unsafe extern "C-unwind" fn(ud: *mut c_void, msg: *const c_char, tocont: c_int);
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
extern "C-unwind" {
//
// State manipulation
//
@@ -174,20 +174,19 @@ pub const LUA_OPSHR: c_int = 11;
pub const LUA_OPUNM: c_int = 12;
pub const LUA_OPBNOT: c_int = 13;
extern "C" {
pub fn lua_arith(L: *mut lua_State, op: c_int);
}
pub const LUA_OPEQ: c_int = 0;
pub const LUA_OPLT: c_int = 1;
pub const LUA_OPLE: c_int = 2;
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
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;
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
extern "C-unwind" {
//
// Push functions (C -> stack)
//
@@ -277,7 +276,8 @@ pub unsafe fn lua_pcall(L: *mut lua_State, n: c_int, r: c_int, f: c_int) -> c_in
lua_pcallk(L, n, r, f, 0, None)
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
extern "C-unwind" {
//
// Coroutine functions
//
@@ -305,7 +305,8 @@ pub unsafe fn lua_yield(L: *mut lua_State, n: c_int) -> c_int {
//
// Warning-related functions
//
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
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);
}
@@ -325,11 +326,13 @@ pub const LUA_GCISRUNNING: c_int = 9;
pub const LUA_GCGEN: c_int = 10;
pub const LUA_GCINC: c_int = 11;
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
extern "C-unwind" {
pub fn lua_gc(L: *mut lua_State, what: c_int, ...) -> c_int;
}
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
extern "C-unwind" {
//
// Miscellaneous functions
//
@@ -500,9 +503,10 @@ pub const LUA_MASKLINE: c_int = 1 << (LUA_HOOKLINE as usize);
pub const LUA_MASKCOUNT: c_int = 1 << (LUA_HOOKCOUNT as usize);
/// Type for functions to be called on debug events.
pub type lua_Hook = unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug);
pub type lua_Hook = unsafe extern "C-unwind" fn(L: *mut lua_State, ar: *mut lua_Debug);
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
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;
+2 -1
View File
@@ -14,7 +14,8 @@ pub const LUA_MATHLIBNAME: &str = "math";
pub const LUA_DBLIBNAME: &str = "debug";
pub const LUA_LOADLIBNAME: &str = "package";
extern "C" {
#[cfg_attr(all(windows, raw_dylib), link(name = "lua54", kind = "raw-dylib"))]
extern "C-unwind" {
pub fn luaopen_base(L: *mut lua_State) -> c_int;
pub fn luaopen_coroutine(L: *mut lua_State) -> c_int;
pub fn luaopen_table(L: *mut lua_State) -> c_int;
+4 -4
View File
@@ -323,7 +323,7 @@ pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char)
pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int {
if luaL_newmetatable_(L, tname) != 0 {
lua_pushstring(L, tname);
lua_setfield(L, -2, cstr!("__name"));
lua_setfield(L, -2, cstr!("__type"));
1
} else {
0
@@ -341,7 +341,7 @@ pub unsafe fn luaL_loadbufferx(
fn free(p: *mut c_void);
}
let chunk_is_text = size == 0 || (*data as u8) >= b'\n';
let chunk_is_text = size == 0 || (*data as u8) >= b'\t';
if !mode.is_null() {
let modeb = CStr::from_ptr(mode).to_bytes();
if !chunk_is_text && !modeb.contains(&b'b') {
@@ -454,7 +454,7 @@ pub unsafe fn luaL_tolstring(L: *mut lua_State, mut idx: c_int, len: *mut usize)
}
}
t => {
let tt = luaL_getmetafield(L, idx, cstr!("__name"));
let tt = luaL_getmetafield(L, idx, cstr!("__type"));
let name = if tt == LUA_TSTRING {
lua_tostring(L, -1)
} else {
@@ -462,7 +462,7 @@ pub unsafe fn luaL_tolstring(L: *mut lua_State, mut idx: c_int, len: *mut usize)
};
lua_pushfstring(L, cstr!("%s: %p"), name, lua_topointer(L, idx));
if tt != LUA_TNIL {
lua_replace(L, -2); // remove '__name'
lua_replace(L, -2); // remove '__type'
}
}
};
+1 -1
View File
@@ -13,7 +13,7 @@ pub struct luaL_Reg {
pub func: lua_CFunction,
}
extern "C" {
extern "C-unwind" {
pub fn luaL_register(L: *mut lua_State, libname: *const c_char, l: *const luaL_Reg);
#[link_name = "luaL_getmetafield"]
pub fn luaL_getmetafield_(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
+21 -21
View File
@@ -69,15 +69,15 @@ pub type lua_Integer = c_int;
pub type lua_Unsigned = c_uint;
/// Type for native C functions that can be passed to Lua.
pub type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> c_int;
pub type lua_Continuation = unsafe extern "C" fn(L: *mut lua_State, status: c_int) -> c_int;
pub type lua_CFunction = unsafe extern "C-unwind" fn(L: *mut lua_State) -> c_int;
pub type lua_Continuation = unsafe extern "C-unwind" fn(L: *mut lua_State, status: c_int) -> c_int;
/// Type for userdata destructor functions.
pub type lua_Udestructor = unsafe extern "C" fn(*mut c_void);
pub type lua_Destructor = unsafe extern "C" fn(L: *mut lua_State, *mut c_void);
pub type lua_Udestructor = unsafe extern "C-unwind" fn(*mut c_void);
pub type lua_Destructor = unsafe extern "C-unwind" fn(L: *mut lua_State, *mut c_void);
/// Type for memory-allocation functions.
pub type lua_Alloc = unsafe extern "C" fn(
pub type lua_Alloc = unsafe extern "C-unwind" fn(
ud: *mut c_void,
ptr: *mut c_void,
osize: usize,
@@ -89,7 +89,7 @@ pub const fn luau_version() -> Option<&'static str> {
option_env!("LUAU_VERSION")
}
extern "C" {
extern "C-unwind" {
//
// State manipulation
//
@@ -251,14 +251,14 @@ pub const LUA_GCSETGOAL: c_int = 7;
pub const LUA_GCSETSTEPMUL: c_int = 8;
pub const LUA_GCSETSTEPSIZE: c_int = 9;
extern "C" {
extern "C-unwind" {
pub fn lua_gc(L: *mut lua_State, what: c_int, data: c_int) -> c_int;
}
//
// Memory statistics
//
extern "C" {
extern "C-unwind" {
pub fn lua_setmemcat(L: *mut lua_State, category: c_int);
pub fn lua_totalbytes(L: *mut lua_State, category: c_int) -> usize;
}
@@ -266,7 +266,7 @@ extern "C" {
//
// Miscellaneous functions
//
extern "C" {
extern "C-unwind" {
pub fn lua_error(L: *mut lua_State) -> !;
pub fn lua_next(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_rawiter(L: *mut lua_State, idx: c_int, iter: c_int) -> c_int;
@@ -286,7 +286,7 @@ extern "C" {
pub const LUA_NOREF: c_int = -1;
pub const LUA_REFNIL: c_int = 0;
extern "C" {
extern "C-unwind" {
pub fn lua_ref(L: *mut lua_State, idx: c_int) -> c_int;
pub fn lua_unref(L: *mut lua_State, r#ref: c_int);
}
@@ -423,9 +423,9 @@ pub unsafe fn lua_tostring(L: *mut lua_State, i: c_int) -> *const c_char {
const LUA_IDSIZE: usize = 256;
/// Type for functions to be called on debug events.
pub type lua_Hook = unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug);
pub type lua_Hook = unsafe extern "C-unwind" fn(L: *mut lua_State, ar: *mut lua_Debug);
pub type lua_Coverage = unsafe extern "C" fn(
pub type lua_Coverage = unsafe extern "C-unwind" fn(
context: *mut c_void,
function: *const c_char,
linedefined: c_int,
@@ -434,7 +434,7 @@ pub type lua_Coverage = unsafe extern "C" fn(
size: usize,
);
extern "C" {
extern "C-unwind" {
pub fn lua_stackdepth(L: *mut lua_State) -> c_int;
pub fn lua_getinfo(
L: *mut lua_State,
@@ -492,23 +492,23 @@ pub struct lua_Callbacks {
pub userdata: *mut c_void,
/// gets called at safepoints (loop back edges, call/ret, gc) if set
pub interrupt: Option<unsafe extern "C" fn(L: *mut lua_State, gc: c_int)>,
pub interrupt: Option<unsafe extern "C-unwind" fn(L: *mut lua_State, gc: c_int)>,
/// gets called when an unprotected error is raised (if longjmp is used)
pub panic: Option<unsafe extern "C" fn(L: *mut lua_State, errcode: c_int)>,
pub panic: Option<unsafe extern "C-unwind" fn(L: *mut lua_State, errcode: c_int)>,
/// gets called when L is created (LP == parent) or destroyed (LP == NULL)
pub userthread: Option<unsafe extern "C" fn(LP: *mut lua_State, L: *mut lua_State)>,
pub userthread: Option<unsafe extern "C-unwind" fn(LP: *mut lua_State, L: *mut lua_State)>,
/// gets called when a string is created; returned atom can be retrieved via tostringatom
pub useratom: Option<unsafe extern "C" fn(s: *const c_char, l: usize) -> i16>,
pub useratom: Option<unsafe extern "C-unwind" fn(s: *const c_char, l: usize) -> i16>,
/// gets called when BREAK instruction is encountered
pub debugbreak: Option<unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug)>,
pub debugbreak: Option<unsafe extern "C-unwind" fn(L: *mut lua_State, ar: *mut lua_Debug)>,
/// gets called after each instruction in single step mode
pub debugstep: Option<unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug)>,
pub debugstep: Option<unsafe extern "C-unwind" fn(L: *mut lua_State, ar: *mut lua_Debug)>,
/// gets called when thread execution is interrupted by break in another thread
pub debuginterrupt: Option<unsafe extern "C" fn(L: *mut lua_State, ar: *mut lua_Debug)>,
pub debuginterrupt: Option<unsafe extern "C-unwind" fn(L: *mut lua_State, ar: *mut lua_Debug)>,
/// gets called when protected call results in an error
pub debugprotectederror: Option<unsafe extern "C" fn(L: *mut lua_State)>,
pub debugprotectederror: Option<unsafe extern "C-unwind" fn(L: *mut lua_State)>,
}
extern "C" {
+3 -1
View File
@@ -13,7 +13,7 @@ pub struct lua_CompileOptions {
pub mutableGlobals: *mut *const c_char,
}
extern "C" {
extern "C-unwind" {
#[link_name = "luau_compile"]
pub fn luau_compile_(
source: *const c_char,
@@ -21,7 +21,9 @@ extern "C" {
options: *mut lua_CompileOptions,
outsize: *mut usize,
) -> *mut c_char;
}
extern "C" {
fn free(p: *mut c_void);
}
+1 -1
View File
@@ -4,7 +4,7 @@ use std::os::raw::c_int;
use super::lua::lua_State;
extern "C" {
extern "C-unwind" {
pub fn luau_codegen_supported() -> c_int;
pub fn luau_codegen_create(state: *mut lua_State);
pub fn luau_codegen_compile(state: *mut lua_State, idx: c_int);
+1 -1
View File
@@ -13,7 +13,7 @@ pub const LUA_UTF8LIBNAME: &str = "utf8";
pub const LUA_MATHLIBNAME: &str = "math";
pub const LUA_DBLIBNAME: &str = "debug";
extern "C" {
extern "C-unwind" {
pub fn luaopen_base(L: *mut lua_State) -> c_int;
pub fn luaopen_coroutine(L: *mut lua_State) -> c_int;
pub fn luaopen_table(L: *mut lua_State) -> c_int;
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "mlua_derive"
version = "0.9.0-rc.1"
version = "0.9.0-rc.2"
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
edition = "2021"
description = "Procedural macros for the mlua crate."
+32
View File
@@ -0,0 +1,32 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
pub fn from_lua(input: TokenStream) -> TokenStream {
let DeriveInput {
ident, generics, ..
} = parse_macro_input!(input as DeriveInput);
let where_clause = match &generics.where_clause {
Some(where_clause) => quote! { #where_clause, Self: 'static + Clone },
None => quote! { where Self: 'static + Clone },
};
let ident_str = ident.to_string();
quote! {
impl #generics ::mlua::FromLua<'_> for #ident #generics #where_clause {
#[inline]
fn from_lua(value: ::mlua::Value<'_>, lua: &'_ ::mlua::Lua) -> ::mlua::Result<Self> {
match value {
::mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
_ => Err(::mlua::Error::FromLuaConversionError {
from: value.type_name(),
to: #ident_str,
message: None,
}),
}
}
}
}
.into()
}
+19 -12
View File
@@ -59,7 +59,7 @@ pub fn lua_module(attr: TokenStream, item: TokenStream) -> TokenStream {
#func
#[no_mangle]
unsafe extern "C" fn #ext_entrypoint_name(state: *mut ::mlua::lua_State) -> ::std::os::raw::c_int {
unsafe extern "C-unwind" fn #ext_entrypoint_name(state: *mut ::mlua::lua_State) -> ::std::os::raw::c_int {
let lua = ::mlua::Lua::init_from_ptr(state);
if #skip_memory_check {
lua.skip_memory_check(true);
@@ -97,21 +97,20 @@ pub fn chunk(input: TokenStream) -> TokenStream {
let wrapped_code = quote! {{
use ::mlua::{AsChunk, ChunkMode, Lua, Result, Table};
use ::std::borrow::Cow;
use ::std::cell::Cell;
use ::std::io::Result as IoResult;
use ::std::sync::Mutex;
use ::std::marker::PhantomData;
struct InnerChunk<F: for <'a> FnOnce(&'a Lua) -> Result<Table<'a>>>(Mutex<Option<F>>);
struct InnerChunk<'lua, F: FnOnce(&'lua Lua) -> Result<Table<'lua>>>(Cell<Option<F>>, PhantomData<&'lua ()>);
impl<F> AsChunk<'static> for InnerChunk<F>
impl<'lua, F> AsChunk<'lua, 'static> for InnerChunk<'lua, F>
where
F: for <'a> FnOnce(&'a Lua) -> Result<Table<'a>>,
F: FnOnce(&'lua Lua) -> Result<Table<'lua>>,
{
fn environment<'lua>(&self, lua: &'lua Lua) -> Result<Option<Table<'lua>>> {
fn environment(&self, lua: &'lua Lua) -> Result<Option<Table<'lua>>> {
if #caps_len > 0 {
if let Ok(mut make_env) = self.0.lock() {
if let Some(make_env) = make_env.take() {
return make_env(lua).map(Some);
}
if let Some(make_env) = self.0.take() {
return make_env(lua).map(Some);
}
}
Ok(None)
@@ -126,7 +125,7 @@ pub fn chunk(input: TokenStream) -> TokenStream {
}
}
fn annotate<F: for<'a> FnOnce(&'a Lua) -> Result<Table<'a>>>(f: F) -> F { f }
fn annotate<'a, F: FnOnce(&'a Lua) -> Result<Table<'a>>>(f: F) -> F { f }
let make_env = annotate(move |lua: &Lua| -> Result<Table> {
let globals = lua.globals();
@@ -142,13 +141,21 @@ pub fn chunk(input: TokenStream) -> TokenStream {
Ok(env)
});
InnerChunk(Mutex::new(Some(make_env)))
InnerChunk(Cell::new(Some(make_env)), PhantomData)
}};
wrapped_code.into()
}
#[cfg(feature = "macros")]
#[proc_macro_derive(FromLua)]
pub fn from_lua(input: TokenStream) -> TokenStream {
from_lua::from_lua(input)
}
#[cfg(feature = "macros")]
mod chunk;
#[cfg(feature = "macros")]
mod from_lua;
#[cfg(feature = "macros")]
mod token;
+10 -10
View File
@@ -15,7 +15,7 @@ use crate::value::{FromLuaMulti, IntoLua, IntoLuaMulti};
///
/// [loadable by Lua]: https://www.lua.org/manual/5.4/manual.html#3.3.2
/// [`Chunk`]: crate::Chunk
pub trait AsChunk<'a> {
pub trait AsChunk<'lua, 'a> {
/// Returns optional chunk name
fn name(&self) -> Option<StdString> {
None
@@ -24,7 +24,7 @@ pub trait AsChunk<'a> {
/// Returns optional chunk [environment]
///
/// [environment]: https://www.lua.org/manual/5.4/manual.html#2.2
fn environment<'lua>(&self, lua: &'lua Lua) -> Result<Option<Table<'lua>>> {
fn environment(&self, lua: &'lua Lua) -> Result<Option<Table<'lua>>> {
let _lua = lua; // suppress warning
Ok(None)
}
@@ -38,43 +38,43 @@ pub trait AsChunk<'a> {
fn source(self) -> IoResult<Cow<'a, [u8]>>;
}
impl<'a> AsChunk<'a> for &'a str {
impl<'a> AsChunk<'_, 'a> for &'a str {
fn source(self) -> IoResult<Cow<'a, [u8]>> {
Ok(Cow::Borrowed(self.as_ref()))
}
}
impl AsChunk<'static> for StdString {
impl AsChunk<'_, 'static> for StdString {
fn source(self) -> IoResult<Cow<'static, [u8]>> {
Ok(Cow::Owned(self.into_bytes()))
}
}
impl<'a> AsChunk<'a> for &'a StdString {
impl<'a> AsChunk<'_, 'a> for &'a StdString {
fn source(self) -> IoResult<Cow<'a, [u8]>> {
Ok(Cow::Borrowed(self.as_bytes()))
}
}
impl<'a> AsChunk<'a> for &'a [u8] {
impl<'a> AsChunk<'_, 'a> for &'a [u8] {
fn source(self) -> IoResult<Cow<'a, [u8]>> {
Ok(Cow::Borrowed(self))
}
}
impl AsChunk<'static> for Vec<u8> {
impl AsChunk<'_, 'static> for Vec<u8> {
fn source(self) -> IoResult<Cow<'static, [u8]>> {
Ok(Cow::Owned(self))
}
}
impl<'a> AsChunk<'a> for &'a Vec<u8> {
impl<'a> AsChunk<'_, 'a> for &'a Vec<u8> {
fn source(self) -> IoResult<Cow<'a, [u8]>> {
Ok(Cow::Borrowed(self.as_ref()))
}
}
impl AsChunk<'static> for &Path {
impl AsChunk<'_, 'static> for &Path {
fn name(&self) -> Option<StdString> {
Some(format!("@{}", self.display()))
}
@@ -84,7 +84,7 @@ impl AsChunk<'static> for &Path {
}
}
impl AsChunk<'static> for PathBuf {
impl AsChunk<'_, 'static> for PathBuf {
fn name(&self) -> Option<StdString> {
Some(format!("@{}", self.display()))
}
+1 -19
View File
@@ -9,7 +9,7 @@ use bstr::{BStr, BString};
use num_traits::cast;
use crate::error::{Error, Result};
use crate::function::{Function, WrappedFunction};
use crate::function::Function;
use crate::lua::Lua;
use crate::string::String;
use crate::table::Table;
@@ -21,9 +21,6 @@ use crate::value::{FromLua, IntoLua, Nil, Value};
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
use crate::{function::OwnedFunction, table::OwnedTable, userdata::OwnedAnyUserData};
#[cfg(feature = "async")]
use crate::function::WrappedAsyncFunction;
impl<'lua> IntoLua<'lua> for Value<'lua> {
#[inline]
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
@@ -136,21 +133,6 @@ impl<'lua> FromLua<'lua> for OwnedFunction {
}
}
impl<'lua> IntoLua<'lua> for WrappedFunction<'lua> {
#[inline]
fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
lua.create_callback(self.0).map(Value::Function)
}
}
#[cfg(feature = "async")]
impl<'lua> IntoLua<'lua> for WrappedAsyncFunction<'lua> {
#[inline]
fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
lua.create_async_callback(self.0).map(Value::Function)
}
}
impl<'lua> IntoLua<'lua> for Thread<'lua> {
#[inline]
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
+19 -4
View File
@@ -13,7 +13,7 @@ use crate::util::{
assert_stack, check_stack, error_traceback, linenumber_to_usize, pop_error, ptr_to_lossy_str,
ptr_to_str, StackGuard,
};
use crate::value::{FromLuaMulti, IntoLua, IntoLuaMulti};
use crate::value::{FromLuaMulti, IntoLua, IntoLuaMulti, Value};
#[cfg(feature = "async")]
use {
@@ -228,7 +228,7 @@ impl<'lua> Function<'lua> {
/// # }
/// ```
pub fn bind<A: IntoLuaMulti<'lua>>(&self, args: A) -> Result<Function<'lua>> {
unsafe extern "C" fn args_wrapper_impl(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C-unwind" fn args_wrapper_impl(state: *mut ffi::lua_State) -> c_int {
let nargs = ffi::lua_gettop(state);
let nbinds = ffi::lua_tointeger(state, ffi::lua_upvalueindex(1)) as c_int;
ffi::luaL_checkstack(state, nbinds, ptr::null());
@@ -423,7 +423,7 @@ impl<'lua> Function<'lua> {
#[cfg(not(feature = "luau"))]
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
pub fn dump(&self, strip: bool) -> Vec<u8> {
unsafe extern "C" fn writer(
unsafe extern "C-unwind" fn writer(
_state: *mut ffi::lua_State,
buf: *const c_void,
buf_len: usize,
@@ -470,7 +470,7 @@ impl<'lua> Function<'lua> {
use std::ffi::CStr;
use std::os::raw::c_char;
unsafe extern "C" fn callback<F: FnMut(CoverageInfo)>(
unsafe extern "C-unwind" fn callback<F: FnMut(CoverageInfo)>(
data: *mut c_void,
function: *const c_char,
line_defined: c_int,
@@ -607,6 +607,21 @@ impl<'lua> Function<'lua> {
}
}
impl<'lua> IntoLua<'lua> for WrappedFunction<'lua> {
#[inline]
fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
lua.create_callback(self.0).map(Value::Function)
}
}
#[cfg(feature = "async")]
impl<'lua> IntoLua<'lua> for WrappedAsyncFunction<'lua> {
#[inline]
fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
lua.create_async_callback(self.0).map(Value::Function)
}
}
#[cfg(test)]
mod assertions {
use super::*;
+9 -1
View File
@@ -216,6 +216,14 @@ pub use crate::{
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
pub use mlua_derive::chunk;
/// Derive [`FromLua`] for a Rust type.
///
/// Current implementation generate code that takes [`UserData`] value, borrow it (of the Rust type)
/// and clone.
#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
pub use mlua_derive::FromLua;
/// Registers Lua module entrypoint.
///
/// You can register multiple entrypoints as required.
@@ -248,7 +256,7 @@ pub use mlua_derive::chunk;
///
/// In module mode, mlua runs in unknown environment and cannot say are there any memory
/// limits or not. As result, some operations that require memory allocation runs in
/// protected mode. Setting this mode will improve performance of such operations
/// protected mode. Setting this attribute will improve performance of such operations
/// with risk of having uncaught exceptions and memory leaks.
///
/// ```ignore
+23 -41
View File
@@ -173,7 +173,7 @@ pub struct LuaOptions {
/// Max size of thread (coroutine) object pool used to execute asynchronous functions.
///
/// It works on Lua 5.4, LuaJIT (vendored) and Luau, where [`lua_resetthread`] function
/// It works on Lua 5.4 and Luau, where [`lua_resetthread`] function
/// is available and allows to reuse old coroutines after resetting their state.
///
/// Default: **0** (disabled)
@@ -357,7 +357,7 @@ impl Lua {
{
// Workaround to avoid stripping a few unused Lua symbols that could be imported
// by C modules in unsafe mode
let mut _symbols: Vec<*const extern "C" fn()> = vec![
let mut _symbols: Vec<*const extern "C-unwind" fn()> = vec![
ffi::lua_atpanic as _,
ffi::lua_isuserdata as _,
ffi::lua_tocfunction as _,
@@ -377,22 +377,14 @@ impl Lua {
/// Creates a new Lua state with required `libs` and `options`
unsafe fn inner_new(libs: StdLib, options: LuaOptions) -> Lua {
// Skip Rust allocator for non-vendored LuaJIT (see https://github.com/khvzak/mlua/issues/176)
let use_rust_allocator = !(cfg!(feature = "luajit") && cfg!(not(feature = "vendored")));
let (state, mem_state) = if use_rust_allocator {
let mut mem_state: *mut MemoryState = Box::into_raw(Box::default());
let mut state = ffi::lua_newstate(ALLOCATOR, mem_state as *mut c_void);
// If state is null (it's possible for LuaJIT on non-x86 arch) then switch to Lua internal allocator
if state.is_null() {
drop(Box::from_raw(mem_state));
mem_state = ptr::null_mut();
state = ffi::luaL_newstate();
}
(state, mem_state)
} else {
(ffi::luaL_newstate(), ptr::null_mut())
};
let mut mem_state: *mut MemoryState = Box::into_raw(Box::default());
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() {
drop(Box::from_raw(mem_state));
mem_state = ptr::null_mut();
state = ffi::luaL_newstate();
}
assert!(!state.is_null(), "Failed to instantiate Lua VM");
ffi::luaL_requiref(state, cstr!("_G"), ffi::luaopen_base, 1);
@@ -893,7 +885,7 @@ impl Lua {
) where
F: Fn(&Lua, Debug) -> Result<()> + MaybeSend + 'static,
{
unsafe extern "C" fn hook_proc(state: *mut ffi::lua_State, ar: *mut ffi::lua_Debug) {
unsafe extern "C-unwind" fn hook_proc(state: *mut ffi::lua_State, ar: *mut ffi::lua_Debug) {
let extra = extra_data(state);
if (*extra).hook_thread != state {
// Hook was destined for a different thread, ignore
@@ -987,7 +979,7 @@ impl Lua {
where
F: Fn(&Lua) -> Result<VmState> + MaybeSend + 'static,
{
unsafe extern "C" fn interrupt_proc(state: *mut ffi::lua_State, gc: c_int) {
unsafe extern "C-unwind" fn interrupt_proc(state: *mut ffi::lua_State, gc: c_int) {
if gc >= 0 {
// We don't support GC interrupts since they cannot survive Lua exceptions
return;
@@ -1039,7 +1031,7 @@ impl Lua {
where
F: Fn(&Lua, &str, bool) -> Result<()> + MaybeSend + 'static,
{
unsafe extern "C" 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 lua: &Lua = mem::transmute((*extra).inner.assume_init_ref());
callback_error_ext(lua.state(), extra, |_| {
@@ -1333,7 +1325,7 @@ impl Lua {
///
/// [`Chunk::exec`]: crate::Chunk::exec
#[track_caller]
pub fn load<'lua, 'a>(&'lua self, chunk: impl AsChunk<'a>) -> Chunk<'lua, 'a> {
pub fn load<'lua, 'a>(&'lua self, chunk: impl AsChunk<'lua, 'a>) -> Chunk<'lua, 'a> {
let caller = Location::caller();
Chunk {
lua: self,
@@ -1673,11 +1665,7 @@ impl Lua {
&'lua self,
func: &Function,
) -> Result<Thread<'lua>> {
#[cfg(any(
feature = "lua54",
all(feature = "luajit", feature = "vendored"),
feature = "luau",
))]
#[cfg(any(feature = "lua54", feature = "luau"))]
unsafe {
let state = self.state();
let _sg = StackGuard::new(state);
@@ -1703,11 +1691,7 @@ impl Lua {
/// Resets thread (coroutine) and returns to the pool for later use.
#[cfg(feature = "async")]
#[cfg(any(
feature = "lua54",
all(feature = "luajit", feature = "vendored"),
feature = "luau",
))]
#[cfg(any(feature = "lua54", feature = "luau"))]
pub(crate) unsafe fn recycle_thread(&self, thread: &mut Thread) -> bool {
let extra = &mut *self.extra.get();
if extra.thread_pool.len() < extra.thread_pool.capacity() {
@@ -1721,8 +1705,6 @@ impl Lua {
// Error object is on top, drop it
ffi::lua_settop(thread_state, 0);
}
#[cfg(all(feature = "luajit", feature = "vendored"))]
ffi::lua_resetthread(self.state(), thread_state);
#[cfg(feature = "luau")]
ffi::lua_resetthread(thread_state);
extra.thread_pool.push(thread.0.index);
@@ -2549,15 +2531,15 @@ impl Lua {
}
let mut has_name = false;
for (k, f) in registry.meta_fields {
has_name = has_name || k == "__name";
has_name = has_name || k == MetaMethod::Type;
self.push_value(f(self, MultiValue::new())?.pop_front().unwrap())?;
rawset_field(state, -2, MetaMethod::validate(&k)?)?;
}
// Set `__name` if not provided
// Set `__name/__type` if not provided
if !has_name {
let type_name = short_type_name::<T>();
push_string(state, type_name.as_bytes(), !self.unlikely_memory_error())?;
rawset_field(state, -2, "__name")?;
rawset_field(state, -2, MetaMethod::Type.name())?;
}
let metatable_index = ffi::lua_absindex(state, -1);
@@ -2754,7 +2736,7 @@ impl Lua {
&'lua self,
func: Callback<'lua, 'static>,
) -> Result<Function<'lua>> {
unsafe extern "C" fn call_callback(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C-unwind" fn call_callback(state: *mut ffi::lua_State) -> c_int {
// Normal functions can be scoped and therefore destroyed,
// so we need to check that the first upvalue is valid
let (upvalue, extra) = match ffi::lua_type(state, ffi::lua_upvalueindex(1)) {
@@ -2832,7 +2814,7 @@ impl Lua {
}
}
unsafe extern "C" fn call_callback(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C-unwind" fn call_callback(state: *mut ffi::lua_State) -> c_int {
// Async functions cannot be scoped and therefore destroyed,
// so the first upvalue is always valid
let upvalue = get_userdata::<AsyncCallbackUpvalue>(state, ffi::lua_upvalueindex(1));
@@ -2865,7 +2847,7 @@ impl Lua {
})
}
unsafe extern "C" fn poll_future(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C-unwind" fn poll_future(state: *mut ffi::lua_State) -> c_int {
let upvalue = get_userdata::<AsyncPollUpvalue>(state, ffi::lua_upvalueindex(1));
let extra = (*upvalue).extra.get();
callback_error_ext(state, extra, |_| {
@@ -2921,7 +2903,7 @@ impl Lua {
Function(self.pop_ref())
};
unsafe extern "C" fn unpack(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C-unwind" fn unpack(state: *mut ffi::lua_State) -> c_int {
let len = ffi::lua_tointeger(state, 2);
ffi::luaL_checkstack(state, len as c_int, ptr::null());
for i in 1..=len {
+2 -2
View File
@@ -32,7 +32,7 @@ impl Lua {
}
}
unsafe extern "C" fn lua_collectgarbage(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C-unwind" fn lua_collectgarbage(state: *mut ffi::lua_State) -> c_int {
let option = ffi::luaL_optstring(state, 1, cstr!("collect"));
let option = CStr::from_ptr(option);
let arg = ffi::luaL_optinteger(state, 2, 0);
@@ -122,7 +122,7 @@ fn lua_require(lua: &Lua, name: Option<StdString>) -> Result<Value> {
}
// Luau vector datatype constructor
unsafe extern "C" fn lua_vector(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C-unwind" fn lua_vector(state: *mut ffi::lua_State) -> c_int {
let x = ffi::luaL_checknumber(state, 1) as c_float;
let y = ffi::luaL_checknumber(state, 2) as c_float;
let z = ffi::luaL_checknumber(state, 3) as c_float;
+2 -1
View File
@@ -101,7 +101,8 @@ macro_rules! protect_lua {
};
($state:expr, $nargs:expr, $nresults:expr, fn($state_inner:ident) $code:expr) => {{
unsafe extern "C" fn do_call($state_inner: *mut ffi::lua_State) -> ::std::os::raw::c_int {
use ::std::os::raw::c_int;
unsafe extern "C-unwind" fn do_call($state_inner: *mut ffi::lua_State) -> c_int {
$code;
let nresults = $nresults;
if nresults == ::ffi::LUA_MULTRET {
+1 -1
View File
@@ -85,7 +85,7 @@ impl MemoryState {
}
}
unsafe extern "C" fn allocator(
unsafe extern "C-unwind" fn allocator(
extra: *mut c_void,
ptr: *mut c_void,
osize: usize,
+6 -16
View File
@@ -202,20 +202,16 @@ impl<'lua> Thread<'lua> {
/// Returns a error in case of either the original error that stopped the thread or errors
/// in closing methods.
///
/// In [LuaJIT] and Luau: resets to the initial state of a newly created Lua thread.
/// In Luau: resets to the initial state of a newly created Lua thread.
/// Lua threads in arbitrary states (like yielded or errored) can be reset properly.
///
/// Sets a Lua function for the thread afterwards.
///
/// Requires `feature = "lua54"` OR `feature = "luajit,vendored"` OR `feature = "luau"`
/// Requires `feature = "lua54"` OR `feature = "luau"`.
///
/// [Lua 5.4]: https://www.lua.org/manual/5.4/manual.html#lua_resetthread
/// [LuaJIT]: https://github.com/openresty/luajit2#lua_resetthread
#[cfg(any(
feature = "lua54",
all(feature = "luajit", feature = "vendored"),
feature = "luau",
))]
/// [Lua 5.4]: https://www.lua.org/manual/5.4/manual.html#lua_closethread
#[cfg(any(feature = "lua54", feature = "luau"))]
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
pub fn reset(&self, func: crate::function::Function<'lua>) -> Result<()> {
let lua = self.0.lua;
let state = lua.state();
@@ -234,8 +230,6 @@ impl<'lua> Thread<'lua> {
if status != ffi::LUA_OK {
return Err(pop_error(thread_state, status));
}
#[cfg(all(feature = "luajit", feature = "vendored"))]
ffi::lua_resetthread(state, thread_state);
#[cfg(feature = "luau")]
ffi::lua_resetthread(thread_state);
@@ -375,11 +369,7 @@ impl<'lua, R> AsyncThread<'lua, R> {
}
#[cfg(feature = "async")]
#[cfg(any(
feature = "lua54",
all(feature = "luajit", feature = "vendored"),
feature = "luau",
))]
#[cfg(any(feature = "lua54", feature = "luau"))]
impl<'lua, R> Drop for AsyncThread<'lua, R> {
fn drop(&mut self) {
if self.recycle {
+23 -3
View File
@@ -1,5 +1,6 @@
use std::any::{type_name, TypeId};
use std::cell::{Ref, RefCell, RefMut};
use std::ffi::CStr;
use std::fmt;
use std::hash::Hash;
use std::mem;
@@ -36,6 +37,7 @@ pub(crate) const USER_VALUE_MAXSLOT: usize = 8;
///
/// [`UserData`]: crate::UserData
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum MetaMethod {
/// The `+` operator.
Add,
@@ -141,6 +143,11 @@ pub enum MetaMethod {
#[cfg(feature = "lua54")]
#[cfg_attr(docsrs, doc(cfg(feature = "lua54")))]
Close,
/// The `__name`/`__type` metafield.
///
/// This is not a function, but it's value can be used by `tostring` and `typeof` built-in functions.
#[doc(hidden)]
Type,
}
impl PartialEq<MetaMethod> for &str {
@@ -212,6 +219,19 @@ impl MetaMethod {
#[cfg(feature = "lua54")]
MetaMethod::Close => "__close",
#[rustfmt::skip]
MetaMethod::Type => if cfg!(feature = "luau") { "__type" } else { "__name" },
}
}
pub(crate) const fn as_cstr(self) -> &'static CStr {
match self {
#[rustfmt::skip]
MetaMethod::Type => unsafe {
CStr::from_bytes_with_nul_unchecked(if cfg!(feature = "luau") { b"__type\0" } else { b"__name\0" })
},
_ => unreachable!(),
}
}
@@ -1089,7 +1109,7 @@ impl<'lua> AnyUserData<'lua> {
unsafe { self.0.lua.get_userdata_type_id(&self.0) }
}
/// Returns a type name of this `UserData` (from `__name` metatable field).
/// Returns a type name of this `UserData` (from a metatable field).
pub(crate) fn type_name(&self) -> Result<Option<StdString>> {
let lua = self.0.lua;
let state = lua.state();
@@ -1101,10 +1121,10 @@ impl<'lua> AnyUserData<'lua> {
let protect = !lua.unlikely_memory_error();
let name_type = if protect {
protect_lua!(state, 1, 1, |state| {
ffi::luaL_getmetafield(state, -1, cstr!("__name"))
ffi::luaL_getmetafield(state, -1, MetaMethod::Type.as_cstr().as_ptr())
})?
} else {
ffi::luaL_getmetafield(state, -1, cstr!("__name"))
ffi::luaL_getmetafield(state, -1, MetaMethod::Type.as_cstr().as_ptr())
};
match name_type {
ffi::LUA_TSTRING => Ok(Some(String(lua.pop_ref()).to_str()?.to_owned())),
+14 -14
View File
@@ -88,7 +88,7 @@ impl Drop for StackGuard {
pub unsafe fn protect_lua_call(
state: *mut ffi::lua_State,
nargs: c_int,
f: unsafe extern "C" fn(*mut ffi::lua_State) -> c_int,
f: unsafe extern "C-unwind" fn(*mut ffi::lua_State) -> c_int,
) -> Result<()> {
let stack_start = ffi::lua_gettop(state) - nargs;
@@ -133,7 +133,7 @@ where
nresults: c_int,
}
unsafe extern "C" fn do_call<F, R>(state: *mut ffi::lua_State) -> c_int
unsafe extern "C-unwind" fn do_call<F, R>(state: *mut ffi::lua_State) -> c_int
where
F: Fn(*mut ffi::lua_State) -> R,
R: Copy,
@@ -295,7 +295,7 @@ pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool)
#[cfg(feature = "luau")]
#[inline]
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool) -> Result<()> {
unsafe extern "C" fn destructor<T>(ud: *mut c_void) {
unsafe extern "C-unwind" fn destructor<T>(ud: *mut c_void) {
ptr::drop_in_place(ud as *mut T);
}
@@ -400,16 +400,16 @@ pub unsafe fn get_gc_userdata<T: Any>(
ud
}
unsafe extern "C" fn lua_error_impl(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C-unwind" fn lua_error_impl(state: *mut ffi::lua_State) -> c_int {
ffi::lua_error(state);
}
unsafe extern "C" fn lua_isfunction_impl(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C-unwind" fn lua_isfunction_impl(state: *mut ffi::lua_State) -> c_int {
ffi::lua_pushboolean(state, ffi::lua_isfunction(state, -1));
1
}
unsafe extern "C" fn lua_istable_impl(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C-unwind" fn lua_istable_impl(state: *mut ffi::lua_State) -> c_int {
ffi::lua_pushboolean(state, ffi::lua_istable(state, -1));
1
}
@@ -613,7 +613,7 @@ pub unsafe fn init_userdata_metatable(
}
#[cfg(not(feature = "luau"))]
pub unsafe extern "C" fn userdata_destructor<T>(state: *mut ffi::lua_State) -> c_int {
pub unsafe extern "C-unwind" fn userdata_destructor<T>(state: *mut ffi::lua_State) -> c_int {
// It's probably NOT a good idea to catch Rust panics in finalizer
// Lua 5.4 ignores it, other versions generates `LUA_ERRGCMM` without calling message handler
take_userdata::<T>(state);
@@ -685,7 +685,7 @@ where
}
}
pub unsafe extern "C" fn error_traceback(state: *mut ffi::lua_State) -> c_int {
pub unsafe extern "C-unwind" fn error_traceback(state: *mut ffi::lua_State) -> c_int {
// Luau calls error handler for memory allocation errors, skip it
// See https://github.com/Roblox/luau/issues/880
#[cfg(feature = "luau")]
@@ -725,7 +725,7 @@ pub unsafe fn error_traceback_thread(state: *mut ffi::lua_State, thread: *mut ff
}
// A variant of `pcall` that does not allow Lua to catch Rust panics from `callback_error`.
pub unsafe extern "C" fn safe_pcall(state: *mut ffi::lua_State) -> c_int {
pub unsafe extern "C-unwind" fn safe_pcall(state: *mut ffi::lua_State) -> c_int {
ffi::luaL_checkstack(state, 2, ptr::null());
let top = ffi::lua_gettop(state);
@@ -751,8 +751,8 @@ pub unsafe extern "C" fn safe_pcall(state: *mut ffi::lua_State) -> c_int {
}
// A variant of `xpcall` that does not allow Lua to catch Rust panics from `callback_error`.
pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C" fn xpcall_msgh(state: *mut ffi::lua_State) -> c_int {
pub unsafe extern "C-unwind" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C-unwind" fn xpcall_msgh(state: *mut ffi::lua_State) -> c_int {
ffi::luaL_checkstack(state, 2, ptr::null());
if let Some(WrappedFailure::Panic(_)) =
@@ -866,7 +866,7 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
// Create error and panic metatables
unsafe extern "C" fn error_tostring(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C-unwind" fn error_tostring(state: *mut ffi::lua_State) -> c_int {
callback_error(state, |_| {
check_stack(state, 3)?;
@@ -924,7 +924,7 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
// Create destructed userdata metatable
unsafe extern "C" fn destructed_error(state: *mut ffi::lua_State) -> c_int {
unsafe extern "C-unwind" fn destructed_error(state: *mut ffi::lua_State) -> c_int {
callback_error(state, |_| Err(Error::CallbackDestructed))
}
@@ -1007,7 +1007,7 @@ impl WrappedFailure {
let size = mem::size_of::<WrappedFailure>();
#[cfg(feature = "luau")]
let ud = {
unsafe extern "C" fn destructor(p: *mut c_void) {
unsafe extern "C-unwind" fn destructor(p: *mut c_void) {
ptr::drop_in_place(p as *mut WrappedFailure);
}
ffi::lua_newuserdatadtor(state, size, destructor) as *mut Self
+1 -1
View File
@@ -223,7 +223,7 @@ impl<'lua> Value<'lua> {
f @ Value::Function(_) => write!(fmt, "function: {:?}", f.to_pointer()),
t @ Value::Thread(_) => write!(fmt, "thread: {:?}", t.to_pointer()),
u @ Value::UserData(ud) => {
// Try `__name` first then `__tostring`
// Try `__name/__type` first then `__tostring`
let name = ud.type_name().ok().flatten();
let s = name
.map(|name| format!("{name}: {:?}", u.to_pointer()))
+13 -1
View File
@@ -1,7 +1,7 @@
use std::fs;
use std::io;
use mlua::{Lua, Result};
use mlua::{AnyUserData, Function, Lua, Result};
#[test]
fn test_chunk_path() -> Result<()> {
@@ -36,12 +36,24 @@ fn test_chunk_macro() -> Result<()> {
let data = lua.create_table()?;
data.raw_set("num", 1)?;
let ud = AnyUserData::wrap("hello");
let f = Function::wrap(|_lua, ()| Ok(()));
lua.globals().set("g", 123)?;
let string = String::new();
let str = string.as_str();
lua.load(mlua::chunk! {
assert($name == "Rustacean")
assert(type($table) == "table")
assert($table[1] == 1)
assert(type($data) == "table")
assert($data.num == 1)
assert(type($ud) == "userdata")
assert(type($f) == "function")
assert(type($str) == "string")
assert($str == "")
assert(g == 123)
s = 321
})
+1 -1
View File
@@ -86,7 +86,7 @@ fn test_rust_function() -> Result<()> {
fn test_c_function() -> Result<()> {
let lua = Lua::new();
unsafe extern "C" fn c_function(state: *mut mlua::lua_State) -> std::os::raw::c_int {
unsafe extern "C-unwind" fn c_function(state: *mut mlua::lua_State) -> std::os::raw::c_int {
let lua = Lua::init_from_ptr(state);
lua.globals().set("c_function", true).unwrap();
0
+4 -8
View File
@@ -17,12 +17,8 @@ fn test_memory_limit() -> Result<()> {
.into_function()?;
f.call::<_, ()>(()).expect("should trigger no memory limit");
if cfg!(feature = "luajit") && cfg!(not(feature = "vendored")) {
// we don't support setting memory limit for non-vendored luajit
assert!(matches!(
lua.set_memory_limit(0),
Err(Error::MemoryLimitNotAvailable)
));
if cfg!(feature = "luajit") && lua.set_memory_limit(0).is_err() {
// seems this luajit version does not support memory limit
return Ok(());
}
@@ -46,8 +42,8 @@ fn test_memory_limit_thread() -> Result<()> {
.load("local t = {}; for i = 1,10000 do t[i] = i end")
.into_function()?;
if cfg!(feature = "luajit") && cfg!(not(feature = "vendored")) {
// we don't support setting memory limit for non-vendored luajit
if cfg!(feature = "luajit") && lua.set_memory_limit(0).is_err() {
// seems this luajit version does not support memory limit
return Ok(());
}
-11
View File
@@ -1,11 +0,0 @@
[target.x86_64-apple-darwin]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]
[target.aarch64-apple-darwin]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]
+7
View File
@@ -0,0 +1,7 @@
fn main() {
#[cfg(target_os = "macos")]
{
println!("cargo:rustc-cdylib-link-arg=-undefined");
println!("cargo:rustc-cdylib-link-arg=dynamic_lookup");
}
}
+1 -1
View File
@@ -69,7 +69,7 @@ fn test_safety() -> Result<()> {
fn test_load() -> Result<()> {
let lua = Lua::new();
let func = lua.load("return 1+2").into_function()?;
let func = lua.load("\treturn 1+2").into_function()?;
let result: i32 = func.call(())?;
assert_eq!(result, 3);
+1 -5
View File
@@ -94,11 +94,7 @@ fn test_thread() -> Result<()> {
}
#[test]
#[cfg(any(
feature = "lua54",
all(feature = "luajit", feature = "vendored"),
feature = "luau",
))]
#[cfg(any(feature = "lua54", feature = "luau"))]
fn test_thread_reset() -> Result<()> {
use mlua::{AnyUserData, UserData};
use std::sync::Arc;
+49 -4
View File
@@ -543,7 +543,7 @@ fn test_metatable() -> Result<()> {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_function("my_type_name", |_, data: AnyUserData| {
let metatable = data.get_metatable()?;
metatable.get::<String>("__name")
metatable.get::<String>(MetaMethod::Type)
});
}
}
@@ -554,6 +554,12 @@ fn test_metatable() -> Result<()> {
lua.load(r#"assert(ud:my_type_name() == "MyUserData")"#)
.exec()?;
#[cfg(any(feature = "lua54", feature = "lua53", feature = "luau"))]
lua.load(r#"assert(tostring(ud):sub(1, 11) == "MyUserData:")"#)
.exec()?;
#[cfg(feature = "luau")]
lua.load(r#"assert(typeof(ud) == "MyUserData")"#).exec()?;
let ud: AnyUserData = globals.get("ud")?;
let metatable = ud.get_metatable()?;
@@ -574,7 +580,7 @@ fn test_metatable() -> Result<()> {
.map(|kv: Result<(_, Value)>| Ok(kv?.0))
.collect::<Result<Vec<_>>>()?;
methods.sort();
assert_eq!(methods, vec!["__index", "__name"]);
assert_eq!(methods, vec!["__index", MetaMethod::Type.name()]);
#[derive(Copy, Clone)]
struct MyUserData2;
@@ -596,13 +602,16 @@ fn test_metatable() -> Result<()> {
impl UserData for MyUserData3 {
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_meta_field_with("__name", |_| Ok("CustomName"));
fields.add_meta_field_with(MetaMethod::Type, |_| Ok("CustomName"));
}
}
let ud = lua.create_userdata(MyUserData3)?;
let metatable = ud.get_metatable()?;
assert_eq!(metatable.get::<String>("__name")?.to_str()?, "CustomName");
assert_eq!(
metatable.get::<String>(MetaMethod::Type)?.to_str()?,
"CustomName"
);
Ok(())
}
@@ -908,3 +917,39 @@ fn test_owned_userdata() -> Result<()> {
Ok(())
}
#[cfg(feature = "macros")]
#[test]
fn test_userdata_derive() -> Result<()> {
let lua = Lua::new();
// Simple struct
#[derive(Clone, Copy, mlua::FromLua)]
struct MyUserData(i32);
lua.register_userdata_type::<MyUserData>(|reg| {
reg.add_function("val", |_, this: MyUserData| Ok(this.0));
})?;
lua.globals()
.set("ud", AnyUserData::wrap(MyUserData(123)))?;
lua.load("assert(ud:val() == 123)").exec()?;
// More complex struct where generics and where clause
#[derive(Clone, Copy, mlua::FromLua)]
struct MyUserData2<'a, T>(&'a T)
where
T: ?Sized;
lua.register_userdata_type::<MyUserData2<'static, i32>>(|reg| {
reg.add_function("val", |_, this: MyUserData2<'static, i32>| Ok(*this.0));
})?;
lua.globals()
.set("ud", AnyUserData::wrap(MyUserData2(&321)))?;
lua.load("assert(ud:val() == 321)").exec()?;
Ok(())
}