Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
features:
# No features at all
- ""
# lua54+vendored base, then all combinations of: send, async, derive
# lua54+vendored base, then all combinations of: send, async, macros
- lua54,vendored
- lua54,vendored,send
- lua54,vendored,async
Expand All @@ -31,12 +31,12 @@ jobs:
- lua54,vendored,send,macros
- lua54,vendored,async,macros
- lua54,vendored,send,async,macros
# Full feature set including serde and macros
- lua54,vendored,send,async,serde,macros
# Full feature set including macros
- lua54,vendored,send,async,macros
# Luau feature combinations
- luau,vendored
- luau,vendored,macros,userdata-wrappers
- luau,vendored,send,async,serde,macros
- luau,vendored,send,async,macros
steps:
- uses: actions/checkout@v6

Expand Down
40 changes: 38 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 18 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,23 @@ features = ["mlua", "lua54", "send", "async", "macros", "vendored"]

[features]
mlua = ["dep:mlua"]
lua54 = ["mlua", "mlua/lua54"]
lua53 = ["mlua", "mlua/lua53"]
lua52 = ["mlua", "mlua/lua52"]
lua51 = ["mlua", "mlua/lua51"]
luajit = ["mlua", "mlua/luajit"]
luau = ["mlua", "mlua/luau"]
lua55 = ["mlua/lua55", "mlua"]
lua54 = ["mlua/lua54", "mlua"]
lua53 = ["mlua/lua53", "mlua"]
lua52 = ["mlua/lua52", "mlua"]
lua51 = ["mlua/lua51", "mlua"]
luajit = ["mlua/luajit", "mlua"]
luajit52 = ["mlua/luajit52", "mlua"]
luau = ["mlua/luau", "mlua"]
luau-jit = ["mlua/luau", "mlua"]
luau-vector4 = ["mlua/luau-vector4", "mlua"]
vendored = ["mlua/vendored"]
serde = ["mlua/serde"]
macros = ["mlua/macros", "dep:mlua-extras-derive"]
module = ["mlua/module"]
send = ["mlua/send"]
async = ["mlua/async"]
send = ["mlua/send"]
error-send = ["mlua/error-send"]
macros = ["mlua/macros", "dep:mlua-extras-derive"]
anyhow = ["mlua/anyhow"]
userdata-wrappers = ["mlua/userdata-wrappers"]

[dev-dependencies]
Expand All @@ -37,8 +42,11 @@ tokio = { version = "1", features = ["macros", "rt"] }
[dependencies]
mlua-extras-derive = { path = "./mlua_extras_derive", version = "11.6.0", optional = true }

mlua = { version = "0.11.6", optional = true, default-features = false }
mlua = { version = "0.11.6", optional = true, default-features = false, features = ["serde"] }

serde = { version = "1.0.228" }
strum = { version = "0.27.2", features = ["derive"], default-features = false }
ryu = "1.0.23"

[[example]]
name = "macros"
Expand Down
148 changes: 148 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,154 @@ function greet(name) end
function printColor(param0) end
```

## Macros

There are helper macros that make writing lua integrations simplier and less manual. There
are variants that support recording type information, and variants that just focus on making
the creation of custom userdata types simple.

```rust
use std::path::PathBuf;
use mlua_extras::{
TypedUserData,
typed::generator::{
Definition, DefinitionFileGenerator, Definitions, LuauDefinitionFileGenerator,
},
typed_user_data_impl,
};

/// Simple Counter
#[derive(Clone, TypedUserData)]
struct Counter { value: i64 }

#[typed_user_data_impl]
impl Counter {
/// The default count
const COUNT: usize = 10;

/// Max count value
#[field]
fn max() -> i64 {
i64::MAX
}

/// Min count value
#[field(rename = "MIN")]
fn min() -> i64 {
0
}

/// Direction of the counter
#[getter("direction")]
fn get_direction(&self) -> String {
"up".into()
}

#[setter("direction")]
fn set_direction(&mut self, dir: String) {
println!("Direction: {dir}");
}

/// Get the current counter value
#[method]
fn get(&self) -> i64 { self.value }

/// Increment the counter
#[method]
fn increment(&mut self) { self.value += 1 }

/// Create a new table
#[method]
fn create_table(&self, lua: &mlua::Lua) -> mlua::Result<mlua::Table> {
lua.create_table()
}

/// String representation of the counter
#[metamethod(ToString)]
fn to_string(&self) -> String { format!("Counter({})", self.value) }

// Requires the `async` feature
// Must be accessed from lua code with an entry of `mlua::Chunk::eval_async` or `mlua::Chunk::exec_async`

/// Fetch the global counter online
#[method]
async fn fetch(&self, lua: mlua::Lua, url: String) -> mlua::Result<String> {
_ = lua;
Ok(format!("fetched: {url}"))
}
}

fn main() -> mlua::Result<()> {
let definitions: Definitions = Definitions::start()
.define("macros", Definition::start().register::<Counter>("Counter"))
.finish();

let types_path = PathBuf::from("examples/types");
if !types_path.exists() {
std::fs::create_dir_all(&types_path).unwrap();
}

let dfg = DefinitionFileGenerator::new(definitions.clone());
for (name, writer) in dfg.iter() {
println!("==== Generated \x1b[1;33mexample/types/{name}\x1b[0m ====");
writer.write_file(types_path.join(name)).unwrap();
}

Ok(())
}
```

Results in the lua type definition

```lua
--- @meta

--- Simple Counter
--- @class Counter
--- Direction of the counter
--- @field direction string
--- @field value integer
local _CLASS_Counter_ = {
--- The default count
COUNT = 10,
--- Min count value
MIN = 0,
--- Max count value
max = 9223372036854775807,
--- Create a new table
--- @param self Counter
--- @return table
create_table = function(self) end,
--- Fetch the global counter online
--- @param self Counter
--- @param url string
--- @return string
fetch = function(self, url) end,
--- Get the current counter value
--- @param self Counter
--- @return integer
get = function(self) end,
--- Increment the counter
--- @param self Counter
increment = function(self) end,
__metatable = {
--- @param param1 userdata
--- @param param2 any
--- @return any
__index = function(param1, param2) end,
--- @param param1 userdata
--- @param param2 any
--- @param param3 any
--- @return any | nil
__newindex = function(param1, param2, param3) end,
--- String representation of the counter
--- @param self Counter
--- @return string
__tostring = function(self) end,
}
}
```

## Testing

To run all the tests in one shot, use `cargo test --features luau,vendored,send,async,serialize,derive`
Expand Down
13 changes: 13 additions & 0 deletions examples/init.lua
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
--- @return Custom
function getCustom() return {} end

--- @type Custom
local c = getCustom()

if c._variant == "B" then
---@cast c CustomB
print(c.COUNT)
end

print(c.COUNT)

print("Hello world!")
1 change: 1 addition & 0 deletions examples/init.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
local _c: Custom = { {} :: any }
Loading