mirror of
https://github.com/lune-org/lune.git
synced 2025-04-10 21:40:54 +01:00
impl require error enum
This commit is contained in:
parent
eaa1c4d16b
commit
edb3041090
2 changed files with 71 additions and 48 deletions
|
@ -9,6 +9,8 @@ use tokio::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::RequireError;
|
||||||
|
|
||||||
/// The private struct that's stored in mlua's app data container
|
/// The private struct that's stored in mlua's app data container
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct RequireContextData<'a> {
|
struct RequireContextData<'a> {
|
||||||
|
@ -29,20 +31,18 @@ impl RequireContext {
|
||||||
- when `RequireContext::init` is called more than once on the same `Lua` instance
|
- when `RequireContext::init` is called more than once on the same `Lua` instance
|
||||||
|
|
||||||
*/
|
*/
|
||||||
pub fn init(lua: &Lua) -> LuaResult<()> {
|
pub fn init(lua: &Lua) -> Result<(), RequireError> {
|
||||||
if lua.set_app_data(RequireContextData::default()).is_some() {
|
if lua.set_app_data(RequireContextData::default()).is_some() {
|
||||||
Err(LuaError::runtime(
|
Err(RequireError::RequireContextInitCalledTwice)
|
||||||
"RequireContext::init got called twice on the same Lua instance",
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn std_exists(lua: &Lua, alias: &str) -> LuaResult<bool> {
|
pub(crate) fn std_exists(lua: &Lua, alias: &str) -> Result<bool, RequireError> {
|
||||||
let data_ref = lua
|
let data_ref = lua
|
||||||
.app_data_ref::<RequireContextData>()
|
.app_data_ref::<RequireContextData>()
|
||||||
.ok_or(LuaError::runtime("Couldn't find RequireContextData in app data container, make sure RequireStorage::init is called on this lua instance"))?;
|
.ok_or(RequireError::RequireContextNotFound)?;
|
||||||
|
|
||||||
Ok(data_ref.std.contains_key(alias))
|
Ok(data_ref.std.contains_key(alias))
|
||||||
}
|
}
|
||||||
|
@ -50,10 +50,10 @@ impl RequireContext {
|
||||||
pub(crate) fn require_std(
|
pub(crate) fn require_std(
|
||||||
lua: &Lua,
|
lua: &Lua,
|
||||||
require_alias: RequireAlias,
|
require_alias: RequireAlias,
|
||||||
) -> LuaResult<LuaMultiValue<'_>> {
|
) -> Result<LuaMultiValue<'_>, RequireError> {
|
||||||
let data_ref = lua
|
let data_ref = lua
|
||||||
.app_data_ref::<RequireContextData>()
|
.app_data_ref::<RequireContextData>()
|
||||||
.ok_or(LuaError::runtime("Couldn't find RequireContextData in app data container, make sure RequireStorage::init is called on this lua instance"))?;
|
.ok_or(RequireError::RequireContextNotFound)?;
|
||||||
|
|
||||||
if let Some(cached) = data_ref.std_cache.get(&require_alias) {
|
if let Some(cached) = data_ref.std_cache.get(&require_alias) {
|
||||||
let multi_vec = lua.registry_value::<Vec<LuaValue>>(cached)?;
|
let multi_vec = lua.registry_value::<Vec<LuaValue>>(cached)?;
|
||||||
|
@ -61,21 +61,17 @@ impl RequireContext {
|
||||||
return Ok(LuaMultiValue::from_vec(multi_vec));
|
return Ok(LuaMultiValue::from_vec(multi_vec));
|
||||||
}
|
}
|
||||||
|
|
||||||
let libraries =
|
let libraries = data_ref.std.get(&require_alias.alias.as_str()).ok_or(
|
||||||
data_ref
|
RequireError::InvalidStdAlias(require_alias.alias.to_string()),
|
||||||
.std
|
)?;
|
||||||
.get(&require_alias.alias.as_str())
|
|
||||||
.ok_or(mlua::Error::runtime(format!(
|
|
||||||
"Alias '{}' does not point to a built-in standard library",
|
|
||||||
require_alias.alias
|
|
||||||
)))?;
|
|
||||||
|
|
||||||
let std = libraries
|
let std =
|
||||||
.get(require_alias.path.as_str())
|
libraries
|
||||||
.ok_or(mlua::Error::runtime(format!(
|
.get(require_alias.path.as_str())
|
||||||
"Library '{}' does not point to a member of '{}' standard libraries",
|
.ok_or(RequireError::StdMemberNotFound(
|
||||||
require_alias.path, require_alias.alias
|
require_alias.path.to_string(),
|
||||||
)))?;
|
require_alias.alias.to_string(),
|
||||||
|
))?;
|
||||||
|
|
||||||
let multi = std.module(lua)?;
|
let multi = std.module(lua)?;
|
||||||
let mutli_clone = multi.clone();
|
let mutli_clone = multi.clone();
|
||||||
|
@ -84,8 +80,8 @@ impl RequireContext {
|
||||||
drop(data_ref);
|
drop(data_ref);
|
||||||
|
|
||||||
let mut data = lua
|
let mut data = lua
|
||||||
.app_data_mut::<RequireContextData>()
|
.app_data_mut::<RequireContextData>()
|
||||||
.ok_or(LuaError::runtime("Couldn't find RequireContextData in app data container, make sure RequireStorage::init is called on this lua instance"))?;
|
.ok_or(RequireError::RequireContextNotFound)?;
|
||||||
|
|
||||||
data.std_cache.insert(require_alias, multi_reg);
|
data.std_cache.insert(require_alias, multi_reg);
|
||||||
|
|
||||||
|
@ -96,18 +92,18 @@ impl RequireContext {
|
||||||
lua: &Lua,
|
lua: &Lua,
|
||||||
path_rel: PathBuf,
|
path_rel: PathBuf,
|
||||||
path_abs: PathBuf,
|
path_abs: PathBuf,
|
||||||
) -> LuaResult<LuaMultiValue> {
|
) -> Result<LuaMultiValue, RequireError> {
|
||||||
// wait for module to be required
|
// wait for module to be required
|
||||||
// if its pending somewhere else
|
// if its pending somewhere else
|
||||||
{
|
{
|
||||||
let data_ref = lua
|
let data_ref = lua
|
||||||
.app_data_ref::<RequireContextData>()
|
.app_data_ref::<RequireContextData>()
|
||||||
.ok_or(LuaError::runtime("Couldn't find RequireContextData in app data container, make sure RequireStorage::init is called on this lua instance"))?;
|
.ok_or(RequireError::RequireContextNotFound)?;
|
||||||
|
|
||||||
let pending = data_ref.pending.try_lock().into_lua_err()?;
|
let pending = data_ref.pending.try_lock()?;
|
||||||
|
|
||||||
if let Some(a) = pending.get(&path_abs) {
|
if let Some(a) = pending.get(&path_abs) {
|
||||||
a.subscribe().recv().await.into_lua_err()?;
|
a.subscribe().recv().await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,8 +111,8 @@ impl RequireContext {
|
||||||
// *if* its cached
|
// *if* its cached
|
||||||
{
|
{
|
||||||
let data_ref = lua
|
let data_ref = lua
|
||||||
.app_data_ref::<RequireContextData>()
|
.app_data_ref::<RequireContextData>()
|
||||||
.ok_or(LuaError::runtime("Couldn't find RequireContextData in app data container, make sure RequireStorage::init is called on this lua instance"))?;
|
.ok_or(RequireError::RequireContextNotFound)?;
|
||||||
|
|
||||||
let cache = data_ref.cache.lock().await;
|
let cache = data_ref.cache.lock().await;
|
||||||
|
|
||||||
|
@ -130,22 +126,21 @@ impl RequireContext {
|
||||||
// create a broadcast channel
|
// create a broadcast channel
|
||||||
{
|
{
|
||||||
let data_ref = lua
|
let data_ref = lua
|
||||||
.app_data_ref::<RequireContextData>()
|
.app_data_ref::<RequireContextData>()
|
||||||
.ok_or(LuaError::runtime("Couldn't find RequireContextData in app data container, make sure RequireStorage::init is called on this lua instance"))?;
|
.ok_or(RequireError::RequireContextNotFound)?;
|
||||||
|
|
||||||
let (broadcast_tx, _) = broadcast::channel(1);
|
let (broadcast_tx, _) = broadcast::channel(1);
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut pending = data_ref.pending.try_lock().into_lua_err()?;
|
let mut pending = data_ref.pending.try_lock()?;
|
||||||
pending.insert(path_abs.clone(), broadcast_tx);
|
pending.insert(path_abs.clone(), broadcast_tx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !fs::try_exists(&path_abs).await? {
|
if !fs::try_exists(&path_abs).await? {
|
||||||
return Err(LuaError::runtime(format!(
|
return Err(RequireError::InvalidRequire(
|
||||||
"Can not require '{}' as it does not exist",
|
path_rel.to_string_lossy().to_string(),
|
||||||
path_rel.to_string_lossy()
|
));
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let content = fs::read_to_string(&path_abs).await?;
|
let content = fs::read_to_string(&path_abs).await?;
|
||||||
|
@ -161,7 +156,7 @@ impl RequireContext {
|
||||||
|
|
||||||
let data_ref = lua
|
let data_ref = lua
|
||||||
.app_data_ref::<RequireContextData>()
|
.app_data_ref::<RequireContextData>()
|
||||||
.ok_or(LuaError::runtime("Couldn't find RequireContextData in app data container, make sure RequireStorage::init is called on this lua instance"))?;
|
.ok_or(RequireError::RequireContextNotFound)?;
|
||||||
|
|
||||||
data_ref
|
data_ref
|
||||||
.cache
|
.cache
|
||||||
|
@ -205,10 +200,10 @@ impl RequireContext {
|
||||||
lua: &Lua,
|
lua: &Lua,
|
||||||
alias: &'static str,
|
alias: &'static str,
|
||||||
std: impl StandardLibrary + 'static,
|
std: impl StandardLibrary + 'static,
|
||||||
) -> LuaResult<()> {
|
) -> Result<(), RequireError> {
|
||||||
let mut data = lua
|
let mut data = lua
|
||||||
.app_data_mut::<RequireContextData>()
|
.app_data_mut::<RequireContextData>()
|
||||||
.ok_or(LuaError::runtime("Couldn't find RequireContextData in app data container, make sure RequireStorage::init is called on this lua instance"))?;
|
.ok_or(RequireError::RequireContextNotFound)?;
|
||||||
|
|
||||||
if let Some(map) = data.std.get_mut(alias) {
|
if let Some(map) = data.std.get_mut(alias) {
|
||||||
map.insert(std.name(), Box::new(std));
|
map.insert(std.name(), Box::new(std));
|
||||||
|
|
|
@ -6,17 +6,41 @@ use crate::{
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
use path::resolve_path;
|
use path::resolve_path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
pub mod context;
|
pub mod context;
|
||||||
mod path;
|
mod path;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum RequireError {
|
||||||
|
#[error("failed to find RequireContextData in the app data container, make sure to call RequireContext::init first")]
|
||||||
|
RequireContextNotFound,
|
||||||
|
#[error("make sure to call RequireContext::init")]
|
||||||
|
RequireContextInitCalledTwice,
|
||||||
|
#[error("Can not require '{0}' as it does not exist")]
|
||||||
|
InvalidRequire(String),
|
||||||
|
#[error("Alias '{0}' does not point to a built-in standard library")]
|
||||||
|
InvalidStdAlias(String),
|
||||||
|
#[error("Library '{0}' does not point to a member of '{1}' standard libraries")]
|
||||||
|
StdMemberNotFound(String, String),
|
||||||
|
|
||||||
|
#[error("IOError: {0}")]
|
||||||
|
IOError(#[from] std::io::Error),
|
||||||
|
#[error("TryLockError: {0}")]
|
||||||
|
TryLockError(#[from] tokio::sync::TryLockError),
|
||||||
|
#[error("BroadcastRecvError: {0}")]
|
||||||
|
BroadcastRecvError(#[from] tokio::sync::broadcast::error::RecvError),
|
||||||
|
#[error("LuaError: {0}")]
|
||||||
|
LuaError(#[from] mlua::Error),
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn lua_require(lua: &Lua, path: String) -> LuaResult<LuaMultiValue> {
|
pub async fn lua_require(lua: &Lua, path: String) -> LuaResult<LuaMultiValue> {
|
||||||
let require_path_rel = PathBuf::from(path);
|
let require_path_rel = PathBuf::from(path);
|
||||||
let require_alias = path_to_alias(&require_path_rel).into_lua_err()?;
|
let require_alias = path_to_alias(&require_path_rel).into_lua_err()?;
|
||||||
|
|
||||||
if let Some(require_alias) = require_alias {
|
if let Some(require_alias) = require_alias {
|
||||||
if context::RequireContext::std_exists(lua, &require_alias.alias)? {
|
if context::RequireContext::std_exists(lua, &require_alias.alias).into_lua_err()? {
|
||||||
context::RequireContext::require_std(lua, require_alias)
|
context::RequireContext::require_std(lua, require_alias).into_lua_err()
|
||||||
} else {
|
} else {
|
||||||
let require_path_abs = resolve_path(
|
let require_path_abs = resolve_path(
|
||||||
&Luaurc::resolve_path(lua, &require_alias)
|
&Luaurc::resolve_path(lua, &require_alias)
|
||||||
|
@ -25,7 +49,9 @@ pub async fn lua_require(lua: &Lua, path: String) -> LuaResult<LuaMultiValue> {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
context::RequireContext::require(lua, require_path_rel, require_path_abs).await
|
context::RequireContext::require(lua, require_path_rel, require_path_abs)
|
||||||
|
.await
|
||||||
|
.into_lua_err()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let parent_path = get_parent_path(lua)?;
|
let parent_path = get_parent_path(lua)?;
|
||||||
|
@ -38,17 +64,19 @@ pub async fn lua_require(lua: &Lua, path: String) -> LuaResult<LuaMultiValue> {
|
||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
context::RequireContext::require(lua, require_path_rel, require_path_abs).await
|
context::RequireContext::require(lua, require_path_rel, require_path_abs)
|
||||||
|
.await
|
||||||
|
.into_lua_err()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(lua: &Lua) -> LuaResult<LuaValue> {
|
pub fn create(lua: &Lua) -> LuaResult<LuaValue> {
|
||||||
let f = lua.create_async_function(lua_require)?;
|
let f = lua.create_async_function(lua_require).into_lua_err()?;
|
||||||
|
|
||||||
context::RequireContext::init(lua)?;
|
context::RequireContext::init(lua).into_lua_err()?;
|
||||||
|
|
||||||
for std in LuneStandardLibrary::ALL {
|
for std in LuneStandardLibrary::ALL {
|
||||||
context::RequireContext::inject_std(lua, "lune", *std)?;
|
context::RequireContext::inject_std(lua, "lune", *std).into_lua_err()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
f.into_lua(lua)
|
f.into_lua(lua)
|
||||||
|
|
Loading…
Add table
Reference in a new issue