From 1f72033a6a15faff6a922af0829bca9734cd9b2e Mon Sep 17 00:00:00 2001 From: Filip Tibell Date: Fri, 18 Aug 2023 13:43:18 -0500 Subject: [PATCH] Use static lua for now, to make lifetimes work --- src/lune/mod.rs | 26 ++++++++++++++++----- src/lune/scheduler/impl_async.rs | 4 ++-- src/lune/scheduler/impl_threads.rs | 14 ++++++------ src/lune/scheduler/mod.rs | 34 +++++++++++++++------------- src/lune/scheduler/traits.rs | 36 ++++++++++++++---------------- 5 files changed, 65 insertions(+), 49 deletions(-) diff --git a/src/lune/mod.rs b/src/lune/mod.rs index dd79aac..30080cf 100644 --- a/src/lune/mod.rs +++ b/src/lune/mod.rs @@ -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, } @@ -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, script_contents: impl AsRef<[u8]>, ) -> Result { - 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); + } + } +} diff --git a/src/lune/scheduler/impl_async.rs b/src/lune/scheduler/impl_async.rs index eac200f..cf14abd 100644 --- a/src/lune/scheduler/impl_async.rs +++ b/src/lune/scheduler/impl_async.rs @@ -33,11 +33,11 @@ where FR: IntoLuaMulti<'fut>, F: Future> + '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"); diff --git a/src/lune/scheduler/impl_threads.rs b/src/lune/scheduler/impl_threads.rs index 638416d..5184576 100644 --- a/src/lune/scheduler/impl_threads.rs +++ b/src/lune/scheduler/impl_threads.rs @@ -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 { - 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 { - 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 diff --git a/src/lune/scheduler/mod.rs b/src/lune/scheduler/mod.rs index e7edc1b..0231f38 100644 --- a/src/lune/scheduler/mod.rs +++ b/src/lune/scheduler/mod.rs @@ -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 + '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>, - thread_senders: RefCell>, - futures: AsyncMutex + 'fut>>>>, + lua: &'static Lua, + state: Arc, + threads: Arc>>, + thread_senders: Arc>>, + futures: Arc>>>, } 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())), } } } diff --git a/src/lune/scheduler/traits.rs b/src/lune/scheduler/traits.rs index 0bf9ff8..b79382b 100644 --- a/src/lune/scheduler/traits.rs +++ b/src/lune/scheduler/traits.rs @@ -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(&'lua self, func: F) -> LuaResult> + fn create_async_function( + &'static self, + func: F, + ) -> LuaResult> where - A: FromLuaMulti<'lua>, - R: IntoLuaMulti<'lua>, - F: Fn(&'lua Lua, A) -> FR + 'static, - FR: Future> + 'fut; + A: FromLuaMulti<'static>, + R: IntoLuaMulti<'static>, + F: Fn(&'static Lua, A) -> FR + 'static, + FR: Future> + 'static; } -impl<'lua, 'fut> LuaSchedulerExt<'lua, 'fut> for Lua -where - 'lua: 'fut, -{ - fn create_async_function(&'lua self, func: F) -> LuaResult> +impl LuaSchedulerExt for Lua { + fn create_async_function(&'static self, func: F) -> LuaResult> where - A: FromLuaMulti<'lua>, - R: IntoLuaMulti<'lua>, - F: Fn(&'lua Lua, A) -> FR + 'static, - FR: Future> + 'fut, + A: FromLuaMulti<'static>, + R: IntoLuaMulti<'static>, + F: Fn(&'static Lua, A) -> FR + 'static, + FR: Future> + '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(()) }), )?;