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};
|
use super::{traits::IntoLuaOwnedThread, SchedulerImpl};
|
||||||
|
|
||||||
impl<'lua, 'fut> SchedulerImpl
|
impl<'lua, 'fut> SchedulerImpl<'fut>
|
||||||
where
|
where
|
||||||
'lua: 'fut,
|
'lua: 'fut,
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,7 @@ where
|
||||||
*/
|
*/
|
||||||
pub fn schedule_future<F>(&self, fut: F)
|
pub fn schedule_future<F>(&self, fut: F)
|
||||||
where
|
where
|
||||||
F: 'static + Future<Output = ()>,
|
F: 'fut + Future<Output = ()>,
|
||||||
{
|
{
|
||||||
let futs = self
|
let futs = self
|
||||||
.futures
|
.futures
|
||||||
|
@ -24,11 +24,11 @@ where
|
||||||
/**
|
/**
|
||||||
Schedules the given `thread` to run when the given `fut` completes.
|
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
|
where
|
||||||
T: 'static + IntoLuaOwnedThread,
|
T: IntoLuaOwnedThread,
|
||||||
F: 'static + Future<Output = LuaResult<R>>,
|
|
||||||
R: IntoLuaMulti<'fut>,
|
R: IntoLuaMulti<'fut>,
|
||||||
|
F: 'fut + Future<Output = LuaResult<R>>,
|
||||||
{
|
{
|
||||||
let thread = thread.into_owned_lua_thread(&self.lua)?;
|
let thread = thread.into_owned_lua_thread(&self.lua)?;
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,18 @@ use futures_util::StreamExt;
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
use tokio::task::LocalSet;
|
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.
|
Runs all lua threads to completion.
|
||||||
|
|
||||||
Returns `true` if any thread was resumed, `false` otherwise.
|
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() {
|
if self.state.has_exit_code() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +60,7 @@ impl<'lua> SchedulerImpl {
|
||||||
|
|
||||||
Returns `true` if any future was resumed, `false` otherwise.
|
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 resumed_any = false;
|
||||||
|
|
||||||
let mut futs = self
|
let mut futs = self
|
||||||
|
@ -81,7 +84,7 @@ impl<'lua> SchedulerImpl {
|
||||||
|
|
||||||
Will emit lua output and errors to stdout and stderr.
|
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 {
|
let fut = async move {
|
||||||
loop {
|
loop {
|
||||||
// 1. Run lua threads until exit or there are none left,
|
// 1. Run lua threads until exit or there are none left,
|
||||||
|
@ -116,4 +119,22 @@ impl<'lua> SchedulerImpl {
|
||||||
ExitCode::SUCCESS
|
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,
|
SchedulerImpl,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'lua> SchedulerImpl {
|
impl<'lua, 'fut> SchedulerImpl<'fut>
|
||||||
|
where
|
||||||
|
'lua: 'fut,
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
Checks if there are any lua threads to run.
|
Checks if there are any lua threads to run.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -18,6 +18,8 @@ mod impl_async;
|
||||||
mod impl_runner;
|
mod impl_runner;
|
||||||
mod impl_threads;
|
mod impl_threads;
|
||||||
|
|
||||||
|
pub use self::traits::*;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
state::SchedulerState,
|
state::SchedulerState,
|
||||||
thread::{SchedulerThread, SchedulerThreadId, SchedulerThreadSender},
|
thread::{SchedulerThread, SchedulerThreadId, SchedulerThreadSender},
|
||||||
|
@ -30,12 +32,11 @@ use self::{
|
||||||
to the same underlying scheduler and Lua struct.
|
to the same underlying scheduler and Lua struct.
|
||||||
*/
|
*/
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Scheduler {
|
pub(crate) struct Scheduler<'fut> {
|
||||||
lua: Arc<Lua>,
|
inner: Arc<SchedulerImpl<'fut>>,
|
||||||
inner: Arc<SchedulerImpl>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scheduler {
|
impl<'fut> Scheduler<'fut> {
|
||||||
/**
|
/**
|
||||||
Creates a new scheduler for the given [`Lua`] struct.
|
Creates a new scheduler for the given [`Lua`] struct.
|
||||||
*/
|
*/
|
||||||
|
@ -45,12 +46,12 @@ impl Scheduler {
|
||||||
|
|
||||||
let inner = Arc::new(sched_impl);
|
let inner = Arc::new(sched_impl);
|
||||||
|
|
||||||
Self { lua, inner }
|
Self { inner }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Scheduler {
|
impl<'fut> Deref for Scheduler<'fut> {
|
||||||
type Target = SchedulerImpl;
|
type Target = SchedulerImpl<'fut>;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.inner
|
&self.inner
|
||||||
}
|
}
|
||||||
|
@ -62,15 +63,15 @@ impl Deref for Scheduler {
|
||||||
Not meant to be used directly, use [`Scheduler`] instead.
|
Not meant to be used directly, use [`Scheduler`] instead.
|
||||||
*/
|
*/
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SchedulerImpl {
|
pub(crate) struct SchedulerImpl<'fut> {
|
||||||
lua: Arc<Lua>,
|
lua: Arc<Lua>,
|
||||||
state: SchedulerState,
|
state: SchedulerState,
|
||||||
threads: RefCell<VecDeque<SchedulerThread>>,
|
threads: RefCell<VecDeque<SchedulerThread>>,
|
||||||
thread_senders: RefCell<HashMap<SchedulerThreadId, SchedulerThreadSender>>,
|
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 {
|
fn new(lua: Arc<Lua>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
lua,
|
lua,
|
||||||
|
|
|
@ -1,64 +1,83 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use futures_util::Future;
|
use futures_util::Future;
|
||||||
use mlua::{chunk, prelude::*};
|
use mlua::prelude::*;
|
||||||
|
|
||||||
use super::Scheduler;
|
use super::Scheduler;
|
||||||
|
|
||||||
|
const ASYNC_IMPL_LUA: &str = r#"
|
||||||
|
schedule(...)
|
||||||
|
return yield()
|
||||||
|
"#;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Trait for extensions to the [`Lua`] struct, allowing
|
Trait for extensions to the [`Lua`] struct, allowing
|
||||||
for access to the scheduler without having to import
|
for access to the scheduler without having to import
|
||||||
it or handle registry / app data references manually.
|
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
|
Creates a function callable from Lua that runs an async
|
||||||
closure and returns the results of it to the call site.
|
closure and returns the results of it to the call site.
|
||||||
*/
|
*/
|
||||||
fn create_async_function<'lua, A, R, F, FR>(
|
fn create_async_function<A, R, F, FR>(&'lua self, func: F) -> LuaResult<LuaFunction<'lua>>
|
||||||
&'lua self,
|
|
||||||
func: F,
|
|
||||||
) -> LuaResult<LuaFunction<'lua>>
|
|
||||||
where
|
where
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: IntoLuaMulti<'lua>,
|
R: IntoLuaMulti<'lua>,
|
||||||
F: 'static + Fn(&'lua Lua, A) -> FR,
|
F: 'static + Fn(&'lua Lua, A) -> FR,
|
||||||
FR: 'static + Future<Output = LuaResult<R>>;
|
FR: 'fut + Future<Output = LuaResult<R>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LuaSchedulerExt for Lua {
|
impl<'lua, 'fut> LuaSchedulerExt<'lua, 'fut> for Lua
|
||||||
fn scheduler(&self) -> &Scheduler {
|
where
|
||||||
*self
|
'lua: 'fut,
|
||||||
.app_data_ref::<&Scheduler>()
|
{
|
||||||
.expect("Lua struct is missing scheduler")
|
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
|
where
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: IntoLuaMulti<'lua>,
|
R: IntoLuaMulti<'lua>,
|
||||||
F: 'static + Fn(&'lua Lua, A) -> FR,
|
F: 'static + Fn(&'lua Lua, A) -> FR,
|
||||||
FR: 'static + Future<Output = LuaResult<R>>,
|
FR: 'fut + Future<Output = LuaResult<R>>,
|
||||||
{
|
{
|
||||||
let coroutine_yield = self
|
let async_env = self.create_table_with_capacity(0, 2)?;
|
||||||
.globals()
|
|
||||||
.get::<_, LuaTable>("coroutine")?
|
async_env.set(
|
||||||
.get::<_, LuaFunction>("yield")?;
|
"yield",
|
||||||
let schedule = LuaFunction::wrap(move |lua: &Lua, args: A| {
|
self.globals()
|
||||||
let thread = lua.current_thread().into_owned();
|
.get::<_, LuaTable>("coroutine")?
|
||||||
let future = func(lua, args);
|
.get::<_, LuaFunction>("yield")?,
|
||||||
lua.scheduler().schedule_future_thread(thread, future);
|
)?;
|
||||||
Ok(())
|
|
||||||
});
|
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
|
let async_func = self
|
||||||
.load(chunk!({
|
.load(ASYNC_IMPL_LUA)
|
||||||
$schedule(...)
|
|
||||||
return $coroutine_yield()
|
|
||||||
}))
|
|
||||||
.set_name("async")
|
.set_name("async")
|
||||||
.into_function()?;
|
.into_function()?;
|
||||||
Ok(async_func)
|
Ok(async_func)
|
||||||
|
|
Loading…
Reference in a new issue