返回排行榜

mlua-rs/mlua

Rust

High level Lua 5.5/5.4/5.3/5.2/5.1 (including LuaJIT) and Luau bindings to Rust with async/await support

rustrust-bindingslualuajitasyncasynchronousscriptingluauwasm
Star 增长趋势
Star
2.8k
Forks
212
周增长
Issues
54
1k2k
2019年12月2022年2月2024年5月2026年7月
制品库crates.iocargo add mlua
README

mlua

Build Status Latest Version API Documentation Coverage Status MSRV

Guided Tour | Benchmarks | FAQ

mlua is a set of bindings to the Lua programming language for Rust with a goal of providing a safe (as much as possible), high level, easy to use, practical and flexible API.

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).

WebAssembly (WASM) is supported through the wasm32-unknown-emscripten target for all Lua/Luau versions excluding JIT.

Usage

Feature flags

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.

  • lua55: enable Lua 5.5 support
  • lua54: enable Lua 5.4 support
  • lua53: enable Lua 5.3 support
  • lua52: enable Lua 5.2 support
  • lua51: enable Lua 5.1 support
  • luajit: enable LuaJIT support
  • luajit52: enable LuaJIT support with partial compatibility with Lua 5.2
  • luau: enable Luau support (auto vendored mode)
  • luau-jit: enable Luau support with JIT backend.
  • luau-vector4: enable Luau support with 4-dimensional vector.
  • vendored: build static Lua(JIT) libraries from sources during mlua compilation using lua-src or luajit-src
  • module: enable module mode (building loadable cdylib library for Lua)
  • async: enable async/await support (any executor can be used, eg. tokio or async-std)
  • send: make mlua::Lua: Send + Sync (adds Send requirement to mlua::Function and Send + Sync to mlua::UserData)
  • error-send: make mlua::Error: Send + Sync
  • serde: add serialization and deserialization support to mlua types using serde
  • macros: enable procedural macros (such as chunk!)
  • 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

Async/await support

mlua supports async/await for all Lua versions including Luau.

This works using Lua coroutines and requires running Thread along with enabling feature = "async" in Cargo.toml.

Examples:

shell command examples:

# 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,serde

# async http server
cargo run --example async_http_server --features=lua54,async,macros,send
curl -v http://localhost:3000

Serde support

With the serde feature flag enabled, mlua allows you to serialize/deserialize any type that implements serde::Serialize and serde::Deserialize into/from mlua::Value. In addition, mlua provides the serde::Serialize trait implementation for mlua::Value (including UserData support).

Example

Compiling

You have to enable one of the features: lua54, lua53, lua52, lua51, luajit(52) or luau, according to the chosen Lua version.

By default mlua uses pkg-config to find Lua includes and libraries for the chosen Lua version. In most cases it works as desired, although sometimes it may be preferable to use a custom Lua library. To achieve this, mlua supports the 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 of how to use them:

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 and luajit-src. Just enable the vendored feature and cargo will automatically build and link the specified Lua/LuaJIT version. This is the easiest way to get started with mlua.

Standalone mode

In standalone mode, mlua allows adding scripting support to your application with a properly configured Lua runtime to ensure safety and soundness.

Add to Cargo.toml:

[dependencies]
mlua = { version = "0.12", 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(())
}

Module mode

In module mode, mlua allows creating a compiled Lua module that can be loaded from Lua code using require. In this case mlua uses an external Lua runtime which could lead to potential unsafety due to the unpredictability of the Lua environment and usage of libraries such as debug.

Example

Add to Cargo.toml:

[lib]
crate-type = ["cdylib"]

[dependencies]
mlua = { version = "0.12", 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)
}

And then (macOS example):

$ 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!

On macOS, you need to set additional linker arguments. One option is to compile with cargo rustc --release -- -C link-arg=-undefined -C link-arg=dynamic_lookup, the other is to create a .cargo/config.toml with the following content:

[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",
]

On Linux you can build modules normally with cargo build --release.

On Windows the target module will be linked with the lua5x.dll library (depending on your feature flags). Your main application should provide this library.

Module builds don't require Lua binaries or headers to be installed on the system.

Publishing to luarocks.org

There is a LuaRocks build backend for mlua modules: luarocks-build-rust-mlua.

Modules written in Rust and published to luarocks:

Safety

One of mlua's goals is to provide a safe API between Rust and Lua. Every place where the Lua C API may trigger an error longjmp is protected by lua_pcall, and the user of the library is protected from directly interacting with unsafe things like the Lua stack. There is overhead associated with this safety.

Unfortunately, mlua does not provide absolute safety even without using unsafe . This library contains a huge amount of unsafe code. There are almost certainly bugs still lurking in this library! It is surprisingly, fiendishly difficult to use the Lua C API without the potential for unsafety.

Panic handling

mlua wraps panics that are generated inside Rust callbacks in a regular Lua error. Panics can then be resumed by returning or propagating the Lua error to Rust code.

For example:

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!()

Optionally, mlua can disable Rust panic catching in Lua via pcall/xpcall and automatically resume them across the Lua API boundary. This is controlled via LuaOptions and done by wrapping the Lua pcall/xpcall functions to prevent catching errors that are wrapped Rust panics.

mlua should also be panic safe in another way as well, which is that any Lua instances or handles remain usable after a user generated panic, and such panics should not break internal invariants or leak Lua stack space. This is mostly important to safely use mlua types in Drop impls, as you should not be using panics for general error handling.

Below is a list of mlua behaviors that should be considered bugs. If you encounter them, a bug report would be very welcome:

  • If you can cause UB with mlua without typing the word "unsafe", this is a bug.

  • If your program panics with a message that contains the string "mlua internal error", this is a bug.

  • Lua C API errors are handled by longjmp. All instances where the Lua C API would otherwise longjmp over calling stack frames should be guarded against, except in internal callbacks where this is intentional. If you detect that mlua is triggering a longjmp over your Rust stack frames, this is a bug!

  • If you detect that, after catching a panic or during a Drop triggered from a panic, a Lua or handle method is triggering other bugs or there is a Lua stack space leak, this is a bug. mlua instances are supposed to remain fully usable in the face of user generated panics. This guarantee does not extend to panics marked with "mlua internal error" simply because that is already indicative of a separate bug.

Sandboxing

Please check the Luau Sandboxing page if you are interested in running untrusted Lua scripts in a controlled environment.

mlua provides the Lua::sandbox method for enabling sandbox mode (Luau only).

License

This project is licensed under the MIT license.

相关仓库
farion1231/cc-switch

A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io

Rustcrates.ioMIT Licenseai-toolsclaude-code
ccswitch.io
119.8k8k
rustdesk/rustdesk

An open-source remote desktop application designed for self-hosting, as an alternative to TeamViewer.

Rustcrates.ioGNU Affero General Public License v3.0remote-controlremote-desktop
rustdesk.com
118.6k18.1k
rust-lang/rust

Empowering everyone to build reliable and efficient software.

Rustcrates.ioApache License 2.0rustcompiler
rust-lang.org
114.8k15.4k
tauri-apps/tauri

Build smaller, faster, and more secure desktop and mobile applications with a web frontend.

Rustcrates.ioApache License 2.0rustwebview
tauri.app
109.3k3.8k
denoland/deno

A modern runtime for JavaScript and TypeScript.

Rustcrates.ioMIT Licensedenotypescript
deno.com
107.8k6.2k
oven-sh/bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one

Rustcrates.ioOtherbunbundler
bun.com
95k4.9k
unionlabs/union

The trust-minimized, zero-knowledge bridging protocol, designed for censorship resistance, extremely high security, and usage in decentralized finance.

Rustcrates.ioApache License 2.0blockchaincosmos
union.build
73.9k3.9k
rtk-ai/rtk

CLI proxy that reduces LLM token consumption by 60-90% on common dev commands. Single Rust binary, zero dependencies

Rustcrates.ioApache License 2.0agentic-codingai-coding
rtk-ai.app
72.4k4.5k
toeverything/AFFiNE

There can be more than Notion and Miro. AFFiNE(pronounced [ə‘fain]) is a next-gen knowledge base that brings planning, sorting and creating all together. Privacy first, open-source, customizable and ready to use.

TypeScriptnpmOthereditorcrdt
affine.pro
70.7k5.1k
openinterpreter/openinterpreter

A coding agent for open models like Kimi K3

Rustcrates.ioApache License 2.0coding-agentdeepseek
openinterpreter.com
67.1k5.8k
BurntSushi/ripgrep

ripgrep recursively searches directories for a regex pattern while respecting your gitignore

Rustcrates.ioThe Unlicenseripgreprecursively-search
66.4k2.7k
alacritty/alacritty

A cross-platform, OpenGL terminal emulator.

Rustcrates.ioApache License 2.0terminal-emulatorsopengl
alacritty.org
65k3.5k