Note
Feel free to use this crate and start working with ideas and features that could be useful.
Pull requests and contribution are encouraged
If you want to discuss this project, you can do that here
The goal of this project is to add a light convenience layer wrapping the mlua crate. The goal isn't to change the way that mlua is used, but instead to make lua embedded development in Rust more enjoyable.
Tealr: A project to enhance and extendmluawith a focus in type information and documentation along with a type syntax in the lua code itself with thetealrsyntax.- This crate is a great choice if you need: type syntax, type information, documentation generation
-
Helper Traits
LuaExtras- Manipulate the lua
pathandcpathvariables withappend,prepend, andsetmethods for each variant. It also includes the ability to add multiple paths with each variant. - Set global variables and functions with
set_global("value", "value")andset_global_function("func", |lua, ()| Ok(()))which wold replacelua.globals().set("value", "value)andlua.globals().set("func", lua.create_function(|lua, ()| Ok(()))?)respectively
- Manipulate the lua
-
Typed Lua Traits
Typed- Generate a
TypeandParamfor a rust type so it can be used both as a type and as a parameter for a function
- Generate a
TypedUserData- Typed variant of
mlua::UserDatawith an additionaladd_documentationmethod to add doc comments to theUserDatatype - An extra
documentmethod is added to theTypedDataFieldsandTypedDataMethodsforadd_fieldsandadd_methods. This will queue doc comments to be added to the next field or method that is added. - All types from function parameters and and return types are stored for fields, functions, and methods.
- This trait is mainly used when generating type definitions. If it is called through the
UserDataderive macro it will ignore all types and documentation
- Typed variant of
TypedDataFields: Implemented on a generator forTypedUserData(add_fields)TypedDataMethods: Implemented on a generator forTypedUserData(add_methods)TypedDataDocumentation: Implemented on a generator forTypedUserData(add_documentation)
-
Derive Macros
Typed: Auto implement theTypedtrait to get type information for bothstructandenumUserData: Auto implement themlua::UserDatatrait for rust types that also implementTypedUserData. This will pass through theUserDataadd_methodsandadd_fieldsto theTypedUserData's version. This will ignore all documentation and types.
- Fully featured definition file generation
- Fully featured documentation generation
- Fully featured addon generator when creating a lua modules with
mlua'smodulefeature - Better and more informative type errors associated with lua type definitions and output generation
- More expressive way of defining exposed lua api types
- Generic types
- Doc comments for params and return types
Helpers
use mlua::{Lua, Table, Function, Variadic, Value};
fn main() -> mlua::Result<()> {
let lua = Lua::new();
// Prepend path to the lua `path`
let path = lua.globals().get::<Table>("package")?.get::<String>("path");
lua.globals().get::<Table>("package")?.set("path", format!("?.lua;{path}"))?;
let temp = lua.create_table()?;
temp.set("getName", lua.create_function(|lua, ()| Ok("name"))?;
// Get a nested function: `table.unpack`
let unpack = lua.globals().get::<Table>("table")?.get::<_, Function>("unpack")?;
// Call the `table.unpack` function
let _ = unpack.call::<Variadic<Value>>(temp)?;
Ok(())
}use mlua_extras::{
mlua::{self, Lua, Table, Variadic, Value}
extras::{Require, LuaExtras},
typed::TypedFunction,
function,
};
fn main() -> mlua::Result<()> {
let lua = Lua::new();
// Prepend path to the lua `path`
lua.prepend_path("?.lua")?;
let temp = lua.create_table()?;
temp.set("name", "MluaExtras")?;
// Get a nested function: `table.unpack`
let unpack = lua.require::<TypedFunction<Table, Variadic<Value>>>("table.unpack")?;
// Call the `table.unpack` function
let _ = unpack.call(temp)?;
Ok(())
}Types
use serde::Deserialize;
use mlua_extras::{
mlua::{self, Lua, Table, Variadic, Value},
extras::{ Require, LuaExtras },
typed::{
generator::{Definition, Definitions, DefinitionFileGenerator},
TypedFunction, TypedUserData
},
Typed, UserData, function,
};
#[derive(Default, Debug, Clone, Copy, Typed, Deserialize)]
enum SystemColor {
#[default]
Black,
Red,
Green,
Yellow,
Blue,
Cyan,
Magenta,
White,
}
#[derive(Debug, Clone, Copy, Typed, UserData, Deserialize)]
#[serde(untagged)]
enum Color {
System(SystemColor),
Xterm(u8),
Rgb(u8, u8, u8),
}
impl Default for Color {
fn default() -> Self {
Color::System(SystemColor::default())
}
}
impl<'lua> FromLua<'lua> for Color {
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> mlua::prelude::LuaResult<Self> {
match value {
Value::UserData(data) => data.borrow::<Self>().map(|v| *v),
// Use serde deserialize if not userdata
other => lua.from_value(other),
}
}
}
#[derive(Debug, Clone, Copy, Typed, UserData, Deserialize)]
struct Example {
color: Color
}
impl TypedUserData for Example {
fn add_documentation<F: mlua_extras::typed::TypedDataDocumentation<Self>>(docs: &mut F) {
docs.add("This is a doc comment section for the overall type");
}
fn add_fields<'lua, F: TypedDataFields<'lua, Self>>(fields: &mut F) {
fields
.document("Example complex type")
.add_field_method_get_set(
"color",
|_lua, this| Ok(this.color),
|_lua, this, clr: Color| {
this.color = clr;
Ok(())
},
);
}
}
fn main() -> mlua::Result<()> {
let definitions = Definitions::generate()
.define("init", Definition::generate()
.register::<SystemColor>("System")?
.register::<Color>("Color")?
.register::<Example>("Example")
.document("Example module")
.value::<Example>("example")
.function::<Color, ()>("printColor", ())
.document("Greet the name that was passed in")
.param("name", "Name of the person to greet")
.function::<String, ()>("greet", ())
)
.finish();
let gen = DefinitionFileGenerator::new(definitions);
for (name, writer) in gen.iter() {
// Writes to a new file `init.d.lua`
writer.write_file(name).unwrap();
}
println!();
Ok(())
}Produces the following definition file
--- init.d.lua
--- @meta
--- @alias System "Black"
--- | "Red"
--- | "Green"
--- | "Yellow"
--- | "Blue"
--- | "Cyan"
--- | "Magenta"
--- | "White"
--- @alias Color SystemColor
--- | integer
--- | [integer, integer, integer]
--- This is a doc comment section for the overall type
--- @class Example
--- Example complex type
--- @field color Color
--- Example module
--- @type Example
example = nil
--- Greet the name that was passed in
--- @param name string Name of the person to greet
function greet(name) end
--- @param param0 Color
function printColor(param0) end