Expand description
Embedding helper for lua-rs.
This crate sits above lua-vm, lua-stdlib, and lua-parse and exposes a
handle-based embedding API: a Lua state, typed Value / Table /
Function handles that root themselves via RAII, UserData for binding
Rust types, and a typed LuaError. It also provides the common setup
sequence (state, parser hook, host hooks, stdlib).
§Userdata model
Userdata behavior in lua-rs runs through real Lua metatables, exactly as in
reference Lua 5.4. The runtime builds the metatable for a type once, on the
first Lua::create_userdata for that TypeId, permanently roots it on
the state, and shares it across every later value of the type. This keeps
getmetatable, setmetatable, rawget, debug.setmetatable, and every
other reflective Lua operation behaving as in C Lua, which is what lets
lua-rs pass the upstream 5.4 test suite and stand in for C Lua in real
embedders.
Fields and methods both live on that single metatable. Register fields with
UserDataMethods::add_field_method_get / add_field_method_set and
methods with UserDataMethods::add_method / add_method_mut. The runtime
composes a single __index whose lookup order is field, then method, then
a raw add_meta_method(MetaMethod::Index, ...) if you registered one as an
escape hatch, with the symmetric composition on __newindex.
§Derive
Enable the derive feature for #[derive(LuaUserData)], #[lua_methods],
and #[lua_impl(Display, PartialEq, PartialOrd)]. The derive targets the
field API above; #[lua_methods] exposes each pub fn(&self / &mut self, ...) as obj:method(args); #[lua_impl(...)] wires __tostring, __eq,
__lt, and __le from the type’s Rust trait impls.
use lua_rs_runtime::{lua_methods, Lua, LuaUserData};
#[derive(LuaUserData, PartialEq, PartialOrd)]
#[lua(methods)]
#[lua_impl(Display, PartialEq, PartialOrd)]
struct Vec2 { pub x: f64, pub y: f64 }
#[lua_methods]
impl Vec2 {
pub fn length(&self) -> f64 { (self.x * self.x + self.y * self.y).sqrt() }
pub fn scale(&mut self, k: f64) { self.x *= k; self.y *= k; }
}§Scope: lending non-'static borrows to Lua
Lua::create_userdata takes its value by ownership, so the type must be
'static. When you instead want to lend Lua a value that lives on the Rust
stack for the duration of one call (typically a game engine’s
&mut World), use Lua::scope. A scope hands Lua a borrow that is
invalidated the moment the scope closure returns: any Lua reference that
escaped the scope fails with a clean runtime error on next use instead of
touching freed memory.
use lua_rs_runtime::{Lua, UserData, UserDataMethods};
struct Counter { value: i64 }
impl UserData for Counter {
fn add_methods<M: UserDataMethods<Self>>(m: &mut M) {
m.add_method_mut("inc", |_, this, by: i64| { this.value += by; Ok(this.value) });
}
}
let lua = Lua::new();
let mut counter = Counter { value: 0 };
lua.scope(|s| {
let ud = s.create_userdata_ref_mut(&lua, &mut counter)?;
lua.globals().set("c", &ud)?;
lua.load("c:inc(5); c:inc(7)").exec()
}).unwrap();
assert_eq!(counter.value, 12);Scope::create_function / Scope::create_function_mut do the same for
closures that capture non-'static borrows. And
AnyUserData::delegate builds a sub-userdata that re-borrows a field of
its parent on every call (world:entity(id) returning a live &mut Entity),
so an App -> World -> Component chain stays a chain of short borrows rather
than one long-held &mut. See Lua::scope for the full contract.
With the derive feature, a #[lua_methods] method that returns a
reference is registered as a delegate automatically: fn entity(&mut self, id: u32) -> &mut Entity becomes world:entity(id) with no hand-written
accessor. &mut T returns give a mutable delegate, &T a read-only one.
§Known limitations and planned work
#[lua_methods]does not yet special-case methods that returnResult<T, E>, associated functions and constructors (Type::new), orOption<T>parameters and returns.- The derive does not yet handle enums (a
register_enum::<T>()path) or the iteration,__close, and arithmetic metamethods. The runtime already supports adding these as ordinaryadd_meta_methodregistrations today.
Structs§
- AnyUser
Data - Chunk
- DynLib
Id - Opaque handle to a dynamically loaded library, allocated by a
DynLibLoadHookbackend and stored inpackage._CLIBS. - Function
- Host
Hooks - Host capabilities exposed to Lua stdlib.
- Lua
- Primary owned embedding handle.
- LuaRuntime
- A Lua state with parser and standard libraries installed.
- LuaString
- OsExecute
Result - Result returned by
OsExecuteHook, carrying the three values that C-Lua’sluaL_execresultpushes:(boolean|nil, "exit"|"signal", int). - Scope
- Handle passed to the closure body of
Lua::scope. - Table
- Thread
- Variadic
- Variable argument or return list converted element-by-element.
Enums§
- Dynamic
Symbol - Resolved dynamic-library symbol.
- LuaError
- The Lua error type. Carries a
LuaValuepayload because Lua errors can be any value (typically a string). - Meta
Method - OsExecute
Reason - Reason a shell command terminated, returned by
OsExecuteHook. - Value
- Dynamically typed owned Lua value.
Traits§
- FromLua
- From
LuaMulti - IntoLua
- Into
LuaMulti - LuaFile
Handle - Capabilities required by the io library from an OS file handle.
- User
Data - User
Data Methods