mirror of
https://github.com/lune-org/mlua-luau-scheduler.git
synced 2025-04-07 03:50:56 +01:00
Expand handle struct and runtime ext trait to be able to use from inside lua
This commit is contained in:
parent
da2846670b
commit
b03a0101e2
9 changed files with 254 additions and 55 deletions
50
Cargo.lock
generated
50
Cargo.lock
generated
|
@ -144,12 +144,31 @@ dependencies = [
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "convert_case"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.19"
|
version = "0.8.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_more"
|
||||||
|
version = "0.99.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
|
||||||
|
dependencies = [
|
||||||
|
"convert_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustc_version",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "erased-serde"
|
name = "erased-serde"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
@ -315,6 +334,7 @@ dependencies = [
|
||||||
"async-fs",
|
"async-fs",
|
||||||
"async-io",
|
"async-io",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
|
"derive_more",
|
||||||
"event-listener",
|
"event-listener",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
"mlua",
|
"mlua",
|
||||||
|
@ -447,6 +467,15 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||||
|
dependencies = [
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.30"
|
version = "0.38.30"
|
||||||
|
@ -460,6 +489,12 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "1.0.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.195"
|
version = "1.0.195"
|
||||||
|
@ -487,7 +522,7 @@ checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -514,6 +549,17 @@ version = "1.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.109"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.48"
|
version = "2.0.48"
|
||||||
|
@ -554,7 +600,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -12,6 +12,7 @@ categories = ["async"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-executor = "1.8"
|
async-executor = "1.8"
|
||||||
concurrent-queue = "2.4"
|
concurrent-queue = "2.4"
|
||||||
|
derive_more = "0.99"
|
||||||
event-listener = "4.0"
|
event-listener = "4.0"
|
||||||
futures-lite = "2.2"
|
futures-lite = "2.2"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
|
|
@ -52,7 +52,7 @@ lua.globals().set(
|
||||||
lua.create_async_function(|lua, path: String| async move {
|
lua.create_async_function(|lua, path: String| async move {
|
||||||
// Spawn background task that does not take up resources on the lua thread
|
// Spawn background task that does not take up resources on the lua thread
|
||||||
// Normally, futures in mlua can not be shared across threads, but this can
|
// Normally, futures in mlua can not be shared across threads, but this can
|
||||||
let task = lua.spawn(async move {
|
let task = lua.spawn_future(async move {
|
||||||
match read_to_string(path).await {
|
match read_to_string(path).await {
|
||||||
Ok(s) => Ok(Some(s)),
|
Ok(s) => Ok(Some(s)),
|
||||||
Err(e) if e.kind() == ErrorKind::NotFound => Ok(None),
|
Err(e) if e.kind() == ErrorKind::NotFound => Ok(None),
|
||||||
|
|
|
@ -6,7 +6,7 @@ use async_fs::read_to_string;
|
||||||
use async_io::block_on;
|
use async_io::block_on;
|
||||||
|
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
use mlua_luau_runtime::{LuaSpawnExt, Runtime};
|
use mlua_luau_runtime::{LuaRuntimeExt, Runtime};
|
||||||
|
|
||||||
const MAIN_SCRIPT: &str = include_str!("./lua/basic_spawn.luau");
|
const MAIN_SCRIPT: &str = include_str!("./lua/basic_spawn.luau");
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ pub fn main() -> LuaResult<()> {
|
||||||
"readFile",
|
"readFile",
|
||||||
lua.create_async_function(|lua, path: String| async move {
|
lua.create_async_function(|lua, path: String| async move {
|
||||||
// Spawn background task that does not take up resources on the Lua thread
|
// Spawn background task that does not take up resources on the Lua thread
|
||||||
let task = lua.spawn(async move {
|
let task = lua.spawn_future(async move {
|
||||||
match read_to_string(path).await {
|
match read_to_string(path).await {
|
||||||
Ok(s) => Ok(Some(s)),
|
Ok(s) => Ok(Some(s)),
|
||||||
Err(e) if e.kind() == ErrorKind::NotFound => Ok(None),
|
Err(e) if e.kind() == ErrorKind::NotFound => Ok(None),
|
||||||
|
|
|
@ -2,27 +2,35 @@
|
||||||
#![allow(clippy::missing_panics_doc)]
|
#![allow(clippy::missing_panics_doc)]
|
||||||
#![allow(clippy::module_name_repetitions)]
|
#![allow(clippy::module_name_repetitions)]
|
||||||
|
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{
|
||||||
|
cell::{Cell, RefCell},
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use event_listener::Event;
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
runtime::Runtime,
|
runtime::Runtime,
|
||||||
status::Status,
|
status::Status,
|
||||||
|
traits::IntoLuaThread,
|
||||||
util::{run_until_yield, ThreadWithArgs},
|
util::{run_until_yield, ThreadWithArgs},
|
||||||
IntoLuaThread,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A handle to a thread that has been spawned onto a [`Runtime`].
|
A handle to a thread that has been spawned onto a [`Runtime`].
|
||||||
|
|
||||||
This handle contains a single public method, [`Handle::result`], which may
|
This handle contains a public method, [`Handle::result`], which may
|
||||||
be used to extract the result of the thread, once it has finished running.
|
be used to extract the result of the thread, once it finishes running.
|
||||||
|
|
||||||
|
A result may be waited for using the [`Handle::listen`] method.
|
||||||
*/
|
*/
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Handle {
|
pub struct Handle {
|
||||||
thread: Rc<RefCell<Option<ThreadWithArgs>>>,
|
thread: Rc<RefCell<Option<ThreadWithArgs>>>,
|
||||||
result: Rc<RefCell<Option<(bool, LuaRegistryKey)>>>,
|
result: Rc<RefCell<Option<(bool, LuaRegistryKey)>>>,
|
||||||
|
status: Rc<Cell<bool>>,
|
||||||
|
event: Rc<Event>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handle {
|
impl Handle {
|
||||||
|
@ -39,6 +47,8 @@ impl Handle {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
thread: Rc::new(RefCell::new(Some(packed))),
|
thread: Rc::new(RefCell::new(Some(packed))),
|
||||||
result: Rc::new(RefCell::new(None)),
|
result: Rc::new(RefCell::new(None)),
|
||||||
|
status: Rc::new(Cell::new(false)),
|
||||||
|
event: Rc::new(Event::new()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +69,12 @@ impl Handle {
|
||||||
.into_inner(lua)
|
.into_inner(lua)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set<'lua>(&self, lua: &'lua Lua, result: &LuaResult<LuaMultiValue<'lua>>) -> LuaResult<()> {
|
fn set<'lua>(
|
||||||
|
&self,
|
||||||
|
lua: &'lua Lua,
|
||||||
|
result: &LuaResult<LuaMultiValue<'lua>>,
|
||||||
|
is_final: bool,
|
||||||
|
) -> LuaResult<()> {
|
||||||
self.result.borrow_mut().replace((
|
self.result.borrow_mut().replace((
|
||||||
result.is_ok(),
|
result.is_ok(),
|
||||||
match &result {
|
match &result {
|
||||||
|
@ -67,6 +82,10 @@ impl Handle {
|
||||||
Err(e) => lua.create_registry_value(e.clone())?,
|
Err(e) => lua.create_registry_value(e.clone())?,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
self.status.replace(is_final);
|
||||||
|
if is_final {
|
||||||
|
self.event.notify(usize::MAX);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +109,17 @@ impl Handle {
|
||||||
Err(lua.registry_value(key).unwrap())
|
Err(lua.registry_value(key).unwrap())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Waits for this handle to have its final result available.
|
||||||
|
|
||||||
|
Does not wait if the final result is already available.
|
||||||
|
*/
|
||||||
|
pub async fn listen(&self) {
|
||||||
|
if !self.status.get() {
|
||||||
|
self.event.listen().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LuaUserData for Handle {
|
impl LuaUserData for Handle {
|
||||||
|
@ -103,8 +133,9 @@ impl LuaUserData for Handle {
|
||||||
it may be caught using the runtime and any error callback(s)
|
it may be caught using the runtime and any error callback(s)
|
||||||
*/
|
*/
|
||||||
let (thread, args) = this.take(lua);
|
let (thread, args) = this.take(lua);
|
||||||
let result = run_until_yield(thread, args).await;
|
let result = run_until_yield(thread.clone(), args).await;
|
||||||
this.set(lua, &result)?;
|
let is_final = thread.status() != LuaThreadStatus::Resumable;
|
||||||
|
this.set(lua, &result, is_final)?;
|
||||||
result
|
result
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,4 +9,4 @@ mod util;
|
||||||
pub use handle::Handle;
|
pub use handle::Handle;
|
||||||
pub use runtime::Runtime;
|
pub use runtime::Runtime;
|
||||||
pub use status::Status;
|
pub use status::Status;
|
||||||
pub use traits::{IntoLuaThread, LuaSpawnExt};
|
pub use traits::{IntoLuaThread, LuaRuntimeExt};
|
||||||
|
|
41
lib/queue.rs
41
lib/queue.rs
|
@ -1,10 +1,11 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use concurrent_queue::ConcurrentQueue;
|
use concurrent_queue::ConcurrentQueue;
|
||||||
|
use derive_more::{Deref, DerefMut};
|
||||||
use event_listener::Event;
|
use event_listener::Event;
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
|
|
||||||
use crate::{util::ThreadWithArgs, IntoLuaThread};
|
use crate::{handle::Handle, traits::IntoLuaThread, util::ThreadWithArgs};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Queue for storing [`LuaThread`]s with associated arguments.
|
Queue for storing [`LuaThread`]s with associated arguments.
|
||||||
|
@ -43,6 +44,20 @@ impl ThreadQueue {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn push_item_with_handle<'lua>(
|
||||||
|
&self,
|
||||||
|
lua: &'lua Lua,
|
||||||
|
thread: impl IntoLuaThread<'lua>,
|
||||||
|
args: impl IntoLuaMulti<'lua>,
|
||||||
|
) -> LuaResult<Handle> {
|
||||||
|
let handle = Handle::new(lua, thread, args)?;
|
||||||
|
let handle_thread = handle.create_thread(lua)?;
|
||||||
|
|
||||||
|
self.push_item(lua, handle_thread, ())?;
|
||||||
|
|
||||||
|
Ok(handle)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn drain_items<'outer, 'lua>(
|
pub fn drain_items<'outer, 'lua>(
|
||||||
&'outer self,
|
&'outer self,
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
|
@ -59,3 +74,27 @@ impl ThreadQueue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Alias for [`ThreadQueue`], providing a newtype to store in Lua app data.
|
||||||
|
*/
|
||||||
|
#[derive(Debug, Clone, Deref, DerefMut)]
|
||||||
|
pub(crate) struct SpawnedThreadQueue(ThreadQueue);
|
||||||
|
|
||||||
|
impl SpawnedThreadQueue {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(ThreadQueue::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Alias for [`ThreadQueue`], providing a newtype to store in Lua app data.
|
||||||
|
*/
|
||||||
|
#[derive(Debug, Clone, Deref, DerefMut)]
|
||||||
|
pub(crate) struct DeferredThreadQueue(ThreadQueue);
|
||||||
|
|
||||||
|
impl DeferredThreadQueue {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(ThreadQueue::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -12,20 +12,33 @@ use mlua::prelude::*;
|
||||||
use async_executor::{Executor, LocalExecutor};
|
use async_executor::{Executor, LocalExecutor};
|
||||||
use tracing::Instrument;
|
use tracing::Instrument;
|
||||||
|
|
||||||
use crate::{status::Status, util::run_until_yield, Handle};
|
use crate::{
|
||||||
|
error_callback::ThreadErrorCallback,
|
||||||
use super::{
|
handle::Handle,
|
||||||
error_callback::ThreadErrorCallback, queue::ThreadQueue, traits::IntoLuaThread,
|
queue::{DeferredThreadQueue, SpawnedThreadQueue},
|
||||||
util::LuaThreadOrFunction,
|
status::Status,
|
||||||
|
traits::IntoLuaThread,
|
||||||
|
util::{run_until_yield, LuaThreadOrFunction},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ERR_METADATA_ALREADY_ATTACHED: &str = "\
|
||||||
|
Lua state already has runtime metadata attached!\
|
||||||
|
\nThis may be caused by running multiple runtimes on the same Lua state, or a call to Runtime::run being cancelled.\
|
||||||
|
\nOnly one runtime can be used per Lua state at once, and runtimes must always run until completion.\
|
||||||
|
";
|
||||||
|
|
||||||
|
const ERR_METADATA_REMOVED: &str = "\
|
||||||
|
Lua state runtime metadata was unexpectedly removed!\
|
||||||
|
\nThis should never happen, and is likely a bug in the runtime.\
|
||||||
|
";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A runtime for running Lua threads and async tasks.
|
A runtime for running Lua threads and async tasks.
|
||||||
*/
|
*/
|
||||||
pub struct Runtime<'lua> {
|
pub struct Runtime<'lua> {
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
queue_spawn: ThreadQueue,
|
queue_spawn: SpawnedThreadQueue,
|
||||||
queue_defer: ThreadQueue,
|
queue_defer: DeferredThreadQueue,
|
||||||
error_callback: ThreadErrorCallback,
|
error_callback: ThreadErrorCallback,
|
||||||
status: Rc<Cell<Status>>,
|
status: Rc<Cell<Status>>,
|
||||||
}
|
}
|
||||||
|
@ -38,8 +51,8 @@ impl<'lua> Runtime<'lua> {
|
||||||
*/
|
*/
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(lua: &'lua Lua) -> Runtime<'lua> {
|
pub fn new(lua: &'lua Lua) -> Runtime<'lua> {
|
||||||
let queue_spawn = ThreadQueue::new();
|
let queue_spawn = SpawnedThreadQueue::new();
|
||||||
let queue_defer = ThreadQueue::new();
|
let queue_defer = DeferredThreadQueue::new();
|
||||||
let error_callback = ThreadErrorCallback::default();
|
let error_callback = ThreadErrorCallback::default();
|
||||||
let status = Rc::new(Cell::new(Status::NotStarted));
|
let status = Rc::new(Cell::new(Status::NotStarted));
|
||||||
Runtime {
|
Runtime {
|
||||||
|
@ -100,13 +113,8 @@ impl<'lua> Runtime<'lua> {
|
||||||
args: impl IntoLuaMulti<'lua>,
|
args: impl IntoLuaMulti<'lua>,
|
||||||
) -> LuaResult<Handle> {
|
) -> LuaResult<Handle> {
|
||||||
tracing::debug!(deferred = false, "new runtime thread");
|
tracing::debug!(deferred = false, "new runtime thread");
|
||||||
|
self.queue_spawn
|
||||||
let handle = Handle::new(self.lua, thread, args)?;
|
.push_item_with_handle(self.lua, thread, args)
|
||||||
let handle_thread = handle.create_thread(self.lua)?;
|
|
||||||
|
|
||||||
self.queue_spawn.push_item(self.lua, handle_thread, ())?;
|
|
||||||
|
|
||||||
Ok(handle)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -132,13 +140,8 @@ impl<'lua> Runtime<'lua> {
|
||||||
args: impl IntoLuaMulti<'lua>,
|
args: impl IntoLuaMulti<'lua>,
|
||||||
) -> LuaResult<Handle> {
|
) -> LuaResult<Handle> {
|
||||||
tracing::debug!(deferred = true, "new runtime thread");
|
tracing::debug!(deferred = true, "new runtime thread");
|
||||||
|
self.queue_defer
|
||||||
let handle = Handle::new(self.lua, thread, args)?;
|
.push_item_with_handle(self.lua, thread, args)
|
||||||
let handle_thread = handle.create_thread(self.lua)?;
|
|
||||||
|
|
||||||
self.queue_defer.push_item(self.lua, handle_thread, ())?;
|
|
||||||
|
|
||||||
Ok(handle)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -228,20 +231,26 @@ impl<'lua> Runtime<'lua> {
|
||||||
let main_exec = Arc::new(Executor::new());
|
let main_exec = Arc::new(Executor::new());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Store the main executor in Lua, so that it may be used with LuaSpawnExt.
|
Store the main executor and queues in Lua, so that they may be used with LuaRuntimeExt.
|
||||||
|
|
||||||
Also ensure we do not already have an executor - this is a definite user error
|
Also ensure we do not already have an executor or queues - these are definite user errors
|
||||||
and may happen if the user tries to run multiple runtimes on the same Lua state.
|
and may happen if the user tries to run multiple runtimes on the same Lua state at once.
|
||||||
*/
|
*/
|
||||||
assert!(
|
assert!(
|
||||||
self.lua.app_data_ref::<Weak<Executor>>().is_none(),
|
self.lua.app_data_ref::<Weak<Executor>>().is_none(),
|
||||||
"\
|
"{ERR_METADATA_ALREADY_ATTACHED}"
|
||||||
Lua state already has an executor attached!\
|
);
|
||||||
\nThis may be caused by running multiple runtimes on the same Lua state, or a call to Runtime::run being cancelled.\
|
assert!(
|
||||||
\nOnly one runtime can be used per Lua state at once, and runtimes must always run until completion.\
|
self.lua.app_data_ref::<SpawnedThreadQueue>().is_none(),
|
||||||
"
|
"{ERR_METADATA_ALREADY_ATTACHED}"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
self.lua.app_data_ref::<DeferredThreadQueue>().is_none(),
|
||||||
|
"{ERR_METADATA_ALREADY_ATTACHED}"
|
||||||
);
|
);
|
||||||
self.lua.set_app_data(Arc::downgrade(&main_exec));
|
self.lua.set_app_data(Arc::downgrade(&main_exec));
|
||||||
|
self.lua.set_app_data(self.queue_spawn.clone());
|
||||||
|
self.lua.set_app_data(self.queue_defer.clone());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Manually tick the Lua executor, while running under the main executor.
|
Manually tick the Lua executor, while running under the main executor.
|
||||||
|
@ -330,6 +339,14 @@ impl<'lua> Runtime<'lua> {
|
||||||
self.status.set(Status::Completed);
|
self.status.set(Status::Completed);
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
self.lua.remove_app_data::<Weak<Executor>>();
|
self.lua
|
||||||
|
.remove_app_data::<Weak<Executor>>()
|
||||||
|
.expect(ERR_METADATA_REMOVED);
|
||||||
|
self.lua
|
||||||
|
.remove_app_data::<SpawnedThreadQueue>()
|
||||||
|
.expect(ERR_METADATA_REMOVED);
|
||||||
|
self.lua
|
||||||
|
.remove_app_data::<DeferredThreadQueue>()
|
||||||
|
.expect(ERR_METADATA_REMOVED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
|
#![allow(clippy::missing_errors_doc)]
|
||||||
|
|
||||||
use std::{future::Future, sync::Weak};
|
use std::{future::Future, sync::Weak};
|
||||||
|
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
|
|
||||||
use async_executor::{Executor, Task};
|
use async_executor::{Executor, Task};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
handle::Handle,
|
||||||
|
queue::{DeferredThreadQueue, SpawnedThreadQueue},
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Trait for any struct that can be turned into an [`LuaThread`]
|
Trait for any struct that can be turned into an [`LuaThread`]
|
||||||
and passed to the runtime, implemented for the following types:
|
and passed to the runtime, implemented for the following types:
|
||||||
|
@ -51,20 +58,50 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Trait for spawning `Send` futures on the current executor.
|
Trait for scheduling Lua threads and spawning `Send` futures on the current executor.
|
||||||
|
|
||||||
For spawning `!Send` futures on the same local executor as a [`Lua`]
|
For spawning `!Send` futures on the same local executor as a [`Lua`]
|
||||||
VM instance, [`Lua::create_async_function`] should be used instead.
|
VM instance, [`Lua::create_async_function`] should be used instead.
|
||||||
*/
|
*/
|
||||||
pub trait LuaSpawnExt<'lua> {
|
pub trait LuaRuntimeExt<'lua> {
|
||||||
|
/**
|
||||||
|
Spawns a lua thread onto the current runtime.
|
||||||
|
|
||||||
|
See [`Runtime::spawn_thread`] for more information.
|
||||||
|
|
||||||
|
# Panics
|
||||||
|
|
||||||
|
Panics if called outside of a running [`Runtime`].
|
||||||
|
*/
|
||||||
|
fn spawn_thread(
|
||||||
|
&'lua self,
|
||||||
|
thread: impl IntoLuaThread<'lua>,
|
||||||
|
args: impl IntoLuaMulti<'lua>,
|
||||||
|
) -> LuaResult<Handle>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Defers a lua thread onto the current runtime.
|
||||||
|
|
||||||
|
See [`Runtime::defer_thread`] for more information.
|
||||||
|
|
||||||
|
# Panics
|
||||||
|
|
||||||
|
Panics if called outside of a running [`Runtime`].
|
||||||
|
*/
|
||||||
|
fn defer_thread(
|
||||||
|
&'lua self,
|
||||||
|
thread: impl IntoLuaThread<'lua>,
|
||||||
|
args: impl IntoLuaMulti<'lua>,
|
||||||
|
) -> LuaResult<Handle>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Spawns the given future on the current executor and returns its [`Task`].
|
Spawns the given future on the current executor and returns its [`Task`].
|
||||||
|
|
||||||
### Panics
|
# Panics
|
||||||
|
|
||||||
Panics if called outside of a [`Runtime`].
|
Panics if called outside of a running [`Runtime`].
|
||||||
|
|
||||||
### Example usage
|
# Example usage
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use async_io::block_on;
|
use async_io::block_on;
|
||||||
|
@ -78,7 +115,7 @@ pub trait LuaSpawnExt<'lua> {
|
||||||
lua.globals().set(
|
lua.globals().set(
|
||||||
"spawnBackgroundTask",
|
"spawnBackgroundTask",
|
||||||
lua.create_async_function(|lua, ()| async move {
|
lua.create_async_function(|lua, ()| async move {
|
||||||
lua.spawn(async move {
|
lua.spawn_future(async move {
|
||||||
println!("Hello from background task!");
|
println!("Hello from background task!");
|
||||||
}).await;
|
}).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -95,11 +132,39 @@ pub trait LuaSpawnExt<'lua> {
|
||||||
|
|
||||||
[`Runtime`]: crate::Runtime
|
[`Runtime`]: crate::Runtime
|
||||||
*/
|
*/
|
||||||
fn spawn<T: Send + 'static>(&self, fut: impl Future<Output = T> + Send + 'static) -> Task<T>;
|
fn spawn_future<T: Send + 'static>(
|
||||||
|
&self,
|
||||||
|
fut: impl Future<Output = T> + Send + 'static,
|
||||||
|
) -> Task<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> LuaSpawnExt<'lua> for Lua {
|
impl<'lua> LuaRuntimeExt<'lua> for Lua {
|
||||||
fn spawn<T: Send + 'static>(&self, fut: impl Future<Output = T> + Send + 'static) -> Task<T> {
|
fn spawn_thread(
|
||||||
|
&'lua self,
|
||||||
|
thread: impl IntoLuaThread<'lua>,
|
||||||
|
args: impl IntoLuaMulti<'lua>,
|
||||||
|
) -> LuaResult<Handle> {
|
||||||
|
let queue = self
|
||||||
|
.app_data_ref::<SpawnedThreadQueue>()
|
||||||
|
.expect("lua threads can only be spawned within a runtime");
|
||||||
|
queue.push_item_with_handle(self, thread, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn defer_thread(
|
||||||
|
&'lua self,
|
||||||
|
thread: impl IntoLuaThread<'lua>,
|
||||||
|
args: impl IntoLuaMulti<'lua>,
|
||||||
|
) -> LuaResult<Handle> {
|
||||||
|
let queue = self
|
||||||
|
.app_data_ref::<DeferredThreadQueue>()
|
||||||
|
.expect("lua threads can only be deferred within a runtime");
|
||||||
|
queue.push_item_with_handle(self, thread, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn_future<T: Send + 'static>(
|
||||||
|
&self,
|
||||||
|
fut: impl Future<Output = T> + Send + 'static,
|
||||||
|
) -> Task<T> {
|
||||||
let exec = self
|
let exec = self
|
||||||
.app_data_ref::<Weak<Executor>>()
|
.app_data_ref::<Weak<Executor>>()
|
||||||
.expect("futures can only be spawned within a runtime")
|
.expect("futures can only be spawned within a runtime")
|
||||||
|
|
Loading…
Add table
Reference in a new issue