22次发布
0.9.1 | 2023年12月15日 |
---|---|
0.9.0-alpha4 | 2023年1月8日 |
0.9.0-alpha3 | 2022年9月15日 |
0.9.0-alpha1 | 2022年7月24日 |
0.2.0 | 2020年10月28日 |
#48 in FFI
67每月下载
用于 4 个crate(2个直接使用)
510KB
4K SLoC
tealr
一个用于增强rlua和mluacrate提供的API的crate
它通过以下方式实现这一目标
- 允许API具有易于访问的嵌入式文档
- 允许使用tealr_doc_gen 将文档构建成网页
- 与文档一起,
tealr
还允许您在API使用的类型上更加精确。想想泛型方法和类型化的lambda。不再需要Lua::Value
- 添加宏以使与静态类型Lua方言teal一起工作更加容易。
它通过添加新特性和替换/扩展rlua 和 mlua 中的现有特性来实现。因此,tealr公开的API与这两个crate的API尽可能相似。
它还包含一些宏,可以轻松生成新类型,以更好地表达API的类型。
示例:instance.help()
所示库为 https://github.com/lenscas/tealsql
HTML渲染文档
渲染的HTML也可在 https://lenscas.github.io/tealsql/ 获取
注意
Both rlua
和 mlua
都位于 rlua
和 mlua
特性标志之后。
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
尽管可以使用来自rlua
和mlua
的lua::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