Use static lua for now, to make lifetimes work

This commit is contained in:
Filip Tibell 2023-08-18 13:43:18 -05:00
parent e1fa89cf60
commit 1f72033a6a
5 changed files with 65 additions and 49 deletions

View file

@ -6,9 +6,11 @@ mod scheduler;
use self::scheduler::Scheduler;
pub use error::LuneError;
use mlua::Lua;
#[derive(Clone, Debug, Default)]
#[derive(Debug, Clone)]
pub struct Lune {
lua: &'static Lua,
args: Vec<String>,
}
@ -16,8 +18,12 @@ impl Lune {
/**
Creates a new Lune script runner.
*/
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self::default()
Self {
lua: Lua::new().into_static(),
args: Vec::new(),
}
}
/**
@ -39,15 +45,25 @@ impl Lune {
script_name: impl AsRef<str>,
script_contents: impl AsRef<[u8]>,
) -> Result<ExitCode, LuneError> {
let scheduler = Scheduler::new();
let scheduler = Scheduler::new(self.lua);
self.lua.set_app_data(scheduler.clone());
let main = scheduler
let main = self
.lua
.load(script_contents.as_ref())
.set_name(script_name.as_ref());
scheduler.push_back(main, ())?;
Ok(scheduler.run_to_completion().await)
}
}
impl Drop for Lune {
fn drop(&mut self) {
// SAFETY: The scheduler needs the static lifetime reference to lua,
// when dropped nothing outside of here has access to the scheduler
unsafe {
Lua::from_static(self.lua);
}
}
}

View file

@ -33,11 +33,11 @@ where
FR: IntoLuaMulti<'fut>,
F: Future<Output = LuaResult<FR>> + 'fut,
{
let thread = thread.into_owned_lua_thread(&self.lua)?;
let thread = thread.into_owned_lua_thread(self.lua)?;
self.schedule_future(async move {
let rets = fut.await.expect("Failed to receive result");
let rets = rets
.into_lua_multi(&self.lua)
.into_lua_multi(self.lua)
.expect("Failed to create return multi value");
self.push_back(thread, rets)
.expect("Failed to schedule future thread");

View file

@ -39,7 +39,7 @@ where
{
Some(thread) => {
let thread_id = &thread.id();
let (thread, args) = thread.into_inner(&self.lua);
let (thread, args) = thread.into_inner(self.lua);
let sender = self
.thread_senders
.borrow_mut()
@ -60,10 +60,10 @@ where
thread: impl IntoLuaOwnedThread,
args: impl IntoLuaMulti<'a>,
) -> LuaResult<SchedulerThreadId> {
let thread = thread.into_owned_lua_thread(&self.lua)?;
let args = args.into_lua_multi(&self.lua)?;
let thread = thread.into_owned_lua_thread(self.lua)?;
let args = args.into_lua_multi(self.lua)?;
let thread = SchedulerThread::new(&self.lua, thread, args)?;
let thread = SchedulerThread::new(self.lua, thread, args)?;
let thread_id = thread.id();
self.threads
@ -87,10 +87,10 @@ where
thread: impl IntoLuaOwnedThread,
args: impl IntoLuaMulti<'a>,
) -> LuaResult<SchedulerThreadId> {
let thread = thread.into_owned_lua_thread(&self.lua)?;
let args = args.into_lua_multi(&self.lua)?;
let thread = thread.into_owned_lua_thread(self.lua)?;
let args = args.into_lua_multi(self.lua)?;
let thread = SchedulerThread::new(&self.lua, thread, args)?;
let thread = SchedulerThread::new(self.lua, thread, args)?;
let thread_id = thread.id();
self.threads

View file

@ -2,6 +2,7 @@ use std::{
cell::RefCell,
collections::{HashMap, VecDeque},
pin::Pin,
sync::Arc,
};
use futures_util::{stream::FuturesUnordered, Future};
@ -23,30 +24,31 @@ use self::{
thread::{SchedulerThread, SchedulerThreadId, SchedulerThreadSender},
};
/**
Scheduler for Lua threads.
type SchedulerFuture<'fut> = Pin<Box<dyn Future<Output = ()> + 'fut>>;
This wraps a [`Lua`] struct and exposes it as the `lua` property.
/**
Scheduler for Lua threads and futures.
This scheduler can be cheaply cloned and the underlying state
and data will remain unchanged and accessible from all clones.
*/
#[derive(Debug)]
#[derive(Debug, Clone)]
pub(crate) struct Scheduler<'fut> {
pub(crate) lua: Lua,
state: SchedulerState,
threads: RefCell<VecDeque<SchedulerThread>>,
thread_senders: RefCell<HashMap<SchedulerThreadId, SchedulerThreadSender>>,
futures: AsyncMutex<FuturesUnordered<Pin<Box<dyn Future<Output = ()> + 'fut>>>>,
lua: &'static Lua,
state: Arc<SchedulerState>,
threads: Arc<RefCell<VecDeque<SchedulerThread>>>,
thread_senders: Arc<RefCell<HashMap<SchedulerThreadId, SchedulerThreadSender>>>,
futures: Arc<AsyncMutex<FuturesUnordered<SchedulerFuture<'fut>>>>,
}
impl<'fut> Scheduler<'fut> {
pub fn new() -> Self {
let lua = Lua::new();
pub fn new(lua: &'static Lua) -> Self {
Self {
lua,
state: SchedulerState::new(),
threads: RefCell::new(VecDeque::new()),
thread_senders: RefCell::new(HashMap::new()),
futures: AsyncMutex::new(FuturesUnordered::new()),
state: Arc::new(SchedulerState::new()),
threads: Arc::new(RefCell::new(VecDeque::new())),
thread_senders: Arc::new(RefCell::new(HashMap::new())),
futures: Arc::new(AsyncMutex::new(FuturesUnordered::new())),
}
}
}

View file

@ -13,32 +13,29 @@ return yield()
for access to the scheduler without having to import
it or handle registry / app data references manually.
*/
pub trait LuaSchedulerExt<'lua, 'fut>
where
'lua: 'fut,
{
pub trait LuaSchedulerExt {
/**
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<A, R, F, FR>(&'lua self, func: F) -> LuaResult<LuaFunction<'lua>>
fn create_async_function<A, R, F, FR>(
&'static self,
func: F,
) -> LuaResult<LuaFunction<'static>>
where
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: Fn(&'lua Lua, A) -> FR + 'static,
FR: Future<Output = LuaResult<R>> + 'fut;
A: FromLuaMulti<'static>,
R: IntoLuaMulti<'static>,
F: Fn(&'static Lua, A) -> FR + 'static,
FR: Future<Output = LuaResult<R>> + 'static;
}
impl<'lua, 'fut> LuaSchedulerExt<'lua, 'fut> for Lua
where
'lua: 'fut,
{
fn create_async_function<A, R, F, FR>(&'lua self, func: F) -> LuaResult<LuaFunction<'lua>>
impl LuaSchedulerExt for Lua {
fn create_async_function<A, R, F, FR>(&'static self, func: F) -> LuaResult<LuaFunction<'static>>
where
A: FromLuaMulti<'lua>,
R: IntoLuaMulti<'lua>,
F: Fn(&'lua Lua, A) -> FR + 'static,
FR: Future<Output = LuaResult<R>> + 'fut,
A: FromLuaMulti<'static>,
R: IntoLuaMulti<'static>,
F: Fn(&'static Lua, A) -> FR + 'static,
FR: Future<Output = LuaResult<R>> + 'static,
{
let async_env = self.create_table_with_capacity(0, 2)?;
@ -58,7 +55,8 @@ where
.app_data_ref::<&Scheduler>()
.expect("Lua struct is missing scheduler");
// FIXME: `self` escapes outside of method because we are borrowing `func`?
// sched.schedule_future_thread(thread, future)?;
// For now we solve this by just using a &'static Lua reference everywhere
sched.schedule_future_thread(thread, future)?;
Ok(())
}),
)?;