diff --git a/Cargo.toml b/Cargo.toml index 49144ac..74d903e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,7 @@ mlua = { version = "0.9", features = ["luau", "luau-jit", "async"] } path = "lib/lib.rs" [examples] +basic-sleep = "examples/basic_sleep.rs" +basic-spawn = "examples/basic_spawn.rs" main = "examples/main.rs" +scheduler-ordering = "examples/scheduler_ordering.rs" diff --git a/examples/basic_sleep.luau b/examples/basic_sleep.luau new file mode 100644 index 0000000..74418d0 --- /dev/null +++ b/examples/basic_sleep.luau @@ -0,0 +1,13 @@ +--!nocheck +--!nolint UnknownGlobal + +print("Sleeping for 3 seconds...") + +sleep(1) +print("1 second passed") + +sleep(1) +print("2 seconds passed") + +sleep(1) +print("3 seconds passed") diff --git a/examples/basic_sleep.rs b/examples/basic_sleep.rs new file mode 100644 index 0000000..bc14ac9 --- /dev/null +++ b/examples/basic_sleep.rs @@ -0,0 +1,30 @@ +use std::time::{Duration, Instant}; + +use smol_mlua::{ + mlua::prelude::{Lua, LuaResult}, + smol::Timer, + Runtime, +}; + +const MAIN_SCRIPT: &str = include_str!("./basic_sleep.luau"); + +pub fn main() -> LuaResult<()> { + // Set up persistent lua environment + let lua = Lua::new(); + lua.globals().set( + "sleep", + lua.create_async_function(|_, duration: f64| async move { + let before = Instant::now(); + let after = Timer::after(Duration::from_secs_f64(duration)).await; + Ok((after - before).as_secs_f64()) + })?, + )?; + + // Load the main script into a runtime and run it until completion + let rt = Runtime::new(&lua)?; + let main = lua.load(MAIN_SCRIPT); + rt.push_main(&lua, main, ()); + rt.run_blocking(&lua); + + Ok(()) +} diff --git a/examples/basic_spawn.luau b/examples/basic_spawn.luau new file mode 100644 index 0000000..9f7a98b --- /dev/null +++ b/examples/basic_spawn.luau @@ -0,0 +1,9 @@ +--!nocheck +--!nolint UnknownGlobal + +local file = readFile("Cargo.toml") +if file ~= nil then + print("Cargo.toml found!") + print("Contents:") + print(file) +end diff --git a/examples/basic_spawn.rs b/examples/basic_spawn.rs new file mode 100644 index 0000000..ca0ad0d --- /dev/null +++ b/examples/basic_spawn.rs @@ -0,0 +1,36 @@ +use mlua::ExternalResult; +use smol::io; +use smol_mlua::{ + mlua::prelude::{Lua, LuaResult}, + smol::fs::read_to_string, + LuaExecutorExt, Runtime, +}; + +const MAIN_SCRIPT: &str = include_str!("./basic_spawn.luau"); + +pub fn main() -> LuaResult<()> { + // Set up persistent lua environment + let lua = Lua::new(); + lua.globals().set( + "readFile", + lua.create_async_function(|lua, path: String| async move { + // Spawn background task that does not take up resources on the lua thread + let task = lua.spawn(async move { + match read_to_string(path).await { + Ok(s) => Ok(Some(s)), + Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(None), + Err(e) => Err(e), + } + }); + task.await.into_lua_err() + })?, + )?; + + // Load the main script into a runtime and run it until completion + let rt = Runtime::new(&lua)?; + let main = lua.load(MAIN_SCRIPT); + rt.push_main(&lua, main, ()); + rt.run_blocking(&lua); + + Ok(()) +} diff --git a/examples/scheduler_ordering.luau b/examples/scheduler_ordering.luau new file mode 100644 index 0000000..437828a --- /dev/null +++ b/examples/scheduler_ordering.luau @@ -0,0 +1,26 @@ +--!nocheck +--!nolint UnknownGlobal + +print(1) + +-- Defer will run at the end of the resumption cycle, but without yielding +__runtime__defer(function() + print(5) +end) + +-- Spawn will instantly run up until the first yield, and must then be resumed manually ... +__runtime__spawn(function() + print(2) + coroutine.yield() + print("unreachable") +end) + +-- ... unless calling functions created using `lua.create_async_function(...)`, +-- which will resume their calling thread with their result automatically +__runtime__spawn(function() + print(3) + wait(1) + print(6) +end) + +print(4) diff --git a/examples/scheduler_ordering.rs b/examples/scheduler_ordering.rs new file mode 100644 index 0000000..78f2786 --- /dev/null +++ b/examples/scheduler_ordering.rs @@ -0,0 +1,31 @@ +use std::time::{Duration, Instant}; + +use smol_mlua::{ + mlua::prelude::{Lua, LuaResult}, + smol::Timer, + Runtime, +}; + +const MAIN_SCRIPT: &str = include_str!("./scheduler_ordering.luau"); + +pub fn main() -> LuaResult<()> { + // Set up persistent lua environment + let lua = Lua::new(); + lua.globals().set( + "wait", + lua.create_async_function(|_, duration: Option| async move { + let duration = duration.unwrap_or_default().max(1.0 / 250.0); + let before = Instant::now(); + let after = Timer::after(Duration::from_secs_f64(duration)).await; + Ok((after - before).as_secs_f64()) + })?, + )?; + + // Load the main script into a runtime and run it until completion + let rt = Runtime::new(&lua)?; + let main = lua.load(MAIN_SCRIPT); + rt.push_main(&lua, main, ()); + rt.run_blocking(&lua); + + Ok(()) +}