64个版本
0.10.0-beta.1 | 2024年7月31日 |
---|---|
0.9.8 | 2024年5月15日 |
0.9.6 | 2024年2月29日 |
0.9.2 | 2023年11月22日 |
0.2.0 | 2019年11月30日 |
在异步类别中排名3
每月下载量51,788
用于139个crates(其中121个直接使用)
1MB
17K SLoC
mlua
主分支是mlua
的v0.10开发版本。请查看v0.9分支以获取mlua
的稳定版本。
mlua
是为Rust编写的Lua编程语言的绑定,旨在提供安全(尽可能做到),高级、易于使用、实用且灵活的API。
作为rlua
的分支,mlua
支持Lua 5.4、5.3、5.2、5.1(包括LuaJIT)以及Roblox Luau,并允许在Rust中编写原生Lua模块,以及以独立模式使用Lua。
mlua
已在Windows/macOS/Linux上进行测试,包括在GitHub Actions上的x86_64
平台上的模块模式以及交叉编译到aarch64
(也支持其他目标)。
通过wasm32-unknown-emscripten
目标支持WebAssembly(WASM),适用于所有Lua版本(不包括JIT)。
使用方法
功能标志
mlua
使用功能标志来减少依赖项数量、编译代码,并允许选择所需的功能集。以下是可用功能标志的列表。默认情况下,mlua
不启用任何功能。
lua54
:激活Lua 5.4 支持lua53
:激活 Lua 5.3 支持lua52
:激活 Lua 5.2 支持lua51
:激活 Lua 5.1 支持luajit
:激活 LuaJIT 支持luajit52
:激活与 Lua 5.2 部分兼容的 LuaJIT 支持luau
:激活 Luau 支持(自动 vendored 模式)luau-jit
:激活带有 JIT 后端的 Luau 支持luau-vector4
:激活带有 4 维向量的 Luau 支持vendored
:在mlua
编译期间使用 lua-src 或 luajit-src crates 从源码构建静态 Lua (JIT) 库module
:启用模块模式(为 Lua 构建可加载的cdylib
库)async
:启用 async/await 支持(可以使用任何执行器,例如 tokio 或 async-std)send
:使mlua::Lua
可在线程边界之间传输(向mlua::Function
和mlua::UserData
添加Send
要求)serialize
:使用 serde 框架为mlua
类型添加序列化和反序列化支持macros
:启用过程宏(例如chunk!
)parking_lot
:支持包装在 parking_lot 的原语中的 UserData 类型(Arc<Mutex>
和Arc<RwLock>
)unstable
:启用 不稳定 功能。这些功能的公共 API 可能会在发布之间中断
Async/await 支持
mlua
支持所有 Lua 版本的 async/await,包括 Luau。
这使用 Lua 协程 实现,并需要在 Thread 中运行,同时在 Cargo.toml
中启用 feature = "async"
。
示例:
shell 命令示例:
# async http client (hyper)
cargo run --example async_http_client --features=lua54,async,macros
# async http client (reqwest)
cargo run --example async_http_reqwest --features=lua54,async,macros,serialize
# async http server
cargo run --example async_http_server --features=lua54,async,macros
curl -v https://127.0.0.1:3000
序列化(serde)支持
启用 serialize
功能标志后,mlua
允许您将实现 serde::Serialize
和 serde::Deserialize
的任何类型序列化和反序列化到/从 mlua::Value
。此外,mlua
为其提供了 serde::Serialize
特性实现(包括对 UserData
的支持)。
编译
您必须根据所选的 Lua 版本启用以下功能之一:lua54
、lua53
、lua52
、lua51
、luajit(52)
或 luau
。
默认情况下,mlua
使用 pkg-config
工具查找所选 Lua 版本的 lua 包含文件和库。在大多数情况下,它按预期工作,尽管有时可能更希望使用自定义 lua 库。为了实现这一点,mlua 支持 LUA_LIB
、LUA_LIB_NAME
和 LUA_LINK
环境变量。 LUA_LINK
是可选的,可以是 dylib
(动态库)或 static
(静态库,.a
归档)。
如何使用它们的示例
my_project $ LUA_LIB=$HOME/tmp/lua-5.2.4/src LUA_LIB_NAME=lua LUA_LINK=static cargo build
mlua
也支持通过辅助包 lua-src 和 luajit-src 使用 vendored lua/luajit。只需启用 vendored
功能,cargo 将自动构建和链接指定的 lua/luajit 版本。这是开始使用 mlua
的最简单方法。
独立模式
在独立模式下,mlua
允许您通过配置温和的 Lua 运行时将脚本支持添加到您的应用程序中,以确保安全和稳健。
添加到 Cargo.toml
[dependencies]
mlua = { version = "0.9.9", features = ["lua54", "vendored"] }
main.rs
use mlua::prelude::*;
fn main() -> LuaResult<()> {
let lua = Lua::new();
let map_table = lua.create_table()?;
map_table.set(1, "one")?;
map_table.set("two", 2)?;
lua.globals().set("map_table", map_table)?;
lua.load("for k,v in pairs(map_table) do print(k,v) end").exec()?;
Ok(())
}
模块模式
在模块模式下,mlua
允许创建一个可以由 Lua 代码使用 require
加载的编译 Lua 模块。在这种情况下,mlua
使用外部 Lua 运行时,这可能导致由于 Lua 环境的不确定性和使用如 debug
等库而导致的潜在不安全性。
添加到 Cargo.toml
[lib]
crate-type = ["cdylib"]
[dependencies]
mlua = { version = "0.9.9", features = ["lua54", "module"] }
lib.rs
:
use mlua::prelude::*;
fn hello(_: &Lua, name: String) -> LuaResult<()> {
println!("hello, {}!", name);
Ok(())
}
#[mlua::lua_module]
fn my_module(lua: &Lua) -> LuaResult<LuaTable> {
let exports = lua.create_table()?;
exports.set("hello", lua.create_function(hello)?)?;
Ok(exports)
}
然后(macOS 示例)
$ cargo rustc -- -C link-arg=-undefined -C link-arg=dynamic_lookup
$ ln -s ./target/debug/libmy_module.dylib ./my_module.so
$ lua5.4 -e 'require("my_module").hello("world")'
hello, world!
在 macOS 上,您需要设置额外的链接器参数。一种选择是使用 cargo rustc --release -- -C link-arg=-undefined -C link-arg=dynamic_lookup
进行编译,另一种选择是创建一个包含以下内容的 .cargo/config
文件:
[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",
]
在 Linux 上,您可以使用 cargo build --release
正常构建模块。
在Windows上,目标模块将与lua5x.dll
库链接(取决于您的功能标志)。您的应用程序应该提供这个库。
模块构建不需要在系统上安装Lua库或头文件。
发布到luarocks.org
为mlua模块提供了一个LuaRocks构建后端luarocks-build-rust-mlua
。
用Rust编写的模块并发布到luarocks
安全性
mlua
的一个目标是为Rust和Lua之间提供安全的 API。Lua C API可能会在任何地方触发错误longjmp的地方,都由lua_pcall
进行保护,并且库的使用者被保护免于直接与不安全的事物(如Lua栈)交互,这与安全性相关联。
不幸的是,即使在没有使用unsafe
的情况下,mlua
也不提供绝对的安全性。这个库包含大量的不安全代码。这个库中肯定还潜伏着许多错误!在不安全性的潜在风险下使用Lua C API出奇地、令人费解地困难。
恐慌处理
mlua
将Rust回调内部生成的恐慌包装为常规的Lua错误。恐慌可以通过返回或传播Lua错误到Rust代码来恢复。
例如
let lua = Lua::new();
let f = lua.create_function(|_, ()| -> LuaResult<()> {
panic!("test panic");
})?;
lua.globals().set("rust_func", f)?;
let _ = lua.load(r#"
local status, err = pcall(rust_func)
print(err) -- prints: test panic
error(err) -- propagate panic
"#).exec();
unreachable!()
可选地,mlua
可以通过pcall
/xpcall
禁用Lua中Rust恐慌的捕获,并自动在Lua API边界跨平台恢复。这是通过LuaOptions
控制的,通过包装Lua的pcall
/xpcall
函数来实现,以防止捕获包装的Rust恐慌的错误。
mlua
还应以另一种方式确保恐慌安全,即任何Lua
实例或处理在用户生成的恐慌后仍然可用,并且此类恐慌不应破坏内部不变性或泄露Lua栈空间。这主要与在Drop实现中安全使用mlua
类型有关,因为您不应该使用恐慌进行常规错误处理。
以下是应该被认为是错误的mlua
行为列表。如果您遇到它们,非常欢迎您提交错误报告
-
如果您可以不用键入“unsafe”这个词,使用
mlua
导致UB,这是一个错误。 -
如果您的程序恐慌并显示包含字符串“mlua内部错误”的消息,这是一个错误。
-
由longjmp处理的Lua C API错误。除内部回调中故意这样做外,所有Lua C API可能会在调用堆栈帧上触发longjmp的实例都应该受到保护。如果您检测到
mlua
正在触发跨越您的Rust堆栈帧的longjmp,这是一个错误! -
如果您检测到在捕获恐慌或从恐慌触发的Drop操作期间,
Lua
或处理方法触发了其他错误或存在Lua栈空间泄露,这是一个错误。mlua
实例在用户生成的恐慌面前应保持完全可用。这种保证不适用于标记为“mlua内部错误”的恐慌,因为这已经表明了另一个错误。
沙盒
如果您对在受控环境中运行不受信任的Lua脚本感兴趣,请查看Luau沙盒页面。
mlua
提供了一个用于启用沙盒模式的Lua::sandbox
方法(仅限于Luau)。
许可证
本项目采用MIT许可协议
依赖项
~1–8.5MB
~59K SLoC