mirror of
https://github.com/lune-org/mlua-luau-scheduler.git
synced 2025-04-06 19:40:55 +01:00
137 lines
4.8 KiB
Rust
137 lines
4.8 KiB
Rust
#![allow(unused_imports)]
|
|
#![allow(clippy::module_name_repetitions)]
|
|
|
|
use mlua::prelude::*;
|
|
|
|
use crate::{
|
|
error_callback::ThreadErrorCallback,
|
|
queue::{DeferredThreadQueue, SpawnedThreadQueue},
|
|
result_map::ThreadResultMap,
|
|
runtime::Runtime,
|
|
thread_id::ThreadId,
|
|
util::{is_poll_pending, LuaThreadOrFunction, ThreadResult},
|
|
};
|
|
|
|
const ERR_METADATA_NOT_ATTACHED: &str = "\
|
|
Lua state does not have runtime metadata attached!\
|
|
\nThis is most likely caused by creating functions outside of a runtime.\
|
|
\nRuntime functions must always be created from within an active runtime.\
|
|
";
|
|
|
|
/**
|
|
A collection of lua functions that may be called to interact with a [`Runtime`].
|
|
*/
|
|
pub struct Functions<'lua> {
|
|
/**
|
|
Resumes a function / thread once instantly, and runs until first yield.
|
|
|
|
Spawns onto the runtime queue if not completed.
|
|
*/
|
|
pub spawn: LuaFunction<'lua>,
|
|
/**
|
|
Defers a function / thread onto the runtime queue.
|
|
|
|
Does not resume instantly, only adds to the queue.
|
|
*/
|
|
pub defer: LuaFunction<'lua>,
|
|
/**
|
|
Cancels a function / thread, removing it from the queue.
|
|
*/
|
|
pub cancel: LuaFunction<'lua>,
|
|
}
|
|
|
|
impl<'lua> Functions<'lua> {
|
|
/**
|
|
Creates a new collection of Lua functions that may be called to interact with a [`Runtime`].
|
|
|
|
# Errors
|
|
|
|
Errors when out of memory, or if default Lua globals are missing.
|
|
|
|
# Panics
|
|
|
|
Panics when the given [`Lua`] instance does not have an attached [`Runtime`].
|
|
*/
|
|
pub fn new(lua: &'lua Lua) -> LuaResult<Self> {
|
|
let spawn_queue = lua
|
|
.app_data_ref::<SpawnedThreadQueue>()
|
|
.expect(ERR_METADATA_NOT_ATTACHED)
|
|
.clone();
|
|
let defer_queue = lua
|
|
.app_data_ref::<DeferredThreadQueue>()
|
|
.expect(ERR_METADATA_NOT_ATTACHED)
|
|
.clone();
|
|
let error_callback = lua
|
|
.app_data_ref::<ThreadErrorCallback>()
|
|
.expect(ERR_METADATA_NOT_ATTACHED)
|
|
.clone();
|
|
let result_map = lua
|
|
.app_data_ref::<ThreadResultMap>()
|
|
.expect(ERR_METADATA_NOT_ATTACHED)
|
|
.clone();
|
|
|
|
let spawn_map = result_map.clone();
|
|
let spawn = lua.create_function(
|
|
move |lua, (tof, args): (LuaThreadOrFunction, LuaMultiValue)| {
|
|
let thread = tof.into_thread(lua)?;
|
|
if thread.status() == LuaThreadStatus::Resumable {
|
|
// NOTE: We need to resume the thread once instantly for correct behavior,
|
|
// and only if we get the pending value back we can spawn to async executor
|
|
match thread.resume::<_, LuaMultiValue>(args.clone()) {
|
|
Ok(v) => {
|
|
if v.get(0).map(is_poll_pending).unwrap_or_default() {
|
|
spawn_queue.push_item(lua, &thread, args)?;
|
|
} else {
|
|
// Not pending, store the value
|
|
let id = ThreadId::from(&thread);
|
|
if spawn_map.is_tracked(id) {
|
|
let res = ThreadResult::new(Ok(v), lua);
|
|
spawn_map.insert(id, res);
|
|
}
|
|
}
|
|
}
|
|
Err(e) => {
|
|
error_callback.call(&e);
|
|
// Not pending, store the error
|
|
let id = ThreadId::from(&thread);
|
|
if spawn_map.is_tracked(id) {
|
|
let res = ThreadResult::new(Err(e), lua);
|
|
spawn_map.insert(id, res);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
Ok(thread)
|
|
},
|
|
)?;
|
|
|
|
let defer = lua.create_function(
|
|
move |lua, (tof, args): (LuaThreadOrFunction, LuaMultiValue)| {
|
|
let thread = tof.into_thread(lua)?;
|
|
if thread.status() == LuaThreadStatus::Resumable {
|
|
defer_queue.push_item(lua, &thread, args)?;
|
|
}
|
|
Ok(thread)
|
|
},
|
|
)?;
|
|
|
|
let close = lua
|
|
.globals()
|
|
.get::<_, LuaTable>("coroutine")?
|
|
.get::<_, LuaFunction>("close")?;
|
|
let close_key = lua.create_registry_value(close)?;
|
|
let cancel = lua.create_function(move |lua, thread: LuaThread| {
|
|
let close: LuaFunction = lua.registry_value(&close_key)?;
|
|
match close.call(thread) {
|
|
Err(LuaError::CoroutineInactive) | Ok(()) => Ok(()),
|
|
Err(e) => Err(e),
|
|
}
|
|
})?;
|
|
|
|
Ok(Self {
|
|
spawn,
|
|
defer,
|
|
cancel,
|
|
})
|
|
}
|
|
}
|