mirror of
https://github.com/lune-org/lune.git
synced 2025-03-04 11:11:39 +00:00
Implement basic abs path require, propagate async errors back to lua threads
This commit is contained in:
parent
bcef44e286
commit
dcb989fd92
9 changed files with 95 additions and 47 deletions
|
@ -2,12 +2,19 @@ use mlua::prelude::*;
|
|||
|
||||
use super::context::*;
|
||||
|
||||
pub(super) async fn require<'lua>(
|
||||
_lua: &'lua Lua,
|
||||
_ctx: RequireContext,
|
||||
pub(super) async fn require<'lua, 'ctx>(
|
||||
lua: &'lua Lua,
|
||||
ctx: &'ctx RequireContext,
|
||||
path: &str,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
Err(LuaError::runtime(format!(
|
||||
"TODO: Support require for absolute paths (tried to require '{path}')"
|
||||
)))
|
||||
) -> LuaResult<LuaMultiValue<'lua>>
|
||||
where
|
||||
'lua: 'ctx,
|
||||
{
|
||||
if ctx.is_cached(path)? {
|
||||
ctx.get_from_cache(lua, path)
|
||||
} else if ctx.is_pending(path)? {
|
||||
ctx.wait_for_cache(lua, path).await
|
||||
} else {
|
||||
ctx.load(lua, path).await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,15 @@ use mlua::prelude::*;
|
|||
|
||||
use super::context::*;
|
||||
|
||||
pub(super) async fn require<'lua>(
|
||||
pub(super) async fn require<'lua, 'ctx>(
|
||||
_lua: &'lua Lua,
|
||||
_ctx: RequireContext,
|
||||
_ctx: &'ctx RequireContext,
|
||||
alias: &str,
|
||||
name: &str,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
) -> LuaResult<LuaMultiValue<'lua>>
|
||||
where
|
||||
'lua: 'ctx,
|
||||
{
|
||||
Err(LuaError::runtime(format!(
|
||||
"TODO: Support require for built-in libraries (tried to require '{name}' with alias '{alias}')"
|
||||
)))
|
||||
|
|
|
@ -2,11 +2,14 @@ use mlua::prelude::*;
|
|||
|
||||
use super::context::*;
|
||||
|
||||
pub(super) async fn require<'lua>(
|
||||
pub(super) async fn require<'lua, 'ctx>(
|
||||
_lua: &'lua Lua,
|
||||
_ctx: RequireContext,
|
||||
_ctx: &'ctx RequireContext,
|
||||
name: &str,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
) -> LuaResult<LuaMultiValue<'lua>>
|
||||
where
|
||||
'lua: 'ctx,
|
||||
{
|
||||
Err(LuaError::runtime(format!(
|
||||
"TODO: Support require for built-in libraries (tried to require '{name}')"
|
||||
)))
|
||||
|
|
|
@ -23,17 +23,15 @@ impl RequireContext {
|
|||
context should be created per [`Lua`] struct, creating more
|
||||
than one context may lead to undefined require-behavior.
|
||||
*/
|
||||
pub fn create(lua: &Lua) {
|
||||
let this = Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
// TODO: Set to false by default, load some kind of config
|
||||
// or env var to check if we should be using absolute paths
|
||||
use_absolute_paths: true,
|
||||
working_directory: env::current_dir().expect("Failed to get current working directory"),
|
||||
cache_results: Arc::new(AsyncMutex::new(HashMap::new())),
|
||||
cache_pending: Arc::new(AsyncMutex::new(HashMap::new())),
|
||||
};
|
||||
lua.set_named_registry_value(REGISTRY_KEY, this)
|
||||
.expect("Failed to insert RequireContext into registry");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,9 +100,9 @@ impl RequireContext {
|
|||
path will first be transformed into an absolute path.
|
||||
*/
|
||||
pub fn get_from_cache<'lua>(
|
||||
&'lua self,
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
path: impl AsRef<str> + 'lua,
|
||||
path: impl AsRef<str>,
|
||||
) -> LuaResult<LuaMultiValue<'lua>> {
|
||||
let path = self.abs_path(path);
|
||||
|
||||
|
@ -136,9 +134,9 @@ impl RequireContext {
|
|||
path will first be transformed into an absolute path.
|
||||
*/
|
||||
pub async fn wait_for_cache<'lua>(
|
||||
&'lua self,
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
path: impl AsRef<str> + 'lua,
|
||||
path: impl AsRef<str>,
|
||||
) -> LuaResult<LuaMultiValue<'lua>> {
|
||||
let path = self.abs_path(path);
|
||||
let sched = lua
|
||||
|
@ -166,9 +164,9 @@ impl RequireContext {
|
|||
path will first be transformed into an absolute path.
|
||||
*/
|
||||
pub async fn load<'lua>(
|
||||
&'lua self,
|
||||
&self,
|
||||
lua: &'lua Lua,
|
||||
path: impl AsRef<str> + 'lua,
|
||||
path: impl AsRef<str>,
|
||||
) -> LuaResult<LuaMultiValue<'lua>> {
|
||||
let path = self.abs_path(path);
|
||||
let sched = lua
|
||||
|
|
|
@ -11,31 +11,34 @@ mod builtin;
|
|||
mod relative;
|
||||
|
||||
pub fn create(lua: &'static Lua) -> LuaResult<impl IntoLua<'_>> {
|
||||
RequireContext::create(lua);
|
||||
|
||||
lua.set_app_data(RequireContext::new());
|
||||
lua.create_async_function(|lua, path: LuaString| async move {
|
||||
let context = RequireContext::from(lua);
|
||||
|
||||
let path = path
|
||||
.to_str()
|
||||
.into_lua_err()
|
||||
.context("Failed to parse require path as string")?
|
||||
.to_string();
|
||||
|
||||
if let Some(builtin_name) = path
|
||||
let context = lua
|
||||
.app_data_ref()
|
||||
.expect("Failed to get RequireContext from app data");
|
||||
|
||||
let res = if let Some(builtin_name) = path
|
||||
.strip_prefix("@lune/")
|
||||
.map(|name| name.to_ascii_lowercase())
|
||||
{
|
||||
builtin::require(lua, context, &builtin_name).await
|
||||
builtin::require(lua, &context, &builtin_name).await
|
||||
} else if let Some(aliased_path) = path.strip_prefix('@') {
|
||||
let (alias, name) = aliased_path.split_once('/').ok_or(LuaError::runtime(
|
||||
"Require with custom alias must contain '/' delimiter",
|
||||
))?;
|
||||
alias::require(lua, context, alias, name).await
|
||||
alias::require(lua, &context, alias, name).await
|
||||
} else if context.use_absolute_paths() {
|
||||
absolute::require(lua, context, &path).await
|
||||
absolute::require(lua, &context, &path).await
|
||||
} else {
|
||||
relative::require(lua, context, &path).await
|
||||
}
|
||||
relative::require(lua, &context, &path).await
|
||||
};
|
||||
|
||||
res.clone()
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2,11 +2,14 @@ use mlua::prelude::*;
|
|||
|
||||
use super::context::*;
|
||||
|
||||
pub(super) async fn require<'lua>(
|
||||
pub(super) async fn require<'lua, 'ctx>(
|
||||
_lua: &'lua Lua,
|
||||
_ctx: RequireContext,
|
||||
_ctx: &'ctx RequireContext,
|
||||
path: &str,
|
||||
) -> LuaResult<LuaValue<'lua>> {
|
||||
) -> LuaResult<LuaMultiValue<'lua>>
|
||||
where
|
||||
'lua: 'ctx,
|
||||
{
|
||||
Err(LuaError::runtime(format!(
|
||||
"TODO: Support require for absolute paths (tried to require '{path}')"
|
||||
)))
|
||||
|
|
|
@ -37,13 +37,20 @@ where
|
|||
{
|
||||
let thread = thread.into_owned_lua_thread(self.lua)?;
|
||||
self.schedule_future(async move {
|
||||
// TODO: Throw any error back to lua instead of panicking here
|
||||
let rets = fut.await.expect("Failed to receive result");
|
||||
let rets = rets
|
||||
.into_lua_multi(self.lua)
|
||||
.expect("Failed to create return multi value");
|
||||
self.push_back(thread, rets)
|
||||
match fut.await.and_then(|rets| rets.into_lua_multi(self.lua)) {
|
||||
Err(e) => {
|
||||
self.state.set_lua_error(e);
|
||||
// NOTE: We push the thread to the front of the scheduler
|
||||
// to ensure that it runs first to be able to catch the
|
||||
// stored error from within the scheduler lua interrupt
|
||||
self.push_front(thread, ())
|
||||
.expect("Failed to schedule future thread");
|
||||
}
|
||||
Ok(v) => {
|
||||
self.push_back(thread, v)
|
||||
.expect("Failed to schedule future thread");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -44,13 +44,23 @@ pub(crate) struct Scheduler<'lua, 'fut> {
|
|||
|
||||
impl<'lua, 'fut> Scheduler<'lua, 'fut> {
|
||||
pub fn new(lua: &'lua Lua) -> Self {
|
||||
Self {
|
||||
let this = Self {
|
||||
lua,
|
||||
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())),
|
||||
}
|
||||
};
|
||||
|
||||
// HACK: Propagate errors given to the scheduler back to their lua threads
|
||||
// FUTURE: Do profiling and anything else we need inside of this interrupt
|
||||
let state = this.state.clone();
|
||||
lua.set_interrupt(move |_| match state.get_lua_error() {
|
||||
Some(e) => Err(e),
|
||||
None => Ok(LuaVmState::Continue),
|
||||
});
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
use std::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use mlua::Error as LuaError;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct SchedulerState {
|
||||
|
@ -6,6 +11,7 @@ pub struct SchedulerState {
|
|||
exit_code: AtomicU8,
|
||||
num_resumptions: AtomicUsize,
|
||||
num_errors: AtomicUsize,
|
||||
lua_error: RefCell<Option<LuaError>>,
|
||||
}
|
||||
|
||||
impl SchedulerState {
|
||||
|
@ -41,4 +47,12 @@ impl SchedulerState {
|
|||
self.exit_state.store(true, Ordering::SeqCst);
|
||||
self.exit_code.store(code.into(), Ordering::SeqCst);
|
||||
}
|
||||
|
||||
pub fn get_lua_error(&self) -> Option<LuaError> {
|
||||
self.lua_error.take()
|
||||
}
|
||||
|
||||
pub fn set_lua_error(&self, e: LuaError) {
|
||||
self.lua_error.replace(Some(e));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue