Skip to main content

Crate lua_rs_runtime

Crate lua_rs_runtime 

Source
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 return Result<T, E>, associated functions and constructors (Type::new), or Option<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 ordinary add_meta_method registrations today.

Structs§

AnyUserData
Chunk
DynLibId
Opaque handle to a dynamically loaded library, allocated by a DynLibLoadHook backend and stored in package._CLIBS.
Function
HostHooks
Host capabilities exposed to Lua stdlib.
Lua
Primary owned embedding handle.
LuaRuntime
A Lua state with parser and standard libraries installed.
LuaString
OsExecuteResult
Result returned by OsExecuteHook, carrying the three values that C-Lua’s luaL_execresult pushes: (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§

DynamicSymbol
Resolved dynamic-library symbol.
LuaError
The Lua error type. Carries a LuaValue payload because Lua errors can be any value (typically a string).
MetaMethod
OsExecuteReason
Reason a shell command terminated, returned by OsExecuteHook.
Value
Dynamically typed owned Lua value.

Traits§

FromLua
FromLuaMulti
IntoLua
IntoLuaMulti
LuaFileHandle
Capabilities required by the io library from an OS file handle.
UserData
UserDataMethods

Functions§

install_parser_hook

Type Aliases§

Error
Result