Skip to content

Commit

Permalink
Merge pull request #81 from lenscas/feature/better_format
Browse files Browse the repository at this point in the history
improve the format used to store type information.
  • Loading branch information
lenscas authored Dec 3, 2023
2 parents 6545a22 + 5909e43 commit a8872b3
Show file tree
Hide file tree
Showing 71 changed files with 2,206 additions and 3,105 deletions.
32 changes: 22 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# tealr
A crate to enhance the APIs provided by the [rlua](https://crates.io/crates/rlua) and [mlua](https://crates.io/crates/mlua) crates

A crate to enhance the APIs provided by the [rlua](https://crates.io/crates/rlua) and [mlua](https://crates.io/crates/mlua) crates

It aims to do this by improving the following:

- Allow the api to have easily accessible documentation embedded into it
- Allow the documentation to be built to web pages (using [tealr_doc_gen](https://github.com/lenscas/tealr_doc_gen) )
- 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. No more `Lua::Value`
Expand All @@ -19,21 +20,26 @@ The library shown is <https://github.com/lenscas/tealsql>
![<https://github.com/lenscas/tealr/tree/master/tealr/images/help_example.gif>](https://raw.githubusercontent.com/lenscas/tealr/master/images/help_example.gif)

## html rendered documentation

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

## Note:

Both `rlua` and `mlua` are behind the feature flags `rlua` and `mlua`.

Tealr reexports these crates and allows you to set flags through it (the forwarded flags are the same with either the prefix `rlua_` or `mlua_`. For example if you want to enable `mlua/async` then you need to enable `tealr/mlua_async`).

Please, do not set feature flags directly in mlua/rlua and instead set them through tealr. The API of these crates can change depending on what feature flags are set and tealr needs to be made aware of those changes.

## Expose a value to lua/teal

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

#### Rlua:

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

//now, implement rlu::TealData.
Expand All @@ -57,10 +63,12 @@ impl tealr::rlu::TealData for ExampleRlua {
}
}
```

Mlua:

```rust ignore
use tealr::TypeName;
#[derive(Clone, tealr::mlu::UserData, TypeName)]
use tealr::ToTypename;
#[derive(Clone, tealr::mlu::UserData, ToTypename)]
struct ExampleMlua {}
impl tealr::mlu::TealData for ExampleMlua {
//implement your methods/functions
Expand All @@ -82,6 +90,7 @@ impl tealr::mlu::TealData for ExampleMlua {
```

## Replacing lua::Value with better type information

Though it is perfectly possible to use the `lua::Value` from `rlua` and `mlua` they aren't the most descriptive type wise. Using them 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.
Expand All @@ -100,6 +109,7 @@ use tealr::{
};
create_union_mlua!(enum YourTypeName = i32 | String);
```

### Typed functions:

Though the normal function type from both mlua and rlua 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.
Expand All @@ -118,24 +128,24 @@ 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.


```rust ignore
use mlua::ToLua;
use tealr::{
create_generic_mlua,
mlu::{mlua::FromLua, TealData, TealDataMethods, TypedFunction,UserData},
TypeName, TypeWalker,
ToTypename, TypeWalker,
};

create_generic_mlua!(X);

#[derive(Clone, UserData, TypeName)]
#[derive(Clone, UserData, ToTypename)]
struct Example {}
impl TealData for Example {
fn add_methods<'lua, T: TealDataMethods<'lua, Self>>(methods: &mut T) {
Expand All @@ -158,6 +168,7 @@ The [teal](https://github.com/teal-language/tl) language is basically just a sta
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

Both rlua and 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 rlua and mlua.
Expand All @@ -175,7 +186,6 @@ Teal makes it possible for the lua vm to load teal files as if they are normal l

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.


```rust no_run
use tealr::embed_compiler;
let compiler = embed_compiler!("v0.13.1");
Expand All @@ -195,14 +205,16 @@ let compiler = embed_compiler!("v0.13.1");
};
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:

```rust ignore
//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)
//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"));
Expand Down
8 changes: 4 additions & 4 deletions examples/mlua/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ use tealr::{
mlua::{Lua, Result},
TealData, TealDataMethods, UserData,
},
TypeName, TypeWalker,
ToTypename, TypeWalker,
};
//this example shows how the new traits allow you to generate the .d.tl file
//and shows how to use them to share data with lua
//It also shows how to generate the file
//NOTE: All it does it generate the contents of the file. Storing it is left to the user.

//First, create the struct you want to export to lua.
//instead of both deriving UserData and TypeName you can also
//instead of both deriving UserData and ToTypename you can also
//derive TealDerive, which does both. However you will still need to import
//UserData and TypeName
//UserData and ToTypename
//The clone is only needed because one of the example functions has it as a parameter
#[derive(Clone, UserData, TypeName)]
#[derive(Clone, UserData, ToTypename)]
struct Example {}

//now, implement TealData. This tells rlua what methods are available and tealr what the types are
Expand Down
15 changes: 4 additions & 11 deletions examples/mlua/manual.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use tealr::{
mlua::{Lua, Result, UserData, UserDataMethods},
TealData, TealDataMethods, UserDataWrapper,
},
new_type, NamePart, TypeBody, TypeName, TypeWalker,
ToTypename, TypeBody, TypeWalker,
};
//This example shows how to manually implement UserData using TealData
//As you can see the amount of code is small and easy copy/paste able.
Expand Down Expand Up @@ -38,17 +38,10 @@ impl TealData for Example {
}
}

impl TypeName for Example {
impl ToTypename for Example {
//how the type should be called in lua.
fn get_type_parts() -> std::borrow::Cow<'static, [NamePart]> {
//this
new_type!(Example)
//is the same as this:
// std::borrow::Cow::Borrowed(&[NamePart::Type(TealType {
// name: std::borrow::Cow::Borrowed("Example"),
// type_kind: tealr::KindOfType::External,
// generics: None,
// })])
fn to_typename() -> tealr::Type {
tealr::Type::new_single("Example", tealr::KindOfType::External)
}
}

Expand Down
12 changes: 4 additions & 8 deletions examples/mlua/manual_documentation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use tealr::{
mlua::{Lua, Result, UserData, UserDataMethods},
TealData, TealDataMethods, UserDataWrapper,
},
NamePart, TealType, TypeBody, TypeName, TypeWalker,
ToTypename, TypeBody, TypeWalker,
};
//This example shows how to manually implement UserData using TealData
//As you can see the amount of code is small and easy copy/paste able.
Expand Down Expand Up @@ -50,14 +50,10 @@ impl TealData for Example {
}
}

impl TypeName for Example {
impl ToTypename for Example {
//how the type should be called in lua.
fn get_type_parts() -> std::borrow::Cow<'static, [NamePart]> {
std::borrow::Cow::Borrowed(&[NamePart::Type(TealType {
name: std::borrow::Cow::Borrowed("Example"),
type_kind: tealr::KindOfType::External,
generics: None,
})])
fn to_typename() -> tealr::Type {
tealr::Type::new_single("Example", tealr::KindOfType::External)
}
}

Expand Down
4 changes: 2 additions & 2 deletions examples/mlua/named_parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ use tealr::{
mlua::{Lua, Result},
TealData, TealDataMethods, UserData,
},
TypeName, TypeWalker,
ToTypename, TypeWalker,
};
//this example shows how to use the create_named_parameters! macro to create methods which has names for their parameters in the documentation
#[derive(Clone, UserData, TypeName)]
#[derive(Clone, UserData, ToTypename)]
struct Example {}

impl TealData for Example {
Expand Down
6 changes: 3 additions & 3 deletions examples/mlua/userdata_proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use tealr::{
mlua::{Lua, Result},
TealData, TealDataMethods, UserData, UserDataProxy,
},
TypeName, TypeWalker,
ToTypename, TypeWalker,
};
//this example shows how to expose a `proxy` type to enable calling static global functions from anywhere.

Expand All @@ -12,7 +12,7 @@ use tealr::{
//derive TealDerive, which does both. However you will still need to import
//UserData and TypeName
//The clone is only needed because one of the example functions has it as a parameter
#[derive(Clone, UserData, TypeName)]
#[derive(Clone, UserData, ToTypename)]
struct Example {
float: f32,
}
Expand Down Expand Up @@ -73,7 +73,7 @@ fn main() -> Result<()> {

//how you pass this type to lua hasn't changed:
let lua = Lua::new();
tealr::mlu::set_global_env(Export::default(), &lua).unwrap();
tealr::mlu::set_global_env(Export {}, &lua).unwrap();
let globals = lua.globals();
globals.set("test", Example { float: 42.0 })?;
let code = "
Expand Down
10 changes: 4 additions & 6 deletions examples/rlua/manual.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use tealr::{
new_type,
rlu::{
rlua::{Lua, Result, UserData, UserDataMethods},
TealData, TealDataMethods, UserDataWrapper,
},
NamePart, RecordGenerator, TypeBody, TypeGenerator, TypeName, TypeWalker,
RecordGenerator, ToTypename, TypeBody, TypeGenerator, TypeWalker,
};
//This example shows how to manually implement UserData using TealData
//As you can see the amount of code is small and easy copy/paste able.
Expand Down Expand Up @@ -32,13 +31,12 @@ impl TealData for Example {
}
}

impl TypeName for Example {
impl ToTypename for Example {
//how the type should be called in lua.
fn get_type_parts() -> std::borrow::Cow<'static, [NamePart]> {
new_type!(Example)
fn to_typename() -> tealr::Type {
tealr::Type::new_single("Example", tealr::KindOfType::External)
}
}

impl UserData for Example {
fn add_methods<'lua, T: UserDataMethods<'lua, Self>>(methods: &mut T) {
let mut wrapper = UserDataWrapper::from_user_data_methods(methods);
Expand Down
9 changes: 4 additions & 5 deletions examples/rlua/manual_documentation.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use tealr::{
new_type,
rlu::{
rlua::{Lua, Result, UserData, UserDataMethods},
TealData, TealDataMethods, UserDataWrapper,
},
NamePart, TypeBody, TypeName, TypeWalker,
ToTypename, TypeBody, TypeWalker,
};
//This example shows how to manually implement UserData using TealData
//As you can see the amount of code is small and easy copy/paste able.
Expand All @@ -31,10 +30,10 @@ impl TealData for Example {
}
}

impl TypeName for Example {
impl ToTypename for Example {
//how the type should be called in lua.
fn get_type_parts() -> std::borrow::Cow<'static, [NamePart]> {
new_type!(Example)
fn to_typename() -> tealr::Type {
tealr::Type::new_single("Example", tealr::KindOfType::External)
}
}

Expand Down
4 changes: 2 additions & 2 deletions examples/rlua/named_parameters.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use tealr::{
rlu::{rlua::Result, TealData, TealDataMethods, UserData},
TypeName, TypeWalker,
ToTypename, TypeWalker,
};
//this example shows how to use the create_named_parameters! macro to create methods which has names for their parameters in the documentation
#[derive(Clone, UserData, TypeName)]
#[derive(Clone, UserData, ToTypename)]
struct Example {}

impl TealData for Example {
Expand Down
6 changes: 3 additions & 3 deletions src/export_instance.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::borrow::Cow;

use crate::{type_walker::GlobalInstance, KindOfType, TypeName};
use crate::{type_walker::GlobalInstance, KindOfType, ToTypename, TypeName};

pub(crate) struct InstanceWalker {
doc: String,
Expand All @@ -11,7 +11,7 @@ impl<'lua> crate::mlu::InstanceCollector<'lua> for InstanceWalker {
fn add_instance<P, T, F>(&mut self, global_name: P, _: F) -> Result<&mut Self, mlua::Error>
where
P: Into<Cow<'static, str>>,
T: TypeName,
T: ToTypename,
F: FnOnce(&'lua mlua::Lua) -> Result<T, mlua::Error>,
{
self.add_instance::<T>(global_name.into());
Expand All @@ -27,7 +27,7 @@ impl<'lua> crate::mlu::InstanceCollector<'lua> for InstanceWalker {
impl<'lua> crate::rlu::InstanceCollector<'lua> for InstanceWalker {
fn add_instance<
P: Into<Cow<'static, str>>,
T: TypeName,
T: ToTypename,
F: FnOnce(rlua::Context<'lua>) -> rlua::Result<T>,
>(
&mut self,
Expand Down
Loading

0 comments on commit a8872b3

Please sign in to comment.