Skip to main content

LuaUserdata

Trait LuaUserdata 

Source
pub trait LuaUserdata: 'static + Sized {
    // Provided methods
    fn type_name() -> &'static str { ... }
    fn add_methods<M: UserdataMethods<Self>>(_m: &mut M) { ... }
    fn trace(&self, _m: &mut UserdataMarker<'_>) { ... }
}
Expand description

Embedder-side trait: implement on any T: 'static to expose method-rich Lua userdata via vm.set_userdata::<T>(...).

The trait’s only required method is add_methods, which defaults to registering nothing — yielding a userdata that still type-checks as "userdata" but only carries identity + __name. An empty impl (impl LuaUserdata for MyType {}) is the source-compatible bridge for B8 callers upgrading from v1.1.

§v1.1 → v1.2 migration

v1.1 Vm::create_userdata / Vm::set_userdata accepted any T: Any + 'static; v1.2 narrows the bound to T: LuaUserdata. Any existing type carries over with a one-line empty impl:

struct MyType { /* … */ }
impl LuaUserdata for MyType {}

§Contract on the host payload

T may hold Gc<...> fields provided it overrides trace to mark every such handle. The default trace is a no-op, suitable for pure host types (no Gc-managed inner state). Forgetting to override trace when T carries a Gc<Table> / Gc<LuaStr> / Gc<NativeClosure> / Gc<Coro> / Gc<Userdata> field whose lifetime is not otherwise rooted risks dangling references after collection.

v1.2 forbade Gc-bearing payloads entirely; v1.3 Phase TB lifts the limitation by giving the trait a default trace method and storing a monomorphic adapter in crate::runtime::userdata::UserdataPayload::Host.

Provided Methods§

Source

fn type_name() -> &'static str

Lua-visible type name. Used as the __name field of the generated metatable; surfaces in tostring fallback messages and in PUC-style "attempt to index a Counter value" errors. Defaults to std::any::type_name.

Source

fn add_methods<M: UserdataMethods<Self>>(_m: &mut M)

Register methods + metamethods on m. Called exactly once per T per Vm, at the first Vm::create_userdata::<T> / set_userdata::<T> — the resulting metatable is cached on the Vm keyed by TypeId::of::<T>().

Source

fn trace(&self, _m: &mut UserdataMarker<'_>)

Mark every Gc-managed handle reachable from self. The default is a no-op — override only when T directly holds Gc<Table> / Gc<LuaStr> / Gc<NativeClosure> / Gc<Coro> / Gc<Userdata> fields whose lifetime is not otherwise rooted (i.e. not pinned via Vm::pin_host and not reachable from a Lua-side table).

Called by the collector during the mark phase; the call runs synchronously, single-threaded, and must return in bounded wall time. The embedder must not allocate new GC objects, reenter the Vm, take locks, or perform I/O from inside trace — see the UserdataMarker type docs for the full contract.

§Override example
use luna_core::runtime::{Gc, Table};
use luna_core::vm::{LuaUserdata, UserdataMarker};

struct Cache { entries: Gc<Table> }
impl LuaUserdata for Cache {
    fn trace(&self, m: &mut UserdataMarker) {
        m.mark(self.entries);
    }
}

Overriding trace does not require touching any other trait method; existing B8 / v1.2 types remain source-compatible with an unchanged empty impl LuaUserdata for T {} (the default no-op runs and no Gc tracing is performed).

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§