mirror of
https://github.com/lune-org/lune.git
synced 2024-12-12 13:00:37 +00:00
Use static lua for now, to make lifetimes work
This commit is contained in:
parent
e1fa89cf60
commit
1f72033a6a
5 changed files with 65 additions and 49 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
}),
|
||||
)?;
|
||||
|
|
Loading…
Reference in a new issue