mirror of
https://github.com/lune-org/lune.git
synced 2024-12-12 13:00:37 +00:00
Add lifetimes because they are fun
This commit is contained in:
parent
6416ef5fb7
commit
ab386e000d
5 changed files with 95 additions and 51 deletions
|
@ -3,7 +3,7 @@ use mlua::prelude::*;
|
|||
|
||||
use super::{traits::IntoLuaOwnedThread, SchedulerImpl};
|
||||
|
||||
impl<'lua, 'fut> SchedulerImpl
|
||||
impl<'lua, 'fut> SchedulerImpl<'fut>
|
||||
where
|
||||
'lua: 'fut,
|
||||
{
|
||||
|
@ -12,7 +12,7 @@ where
|
|||
*/
|
||||
pub fn schedule_future<F>(&self, fut: F)
|
||||
where
|
||||
F: 'static + Future<Output = ()>,
|
||||
F: 'fut + Future<Output = ()>,
|
||||
{
|
||||
let futs = self
|
||||
.futures
|
||||
|
@ -24,11 +24,11 @@ where
|
|||
/**
|
||||
Schedules the given `thread` to run when the given `fut` completes.
|
||||
*/
|
||||
pub fn schedule_future_thread<T, F, R>(&'lua self, thread: T, fut: F) -> LuaResult<()>
|
||||
pub fn schedule_future_thread<T, R, F>(&'fut self, thread: T, fut: F) -> LuaResult<()>
|
||||
where
|
||||
T: 'static + IntoLuaOwnedThread,
|
||||
F: 'static + Future<Output = LuaResult<R>>,
|
||||
T: IntoLuaOwnedThread,
|
||||
R: IntoLuaMulti<'fut>,
|
||||
F: 'fut + Future<Output = LuaResult<R>>,
|
||||
{
|
||||
let thread = thread.into_owned_lua_thread(&self.lua)?;
|
||||
|
||||
|
|
|
@ -4,15 +4,18 @@ use futures_util::StreamExt;
|
|||
use mlua::prelude::*;
|
||||
use tokio::task::LocalSet;
|
||||
|
||||
use super::SchedulerImpl;
|
||||
use super::{traits::IntoLuaOwnedThread, SchedulerImpl};
|
||||
|
||||
impl<'lua> SchedulerImpl {
|
||||
impl<'lua, 'fut> SchedulerImpl<'fut>
|
||||
where
|
||||
'lua: 'fut,
|
||||
{
|
||||
/**
|
||||
Runs all lua threads to completion.
|
||||
|
||||
Returns `true` if any thread was resumed, `false` otherwise.
|
||||
*/
|
||||
fn run_lua_threads(&self) -> bool {
|
||||
fn run_lua_threads(&'lua self) -> bool {
|
||||
if self.state.has_exit_code() {
|
||||
return false;
|
||||
}
|
||||
|
@ -57,7 +60,7 @@ impl<'lua> SchedulerImpl {
|
|||
|
||||
Returns `true` if any future was resumed, `false` otherwise.
|
||||
*/
|
||||
async fn run_futures(&self) -> bool {
|
||||
async fn run_futures(&'lua self) -> bool {
|
||||
let mut resumed_any = false;
|
||||
|
||||
let mut futs = self
|
||||
|
@ -81,7 +84,7 @@ impl<'lua> SchedulerImpl {
|
|||
|
||||
Will emit lua output and errors to stdout and stderr.
|
||||
*/
|
||||
pub async fn run_to_completion(&self) -> ExitCode {
|
||||
pub async fn run_to_completion(&'lua self) -> ExitCode {
|
||||
let fut = async move {
|
||||
loop {
|
||||
// 1. Run lua threads until exit or there are none left,
|
||||
|
@ -116,4 +119,22 @@ impl<'lua> SchedulerImpl {
|
|||
ExitCode::SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Schedules a new main thread and runs the scheduler until completion.
|
||||
|
||||
See [`Self::run_to_completion`] for more info.
|
||||
*/
|
||||
pub async fn run_main(
|
||||
&'lua self,
|
||||
main: impl IntoLuaOwnedThread,
|
||||
args: impl IntoLuaMulti<'lua>,
|
||||
) -> ExitCode {
|
||||
let thread = main
|
||||
.into_owned_lua_thread(&self.lua)
|
||||
.expect("Failed to create thread for main");
|
||||
self.push_back(thread, args)
|
||||
.expect("Failed to queue thread for main");
|
||||
self.run_to_completion().await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,10 @@ use super::{
|
|||
SchedulerImpl,
|
||||
};
|
||||
|
||||
impl<'lua> SchedulerImpl {
|
||||
impl<'lua, 'fut> SchedulerImpl<'fut>
|
||||
where
|
||||
'lua: 'fut,
|
||||
{
|
||||
/**
|
||||
Checks if there are any lua threads to run.
|
||||
*/
|
||||
|
|
|
@ -18,6 +18,8 @@ mod impl_async;
|
|||
mod impl_runner;
|
||||
mod impl_threads;
|
||||
|
||||
pub use self::traits::*;
|
||||
|
||||
use self::{
|
||||
state::SchedulerState,
|
||||
thread::{SchedulerThread, SchedulerThreadId, SchedulerThreadSender},
|
||||
|
@ -30,12 +32,11 @@ use self::{
|
|||
to the same underlying scheduler and Lua struct.
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Scheduler {
|
||||
lua: Arc<Lua>,
|
||||
inner: Arc<SchedulerImpl>,
|
||||
pub(crate) struct Scheduler<'fut> {
|
||||
inner: Arc<SchedulerImpl<'fut>>,
|
||||
}
|
||||
|
||||
impl Scheduler {
|
||||
impl<'fut> Scheduler<'fut> {
|
||||
/**
|
||||
Creates a new scheduler for the given [`Lua`] struct.
|
||||
*/
|
||||
|
@ -45,12 +46,12 @@ impl Scheduler {
|
|||
|
||||
let inner = Arc::new(sched_impl);
|
||||
|
||||
Self { lua, inner }
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Scheduler {
|
||||
type Target = SchedulerImpl;
|
||||
impl<'fut> Deref for Scheduler<'fut> {
|
||||
type Target = SchedulerImpl<'fut>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
|
@ -62,15 +63,15 @@ impl Deref for Scheduler {
|
|||
Not meant to be used directly, use [`Scheduler`] instead.
|
||||
*/
|
||||
#[derive(Debug)]
|
||||
pub struct SchedulerImpl {
|
||||
pub(crate) struct SchedulerImpl<'fut> {
|
||||
lua: Arc<Lua>,
|
||||
state: SchedulerState,
|
||||
threads: RefCell<VecDeque<SchedulerThread>>,
|
||||
thread_senders: RefCell<HashMap<SchedulerThreadId, SchedulerThreadSender>>,
|
||||
futures: AsyncMutex<FuturesUnordered<Pin<Box<dyn Future<Output = ()>>>>>,
|
||||
futures: AsyncMutex<FuturesUnordered<Pin<Box<dyn Future<Output = ()> + 'fut>>>>,
|
||||
}
|
||||
|
||||
impl SchedulerImpl {
|
||||
impl<'fut> SchedulerImpl<'fut> {
|
||||
fn new(lua: Arc<Lua>) -> Self {
|
||||
Self {
|
||||
lua,
|
||||
|
|
|
@ -1,64 +1,83 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use futures_util::Future;
|
||||
use mlua::{chunk, prelude::*};
|
||||
use mlua::prelude::*;
|
||||
|
||||
use super::Scheduler;
|
||||
|
||||
const ASYNC_IMPL_LUA: &str = r#"
|
||||
schedule(...)
|
||||
return yield()
|
||||
"#;
|
||||
|
||||
/**
|
||||
Trait for extensions to the [`Lua`] struct, allowing
|
||||
for access to the scheduler without having to import
|
||||
it or handle registry / app data references manually.
|
||||
*/
|
||||
pub trait LuaSchedulerExt {
|
||||
pub trait LuaSchedulerExt<'lua, 'fut>
|
||||
where
|
||||
'lua: 'fut,
|
||||
{
|
||||
/**
|
||||
Get a reference to the scheduler for the [`Lua`] struct.
|
||||
Creates a new [`Lua`] struct with a [`Scheduler`].
|
||||
*/
|
||||
fn scheduler(&self) -> &Scheduler;
|
||||
fn new_with_scheduler() -> Arc<Self>;
|
||||
|
||||
/**
|
||||
Creates a function callable from Lua that runs an async
|
||||
closure and returns the results of it to the call site.
|
||||
*/
|
||||
fn create_async_function<'lua, A, R, F, FR>(
|
||||
&'lua self,
|
||||
func: F,
|
||||
) -> LuaResult<LuaFunction<'lua>>
|
||||
fn create_async_function<A, R, F, FR>(&'lua self, func: F) -> LuaResult<LuaFunction<'lua>>
|
||||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: IntoLuaMulti<'lua>,
|
||||
F: 'static + Fn(&'lua Lua, A) -> FR,
|
||||
FR: 'static + Future<Output = LuaResult<R>>;
|
||||
FR: 'fut + Future<Output = LuaResult<R>>;
|
||||
}
|
||||
|
||||
impl LuaSchedulerExt for Lua {
|
||||
fn scheduler(&self) -> &Scheduler {
|
||||
*self
|
||||
.app_data_ref::<&Scheduler>()
|
||||
.expect("Lua struct is missing scheduler")
|
||||
impl<'lua, 'fut> LuaSchedulerExt<'lua, 'fut> for Lua
|
||||
where
|
||||
'lua: 'fut,
|
||||
{
|
||||
fn new_with_scheduler() -> Arc<Self> {
|
||||
let lua = Arc::new(Lua::new());
|
||||
lua.set_app_data(Scheduler::new(Arc::clone(&lua)));
|
||||
lua
|
||||
}
|
||||
|
||||
fn create_async_function<'lua, A, R, F, FR>(&'lua self, func: F) -> LuaResult<LuaFunction<'lua>>
|
||||
fn create_async_function<A, R, F, FR>(&'lua self, func: F) -> LuaResult<LuaFunction<'lua>>
|
||||
where
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: IntoLuaMulti<'lua>,
|
||||
F: 'static + Fn(&'lua Lua, A) -> FR,
|
||||
FR: 'static + Future<Output = LuaResult<R>>,
|
||||
FR: 'fut + Future<Output = LuaResult<R>>,
|
||||
{
|
||||
let coroutine_yield = self
|
||||
.globals()
|
||||
.get::<_, LuaTable>("coroutine")?
|
||||
.get::<_, LuaFunction>("yield")?;
|
||||
let schedule = LuaFunction::wrap(move |lua: &Lua, args: A| {
|
||||
let thread = lua.current_thread().into_owned();
|
||||
let future = func(lua, args);
|
||||
lua.scheduler().schedule_future_thread(thread, future);
|
||||
Ok(())
|
||||
});
|
||||
let async_env = self.create_table_with_capacity(0, 2)?;
|
||||
|
||||
async_env.set(
|
||||
"yield",
|
||||
self.globals()
|
||||
.get::<_, LuaTable>("coroutine")?
|
||||
.get::<_, LuaFunction>("yield")?,
|
||||
)?;
|
||||
|
||||
async_env.set(
|
||||
"schedule",
|
||||
LuaFunction::wrap(move |lua: &Lua, args: A| {
|
||||
let _thread = lua.current_thread().into_owned();
|
||||
let _future = func(lua, args);
|
||||
let _sched = lua
|
||||
.app_data_ref::<&Scheduler>()
|
||||
.expect("Lua struct is missing scheduler");
|
||||
// FIXME: `self` escapes outside of method
|
||||
// sched.schedule_future_thread(thread, future)?;
|
||||
Ok(())
|
||||
}),
|
||||
)?;
|
||||
|
||||
let async_func = self
|
||||
.load(chunk!({
|
||||
$schedule(...)
|
||||
return $coroutine_yield()
|
||||
}))
|
||||
.load(ASYNC_IMPL_LUA)
|
||||
.set_name("async")
|
||||
.into_function()?;
|
||||
Ok(async_func)
|
||||
|
|
Loading…
Reference in a new issue