#lua #类型 #生成 #teal #生成文档 #网页 #类型生成

tealr

一个用于增强rlua和mluacrate提供的API的crate

22次发布

0.9.1 2023年12月15日
0.9.0-alpha42023年1月8日
0.9.0-alpha32022年9月15日
0.9.0-alpha12022年7月24日
0.2.0 2020年10月28日

#48 in FFI

Download history 348/week @ 2024-04-01 284/week @ 2024-04-08 29/week @ 2024-04-15 117/week @ 2024-04-22 38/week @ 2024-04-29 88/week @ 2024-05-06 55/week @ 2024-05-13 29/week @ 2024-05-20 46/week @ 2024-05-27 24/week @ 2024-06-03 46/week @ 2024-06-10 47/week @ 2024-06-17 16/week @ 2024-06-24 15/week @ 2024-07-08 27/week @ 2024-07-15

67每月下载
用于 4 个crate(2个直接使用)

MIT/Apache

510KB
4K SLoC

tealr

一个用于增强rlua和mluacrate提供的API的crate

它通过以下方式实现这一目标

  • 允许API具有易于访问的嵌入式文档
  • 允许使用tealr_doc_gen 将文档构建成网页
  • 与文档一起,tealr 还允许您在API使用的类型上更加精确。想想泛型方法和类型化的lambda。不再需要 Lua::Value
  • 添加宏以使与静态类型Lua方言teal一起工作更加容易。

它通过添加新特性和替换/扩展rluamlua 中的现有特性来实现。因此,tealr公开的API与这两个crate的API尽可能相似。

它还包含一些宏,可以轻松生成新类型,以更好地表达API的类型。

示例:instance.help()

所示库为 https://github.com/lenscas/tealsql

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

HTML渲染文档

渲染的HTML也可在 https://lenscas.github.io/tealsql/ 获取

注意

Both rluamlua 都位于 rluamlua 特性标志之后。

Tealr导出这些crate,并允许您通过它设置标志(转发标志的前缀可以是rlua_mlua_。例如,如果您想启用mlua/async,则需要启用tealr/mlua_async)。

请勿直接在mlua/rlua中设置功能标志,而是通过tealr设置。这些crate的API会根据设置的功能标志而改变,而tealr需要了解这些变化。

向lua/teal暴露值

将类型暴露给lua作为userdata,使用tealr与使用rlua和mlua几乎相同

Rlua

use tealr::ToTypename;
#[derive(Clone, tealr::rlu::UserData, ToTypename)]
struct ExampleRlua {}

//now, implement rlu::TealData.
//This tells rlua what methods are available and tealr what the types are
impl tealr::rlu::TealData for ExampleRlua {
    //implement your methods/functions
    fn add_methods<'lua, T: tealr::rlu::TealDataMethods<'lua, 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<ExampleRlua>)| {
            Ok(x)
        });
        ///This creates the instance.help() function, which returns the documentation as a string.
        methods.generate_help();
    }
}

Mlua

use tealr::ToTypename;
#[derive(Clone, tealr::mlu::UserData, ToTypename)]
struct ExampleMlua {}
impl<'lua> FromLua<'lua> for ExampleMlua {
    fn from_lua(value: mlua::prelude::LuaValue<'lua>, _: &'lua 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<'lua, T: tealr::mlu::TealDataMethods<'lua, 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();
    }
}

用更好的类型信息替换lua::Value

尽管可以使用来自rluamlualua::Value,但从类型描述的角度来看它们并不理想。使用它们将损害您的文档。

为了帮助避免使用lua::Value,tealr提供了一些新的类型和宏,可以帮助您在API中更好地定义类型。

简单联合

这些允许您轻松创建一个类型,它只是您提供的类型之一。

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

类型化函数

虽然mlua和rlua的正常函数类型完全可以使用,但它不包含任何类型信息。为了帮助在API中添加更多类型信息,tealr提供了包含类型信息的函数类型的版本。

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);

泛型

为了与类型化函数配合使用,tealr还提供了一种模拟泛型的方法。尽管由于无法对泛型设置界限,它们最初看起来只是使用lua::Value的另一种方式,但它们仍然非常有用,可以正确地建模输入和输出之间的关系。

在下面的示例中,我们调用一个泛型函数,并将其返回值返回给lua。得益于泛型的使用,方法返回类型与lambda返回类型相同。如果使用lua::Value,则这并不清楚。

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<'lua, T: TealDataMethods<'lua, Self>>(methods: &mut T) {
        methods.add_method(
            "generic_function_callback",
            |lua, _, fun: TypedFunction<String, X>| {
                fun.call("A nice string!".to_string())
            },
        );
    }
}

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


对于rlua,您只需将mlua替换为rlua即可。

Teal集成

Teal语言基本上是lua的静态类型变体,甚至可以修改为在编译到lua之前在lua vm中运行。

由于这个原因,以及tealr专注于启用更丰富的类型API,这两个项目可以很好地协同工作。然而,为了进一步帮助绑定这两个项目,tealr为想要使用teal的用户提供了一些额外的辅助工具。

将内联teal代码编译成lua

rlua和mlua都允许您运行嵌入在应用程序中的lua代码。

同样,tealr允许您在编译应用程序时编译嵌入的teal代码到lua。然后,它可以由rlua和mlua执行。

这意味着您可以在Rust代码库中的小型脚本中利用teal的静态类型系统。

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

嵌入teal编译器

Teal使lua vm能够将teal文件加载为普通lua文件。

Tealr通过暴露一个可以将teal编译器嵌入到您的应用程序中的宏,使从rust内部执行此操作变得更容易。此函数接受一个字符串,即需要获取依赖的文件。

use tealr::embed_compiler;
let compiler = embed_compiler!("v0.13.1");
#[cfg(feature = "rlua")]
{
    let res : u8 = tealr::rlu::rlua::Lua::new().context(|ctx| {
        let code = compiler("example/basic_teal_file");
        ctx.load(&code).set_name("embedded_compiler")?.eval()
    })?;
};

#[cfg(feature = "mlua")]
{
    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>>(())

tealr可以使用几个来源来获取编译器。如果没有指定来源,则默认为github发布版。其他来源可以按以下方式指定。

//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"));

您可以在这里找到更长的带有每个调用功能的注释。

依赖项

约2-14MB
约172K SLoC