roan_engine/module/loaders/
mod.rs

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