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.
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<()>;
}// 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.0register_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>,
...
}
__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)]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.rs—example_multi_type()
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)])?;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.0Runnable example: See
examples/luars-example/src/main.rs—example_push_existing()
- Type Conversions — detailed conversion rules for parameters and return values
- Complete Examples — multiple end-to-end usage examples