Crate tealr

Source
Expand description

§tealr

A crate to enhance the APIs provided by mlua

It aims to do this by improving the following:

  • Allow the documentation to be built to web pages (using tealr_doc_gen )

  • Generate definition files describing your API (using tealr_doc_gen )

  • Allow the api to have easily accessible documentation embedded into it

  • To go along with the documentation, tealr also allow you to be more precise in the types your api works with. Think generic methods and typed lambdas.

  • macro’s to make new types easier to create. No more mlua::Value!

  • Add macros to make it easier to work with teal, a statically typed dialect of lua.

It does this by adding new traits and replacing/extending the existing ones from mlua. As a result, the api that tealr exposes is as similar as the api from mlua as possible.

§Example of instance.help()

The library shown is https://github.com/lenscas/tealsql

https://github.com/lenscas/tealr/tree/master/tealr/images/help_example.gif

§html rendered documentation

Rendered html is also available at https://lenscas.github.io/tealsql/

§Expose a value to lua/teal

Exposing types to lua as userdata is almost the same using tealr as it is using mlua

§Mlua:
use tealr::ToTypename;
#[derive(Clone, tealr::mlu::UserData, ToTypename)]
struct ExampleMlua {}
impl FromLua for ExampleMlua {
    fn from_lua(value: mlua::prelude::LuaValue, _: &Lua) -> Result<Self> {
        value
            .as_userdata()
            .map(|x| x.take())
            .unwrap_or(Err(mlua::Error::FromLuaConversionError {
                from: value.type_name(),
                to: "Example",
                message: None,
            }))
    }
}

impl tealr::mlu::TealData for ExampleMlua {
    //implement your methods/functions
    fn add_methods<T: tealr::mlu::TealDataMethods<Self>>(methods: &mut T) {
        methods.document_type("This is documentation added to the type itself.");
        methods.document("This documentation gets added to the exposed function bellow.");
        methods.add_method("example_method", |_, _, x: i8| Ok(x));
        methods.add_method_mut("example_method_mut", |_, _, x: (i8, String)| Ok(x.1));
        methods.add_function("example_function", |_, x: Vec<String>| Ok((x, 8)));
        methods.document("***You*** can also embed markdown to the documentation, which gets picked up by [tealr_doc_gen](https://github.com/lenscas/type_generator)`");
        methods.document("It is also possible to use this function multiple times. These are added as paragraphs.");
        methods.add_function_mut("example_function_mut", |_, x: (bool, Option<ExampleMlua>)| {
            Ok(x)
        });
        ///This creates the instance.help() function, which returns the documentation as a string.
        methods.generate_help();
    }
}

§Replacing lua::Value with better type information

Though it is perfectly possible to use the lua::Value from mlua it isn’t the most descriptive type wise. Using it will hurt your documentation as a result.

To help avoid lua::Value tealr comes with new types and macros that help you define your API better type wise.

§Simple unions:

These allow you to easily create a type that is only one of the types you give.

use tealr::{
    create_union_mlua,
};
create_union_mlua!(enum YourTypeName = i32 | String);

§Typed functions:

Though the normal function type from mlua is perfectly useable it doesn’t contain contain any type information. To help add more type information to your api tealr comes with its own version of this function type that contains type information.

use tealr::{
    mlu::{
        mlua::Lua,
        TypedFunction
    },
}

let lua = mlua::Lua::new();
let add_1 = TypedFunction::<u8, u8>::from_rust(|_lua, x| Ok(x + 1), &lua)?;

assert_eq!(add_1.call(2)?, 3);

§Generics

To go along with typed functions, tealr also comes with a way to mimic generics. Though they at first glance will just look like another way to use lua::Value due to not being able to put bounds on the generic, they are still very useful to properly model how input and output rely on each other.

In the following example we take a generic function and call it, returning whatever it returned back to lua. Thanks to the use of generics, it i clear that the return type of the method is equal to the return type of the lambda. If lua::Value was used instead this was not clear.

use mlua::IntoLua;
use tealr::{
    create_generic_mlua,
    mlu::{mlua::FromLua, TealData, TealDataMethods, TypedFunction,UserData},
    ToTypename, TypeWalker,
};

create_generic_mlua!(X);

#[derive(Clone, UserData, ToTypename)]
struct Example {}

impl TealData for Example {
    fn add_methods<T: TealDataMethods<Self>>(methods: &mut T) {
        methods.add_method(
            "generic_function_callback",
            |lua, _, fun: TypedFunction<String, X>| {
                fun.call("A nice string!".to_string())
            },
        );
    }
}

impl FromLua for Example {
    fn from_lua(value: mlua::prelude::LuaValue, _: &Lua) -> Result<Self> {
        value
            .as_userdata()
            .map(|x| x.take())
            .unwrap_or(Err(mlua::Error::FromLuaConversionError {
                from: value.type_name(),
                to: "Example",
                message: None,
            }))
    }
}

§Teal integration

The teal language is a statically typed variant of lua and can even be made to run in the lua vm without compiling to lua first.

As a result of this and tealr’s focus on enabling a richer typed api causes the 2 projects to work well together. However, to further help bind the 2 projects, tealr contains some extra helpers for those that want to use teal.

§Compile inline teal code into lua

Mlua allow you to run lua code embedded in your application.

Similarly, tealr allows you to compile embedded teal code to lua while compiling your application. This can then be executed by mlua.

This means that you can make use of teal’s static type system even for small scripts inside your rust codebase.

use tealr::compile_inline_teal;
let code = compile_inline_teal!("local x : number = 5 return x");

§Embed the teal compiler

Teal makes it possible for the lua vm to load teal files as if they are normal lua files.

Tealr makes doing this from withing rust a bit easier, by exposing a macro that can embed the teal compiler in your application and create a function that creates the needed lua code to set the VM up. This function takes a string, which is the file that needs to get required.

use tealr::embed_compiler;
let compiler = embed_compiler!("v0.13.1");

{
    let code = compiler("example/basic_teal_file");
    let lua = tealr::mlu::mlua::Lua::new();
    let res: u8 = lua.load(&code).set_name("embedded_compiler").eval()?;
};
Ok::<(), Box<dyn std::error::Error>>(())

There are a few sources tealr can use to get the compiler. If no source is specified it defaults to github releases. Other sources can be specified as follows:

//get the teal compiler using the given path
embed_compiler!(Local(path = "some/path/to/tl.tl"));
//this uses luarocks to try and discover the location of the compiler
embed_compiler!(Local());
//download the compiler at compile time from github (default)
embed_compiler!(GitHub(version = "v0.13.1"));
//download the compiler at compile time from luarocks
embed_compiler!(Luarocks(version = "v0.13.1"));

You can find longer ones with comments on what each call does here

Modules§

mlu
traits and types specific to mlua

Macros§

compile_inline_teal
Compiles the given teal code at compile time to lua.
create_generic_mlua
This macro creates a new type that acts as similar as possible to mlua::Value however, it acts as a generic type instead of being translated as any.
create_union_mlua
Creates a new type that is a union of the types you gave.
embed_compiler
Embeds the teal compiler, making it easy to load teal files directly.
mlua_create_named_parameters
Creates a type that allows you to give names to the positional parameters. The names only show up in the documentation and definition files. Making them great to add just a bit more of documentation in the function signature itself
new_type
An easy way to implement TypeName::get_type_parts if it only needs to return a single type without generics.

Structs§

EnumGenerator
contains all the information needed to create a teal enum.
ExportedFunction
Contains the data needed to write down the type of a function
ExtraPage
Used to document what global instances get made by the module
Field
Represents a field, containing both the name and its type
FunctionParam
A parameter for a function
FunctionRepresentation
The representation of a function type
GlobalInstance
Used to document what global instances get made by the module
MapRepresentation
The representation of a Map<K,T> type
Name
The name of a type
NameContainer
Simple wrapper around Vec<u8>
RecordGenerator
contains all the information needed to create a record
SingleType
A singular type
TealType
Represents a type
TypeCreator
Automatically generated for exporting to lua
TypeWalker
This generates the .d.tl files

Enums§

KindOfType
Keeps track of any special treatment a type needs to get
NamePart
The parts that a name consists of
Type
A type
TypeGenerator
Container of all the information needed to create the .d.tl file for your type.

Traits§

TealMultiValue
A collection of TealValues.
ToTypename
This trait turns a A into a type representation for Lua/Teal
TypeBody
Creates the body of the type, so the functions and fields it exposes.
TypeName
A trait to collect the required type information like the name of the type.

Functions§

get_generics
Gets the generics of any given type
get_tealr_version
Gets the current version of tealr.
new_type_to_oldDeprecated
Turns a type in the new representation into the old representation
type_parts_to_str
Used to turn an entire type (Cow<'static, [NamePart]>) into a string representing this type

Derive Macros§

ToTypename
Implements ToTypename.