Skip to content

Latest commit

 

History

History
151 lines (112 loc) · 4.45 KB

File metadata and controls

151 lines (112 loc) · 4.45 KB

register_type — Type Registration

register_type_of and register_type are methods on LuaState that create a class table in the Lua global environment, exposing a Rust type's associated functions (such as constructors) to Lua.

API Signatures

impl LuaState {
    /// Preferred — uses the LuaRegistrable trait (auto-generated by #[lua_methods])
    pub fn register_type_of<T: LuaRegistrable>(&mut self, name: &str) -> LuaResult<()>;

    /// Manual — pass an explicit method list
    pub fn register_type(
        &mut self,
        name: &str,                               // Lua global name
        static_methods: &[(&str, CFunction)],     // static method list
    ) -> LuaResult<()>;
}

Basic Usage

// Get the LuaState
let state = vm.main_state();

// Preferred: register using the type parameter
state.register_type_of::<Point>("Point")?;

// Alternative: register with explicit method list
// state.register_type("Point", Point::__lua_static_methods())?;

After registration, a global table named "Point" appears in Lua:

-- Point is a table
print(type(Point))       -- "table"

-- Point.new is a function
print(type(Point.new))   -- "function"

-- Create an instance
local p = Point.new(3, 4)
print(p.x, p.y)          -- 3.0  4.0
print(p:distance())      -- 5.0

How It Works

register_type performs the following steps internally:

1. create_table(0, n)          → create an empty table with n hash slots
2. For each (name, func):
   a. create_string(name)      → create/intern the string key
   b. LuaValue::cfunction(func) → wrap as a Lua CFunction value
   c. raw_set(table, key, val) → set into the table
3. set_global(name, table)     → set the table as a global variable

The resulting structure in the Lua global environment:

_G["Point"] = {
    new    = <CFunction: __lua_static_new>,
    origin = <CFunction: __lua_static_origin>,
    ...
}

Where __lua_static_methods() Comes From

__lua_static_methods() is an inherent method auto-generated by #[lua_methods]. It returns a static array containing all pub fn items without a self parameter, paired with their C wrapper functions.

#[lua_methods]
impl Point {
    pub fn new(x: f64, y: f64) -> Self { ... }    // ← included
    pub fn origin() -> Self { ... }                // ← included
    pub fn distance(&self) -> f64 { ... }          // ← excluded (has self)
}

// Generates:
// Point::__lua_static_methods() → &[("new", __lua_static_new), ("origin", __lua_static_origin)]

Registering Multiple Types

You can register multiple types:

let state = vm.main_state();
state.register_type_of::<Point>("Point")?;
state.register_type_of::<Color>("Color")?;
state.register_type_of::<Entity>("Entity")?;
local p = Point.new(1, 2)
local c = Color.new(255, 0, 0)

Runnable example: See examples/luars-example/src/main.rsexample_multi_type()

Manually Registering Custom Methods

You can also pass a custom method list instead of relying on macros:

fn my_custom_new(l: &mut LuaState) -> LuaResult<usize> {
    // Manually implement construction logic
    let x = l.get_arg(1).and_then(|v| v.as_number()).unwrap_or(0.0);
    let ud = LuaUserdata::new(MyStruct { x });
    let val = l.create_userdata(ud)?;
    l.push_value(val)?;
    Ok(1)
}

// Manual registration with a custom method list
state.register_type("MyStruct", &[("new", my_custom_new as CFunction)])?;

Working with Pre-existing Userdata Instances

register_type only registers a class table (for constructors). It does not affect existing instances. Both can coexist:

let state = vm.main_state();

// Register the class table — provides Point.new()
state.register_type_of::<Point>("Point")?;

// Also register a pre-created instance as a global variable
let origin = LuaUserdata::new(Point { x: 0.0, y: 0.0 });
let origin_val = state.create_userdata(origin)?;
state.set_global("ORIGIN", origin_val)?;
-- Both approaches work
local p = Point.new(3, 4)    -- created via constructor
print(ORIGIN.x, ORIGIN.y)    -- uses pre-created instance: 0.0  0.0

Runnable example: See examples/luars-example/src/main.rsexample_push_existing()

Next