mirror of
https://github.com/lune-org/lune.git
synced 2025-04-18 10:53:46 +01:00
require and cache impl for stds
This commit is contained in:
parent
12b87b3065
commit
370c7f8187
4 changed files with 135 additions and 21 deletions
|
@ -1,4 +1,4 @@
|
||||||
use crate::{luaurc::path_to_alias, path::get_parent_path};
|
use crate::{luaurc::path_to_alias, path::get_parent_path, LuneStandardLibrary};
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -9,11 +9,8 @@ pub async fn lua_require(lua: &Lua, path: String) -> LuaResult<LuaMultiValue> {
|
||||||
let require_alias = path_to_alias(&require_path_rel)?;
|
let require_alias = path_to_alias(&require_path_rel)?;
|
||||||
|
|
||||||
if let Some(require_alias) = require_alias {
|
if let Some(require_alias) = require_alias {
|
||||||
if require_alias.alias == "lune" {
|
if storage::RequireStorage::std_exists(lua, &require_alias.alias)? {
|
||||||
Err(LuaError::runtime(format!(
|
storage::RequireStorage::require_std(lua, require_alias)
|
||||||
"Tried requiring a lune library '{}'\nbut aliases are not implemented yet.",
|
|
||||||
require_alias.path,
|
|
||||||
)))
|
|
||||||
} else {
|
} else {
|
||||||
Err(LuaError::runtime(format!(
|
Err(LuaError::runtime(format!(
|
||||||
"Tried requiring a custom alias '{}'\nbut aliases are not implemented yet.",
|
"Tried requiring a custom alias '{}'\nbut aliases are not implemented yet.",
|
||||||
|
@ -22,7 +19,7 @@ pub async fn lua_require(lua: &Lua, path: String) -> LuaResult<LuaMultiValue> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let parent_path = get_parent_path(lua)?;
|
let parent_path = get_parent_path(lua)?;
|
||||||
let require_path_abs = parent_path.join(require_path_rel);
|
let require_path_abs = parent_path.join(&require_path_rel);
|
||||||
|
|
||||||
Err(LuaError::runtime(format!(
|
Err(LuaError::runtime(format!(
|
||||||
"Tried requiring '{}'\nbut requires are not implemented yet.",
|
"Tried requiring '{}'\nbut requires are not implemented yet.",
|
||||||
|
@ -34,5 +31,11 @@ pub async fn lua_require(lua: &Lua, path: String) -> LuaResult<LuaMultiValue> {
|
||||||
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)?;
|
||||||
|
|
||||||
|
storage::RequireStorage::init(lua)?;
|
||||||
|
|
||||||
|
for std in LuneStandardLibrary::ALL {
|
||||||
|
storage::RequireStorage::inject_std(lua, "lune", *std)?;
|
||||||
|
}
|
||||||
|
|
||||||
f.into_lua(lua)
|
f.into_lua(lua)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,92 @@
|
||||||
use crate::library::StandardLibrary;
|
use crate::{library::StandardLibrary, luaurc::RequireAlias};
|
||||||
|
use mlua::prelude::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct RequireStorage<'a> {
|
/// The private struct that's stored in mlua's app data container
|
||||||
stds: HashMap<&'a str, Box<dyn StandardLibrary>>,
|
#[derive(Debug, Default)]
|
||||||
|
struct RequireStorageData<'a> {
|
||||||
|
std: HashMap<&'a str, HashMap<&'a str, Box<dyn StandardLibrary>>>,
|
||||||
|
std_cache: HashMap<RequireAlias, LuaRegistryKey>,
|
||||||
|
cache: HashMap<&'a str, LuaRegistryKey>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RequireStorage {}
|
||||||
|
|
||||||
|
impl RequireStorage {
|
||||||
|
pub fn init(lua: &Lua) -> LuaResult<()> {
|
||||||
|
if lua.set_app_data(RequireStorageData::default()).is_some() {
|
||||||
|
Err(LuaError::runtime("RequireStorage::init got called twice"))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn std_exists(lua: &Lua, alias: &str) -> LuaResult<bool> {
|
||||||
|
let data_ref = lua
|
||||||
|
.app_data_ref::<RequireStorageData>()
|
||||||
|
.ok_or(LuaError::runtime("Couldn't find RequireStorageData in app data container, make sure RequireStorage::init is called on this lua instance"))?;
|
||||||
|
|
||||||
|
Ok(data_ref.std.contains_key(alias))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn require_std(lua: &Lua, require_alias: RequireAlias) -> LuaResult<LuaMultiValue<'_>> {
|
||||||
|
let data_ref = lua
|
||||||
|
.app_data_ref::<RequireStorageData>()
|
||||||
|
.ok_or(LuaError::runtime("Couldn't find RequireStorageData in app data container, make sure RequireStorage::init is called on this lua instance"))?;
|
||||||
|
|
||||||
|
if let Some(cached) = data_ref.std_cache.get(&require_alias) {
|
||||||
|
return cached.into_lua(lua)?.into_lua_multi(lua);
|
||||||
|
}
|
||||||
|
|
||||||
|
let libraries =
|
||||||
|
data_ref
|
||||||
|
.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
|
||||||
|
.get(require_alias.path.as_str())
|
||||||
|
.ok_or(mlua::Error::runtime(format!(
|
||||||
|
"Library '{}' does not point to a member of '{}' standard libraries",
|
||||||
|
require_alias.path, require_alias.alias
|
||||||
|
)))?;
|
||||||
|
|
||||||
|
let multi = std.module(lua)?;
|
||||||
|
let mutli_clone = multi.clone();
|
||||||
|
let multi_reg = lua.create_registry_value(mutli_clone.into_vec())?;
|
||||||
|
|
||||||
|
let mut data = lua
|
||||||
|
.app_data_mut::<RequireStorageData>()
|
||||||
|
.ok_or(LuaError::runtime("Couldn't find RequireStorageData in app data container, make sure RequireStorage::init is called on this lua instance"))?;
|
||||||
|
|
||||||
|
data.std_cache.insert(require_alias, multi_reg);
|
||||||
|
|
||||||
|
Ok(multi)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inject_std(
|
||||||
|
lua: &Lua,
|
||||||
|
alias: &'static str,
|
||||||
|
std: impl StandardLibrary + 'static,
|
||||||
|
) -> LuaResult<()> {
|
||||||
|
let mut data = lua
|
||||||
|
.app_data_mut::<RequireStorageData>()
|
||||||
|
.ok_or(LuaError::runtime("Couldn't find RequireStorageData in app data container, make sure RequireStorage::init is called on this lua instance"))?;
|
||||||
|
|
||||||
|
if let Some(map) = data.std.get_mut(alias) {
|
||||||
|
map.insert(std.name(), Box::new(std));
|
||||||
|
} else {
|
||||||
|
let mut map: HashMap<&str, Box<dyn StandardLibrary>> = HashMap::new();
|
||||||
|
|
||||||
|
map.insert(std.name(), Box::new(std));
|
||||||
|
|
||||||
|
data.std.insert(alias, map);
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
use std::str::FromStr;
|
use std::{fmt::Debug, str::FromStr};
|
||||||
|
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
|
|
||||||
pub trait StandardLibrary {
|
pub trait StandardLibrary
|
||||||
|
where
|
||||||
|
Self: Debug,
|
||||||
|
{
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
|
|
||||||
fn module<'lua>(&self, lua: &'lua Lua) -> LuaResult<LuaMultiValue<'lua>>;
|
fn module<'lua>(&self, lua: &'lua Lua) -> LuaResult<LuaMultiValue<'lua>>;
|
||||||
|
@ -26,6 +29,25 @@ pub enum LuneStandardLibrary {
|
||||||
#[cfg(feature = "roblox")] Roblox,
|
#[cfg(feature = "roblox")] Roblox,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LuneStandardLibrary {
|
||||||
|
/**
|
||||||
|
All available standard libraries.
|
||||||
|
*/
|
||||||
|
#[rustfmt::skip]
|
||||||
|
pub const ALL: &'static [Self] = &[
|
||||||
|
#[cfg(feature = "datetime")] Self::DateTime,
|
||||||
|
#[cfg(feature = "fs")] Self::Fs,
|
||||||
|
#[cfg(feature = "luau")] Self::Luau,
|
||||||
|
#[cfg(feature = "net")] Self::Net,
|
||||||
|
#[cfg(feature = "task")] Self::Task,
|
||||||
|
#[cfg(feature = "process")] Self::Process,
|
||||||
|
#[cfg(feature = "regex")] Self::Regex,
|
||||||
|
#[cfg(feature = "serde")] Self::Serde,
|
||||||
|
#[cfg(feature = "stdio")] Self::Stdio,
|
||||||
|
#[cfg(feature = "roblox")] Self::Roblox,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
impl StandardLibrary for LuneStandardLibrary {
|
impl StandardLibrary for LuneStandardLibrary {
|
||||||
/**
|
/**
|
||||||
Gets the name of the library, such as `datetime` or `fs`.
|
Gets the name of the library, such as `datetime` or `fs`.
|
||||||
|
|
|
@ -8,10 +8,10 @@ use std::{
|
||||||
};
|
};
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
|
||||||
pub struct RequireAlias<'a> {
|
pub struct RequireAlias {
|
||||||
pub alias: &'a str,
|
pub alias: String,
|
||||||
pub path: &'a str,
|
pub path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||||
|
@ -26,7 +26,7 @@ pub struct Luaurc {
|
||||||
/// `@lune/task` becomes `Some({ alias: "lune", path: "task" })`
|
/// `@lune/task` becomes `Some({ alias: "lune", path: "task" })`
|
||||||
///
|
///
|
||||||
/// `../path/script` becomes `None`
|
/// `../path/script` becomes `None`
|
||||||
pub fn path_to_alias(path: &Path) -> Result<Option<RequireAlias<'_>>, mlua::Error> {
|
pub fn path_to_alias(path: &Path) -> Result<Option<RequireAlias>, mlua::Error> {
|
||||||
if let Some(aliased_path) = path
|
if let Some(aliased_path) = path
|
||||||
.to_str()
|
.to_str()
|
||||||
.ok_or(mlua::Error::runtime("Couldn't turn path into string"))?
|
.ok_or(mlua::Error::runtime("Couldn't turn path into string"))?
|
||||||
|
@ -36,7 +36,10 @@ pub fn path_to_alias(path: &Path) -> Result<Option<RequireAlias<'_>>, mlua::Erro
|
||||||
"Require with alias doesn't contain '/'",
|
"Require with alias doesn't contain '/'",
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
Ok(Some(RequireAlias { alias, path }))
|
Ok(Some(RequireAlias {
|
||||||
|
alias: alias.to_string(),
|
||||||
|
path: path.to_string(),
|
||||||
|
}))
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -55,7 +58,7 @@ async fn parse_luaurc(_: &mlua::Lua, path: &PathBuf) -> Result<Option<Luaurc>, m
|
||||||
/// until an alias for the provided `RequireAlias` is found
|
/// until an alias for the provided `RequireAlias` is found
|
||||||
pub async fn resolve_require_alias<'lua>(
|
pub async fn resolve_require_alias<'lua>(
|
||||||
lua: &'lua mlua::Lua,
|
lua: &'lua mlua::Lua,
|
||||||
alias: &'lua RequireAlias<'lua>,
|
alias: &'lua RequireAlias,
|
||||||
) -> Result<PathBuf, mlua::Error> {
|
) -> Result<PathBuf, mlua::Error> {
|
||||||
let cwd = current_dir()?;
|
let cwd = current_dir()?;
|
||||||
let parent = cwd.join(get_parent_path(lua)?);
|
let parent = cwd.join(get_parent_path(lua)?);
|
||||||
|
@ -65,8 +68,8 @@ pub async fn resolve_require_alias<'lua>(
|
||||||
if path.starts_with(&cwd) {
|
if path.starts_with(&cwd) {
|
||||||
if let Some(luaurc) = parse_luaurc(lua, &parent.join(".luaurc")).await? {
|
if let Some(luaurc) = parse_luaurc(lua, &parent.join(".luaurc")).await? {
|
||||||
if let Some(aliases) = luaurc.aliases {
|
if let Some(aliases) = luaurc.aliases {
|
||||||
if let Some(alias_path) = aliases.get(alias.alias) {
|
if let Some(alias_path) = aliases.get(&alias.alias) {
|
||||||
let resolved = path.join(alias_path.join(alias.path));
|
let resolved = path.join(alias_path.join(&alias.path));
|
||||||
|
|
||||||
return Ok(resolved);
|
return Ok(resolved);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue