roan_engine/module/loaders/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
use crate::{
context::Context,
module::{loaders::ident::ModuleIdentifier, Module},
};
use std::{fmt::Debug, path::PathBuf};
use tracing::debug;
pub mod ident;
/// Trait that defines the interface for a module loader.
pub trait ModuleLoader: Debug {
/// Load a module from a given source.
fn load(&mut self, referrer: &Module, spec: &str, ctx: &Context) -> anyhow::Result<Module>;
/// Insert a module into the loader's cache if loader handles caching.
///
/// This function is a no-op for loaders that do not cache modules.
///
/// # Arguments
/// - `name` - The name of the module to insert into the cache.
/// - `module` - The module to insert into the cache.
fn insert(&mut self, name: String, module: Module) {}
/// Get a module from the cache if the loader caches modules.
///
/// This function returns `None` for loaders that do not cache modules.
///
/// # Arguments
/// - `name` - The name of the module to get from the cache.
fn get(&self, name: &str) -> Option<Module> {
None
}
/// Returns all the keys in the cache.
///
/// This function returns an empty vector for loaders that do not cache modules.
///
/// # Returns
/// A vector of strings representing the keys in the cache.
fn keys(&self) -> Vec<String> {
Vec::new()
}
/// Resolves the path of a referenced module based on the referrer module's path and the provided specification.
///
/// # Arguments
///
/// * `referrer` - A reference to the `Module` that provides the context for resolving the path.
/// * `spec` - A string slice that represents the specification of the path to resolve.
///
/// # Returns
///
/// A `Result<PathBuf>`, where the `Ok` variant contains the resolved path, and the `Err` variant
/// contains an error if the operation fails (e.g., if the `referrer` path has no parent).
///
/// # Panics
///
/// This function will panic if the `referrer` module's path has no parent directory.
fn resolve_referrer(&self, referrer: &Module, spec: &str) -> anyhow::Result<PathBuf> {
debug!("Resolving referrer: {:?}, spec: {}", referrer.path(), spec);
let referrer_path = referrer
.path()
.map_or_else(|| PathBuf::new(), |p| p.to_path_buf());
let dir = referrer_path.parent().expect("Module path has no parent");
let spec = if cfg!(windows) {
spec.replace("/", "\\")
} else {
spec.to_string()
};
let str_path = remove_surrounding_quotes(&spec);
let spec_path = PathBuf::from(str_path);
let path = if spec_path.is_absolute() {
spec_path
} else {
dir.join(spec_path)
};
debug!("Resolved path: {:?}", path);
Ok(path)
}
}
/// Removes surrounding double quotes from a string slice if present.
pub fn remove_surrounding_quotes(s: &str) -> &str {
if s.starts_with('"') && s.ends_with('"') && s.len() >= 2 {
&s[1..s.len() - 1]
} else {
s
}
}