Skip to content

Commit

Permalink
Introduce procedural macro repository
Browse files Browse the repository at this point in the history
commit-id:3bccdcec
  • Loading branch information
integraledelebesgue committed Jan 29, 2025
1 parent 9ca6a9b commit 170b636
Showing 1 changed file with 64 additions and 0 deletions.
64 changes: 64 additions & 0 deletions scarb/src/compiler/plugin/proc_macro/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use itertools::Itertools;
use scarb_stable_hash::short_hash;
use smol_str::SmolStr;
use std::any::Any;
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
use std::sync::{Arc, OnceLock, RwLock};
Expand Down Expand Up @@ -1172,3 +1173,66 @@ impl ProcMacroHost {
&self.macros
}
}

/// A global storage for dynamically-loaded procedural macros.
/// Loads dynamic shared libraries and hides them beside [`ProcMacroHostPlugin`].
/// Guarantees that every library is loaded exactly once,
/// but does not prevent loading multiple versions of the same library.
#[derive(Default)]
pub struct ProcMacroRepository {
/// A mapping between the [`PackageId`] of the package which defines the plugin
/// and the [`ProcMacroHostPlugin`] holding the underlying shared library.
macros: HashMap<PackageId, Arc<ProcMacroHostPlugin>>,
}

impl ProcMacroRepository {
/// Inserts the pre-loaded [`ProcMacroInstance`] to the storage, without checking
/// whether some plugin for the [`PackageId`] already exists.
pub fn insert_prebuilt_unchecked(
&mut self,
package_id: PackageId,
instance: Arc<ProcMacroInstance>,
) -> Result<()> {
let plugin = Arc::new(ProcMacroHostPlugin::try_new(vec![instance])?);
self.macros.insert(package_id, plugin);
Ok(())
}

/// Returns the [`ProcMacroHostPlugin`] representing the procedural macros defined in the [`Package`].
/// Loads the underlying shared library if it has not been loaded yet.
pub fn get_or_load(
&mut self,
package: Package,
config: &Config,
) -> Result<Arc<ProcMacroHostPlugin>> {
match self.macros.entry(package.id) {
Entry::Occupied(slot) => Ok(slot.get().clone()),
Entry::Vacant(slot) => {
let lib_path = package
.shared_lib_path(config)
.context("could not resolve shared library path")?;

let instance = Arc::new(ProcMacroInstance::try_new(package.id, lib_path)?);
let plugin = Arc::new(ProcMacroHostPlugin::try_new(vec![instance])?);

slot.insert(plugin.clone());
Ok(plugin)
}
}
}

/// Returns the [`ProcMacroHostPlugin`] corresponding to the given [`PackageId`] if it exists.
pub fn get(&self, package_id: &PackageId) -> Option<Arc<ProcMacroHostPlugin>> {
self.macros.get(package_id).cloned()
}

/// Drops the [`ProcMacroRepository`], invoking the necessary
/// [`ProcMacroHostPlugin::post_process`] on each stored proc macro.
pub fn safe_drop(self, db: &dyn SemanticGroup) -> Result<()> {
for plugin in self.macros.values() {
plugin.post_process(db)?;
}

Ok(())
}
}

0 comments on commit 170b636

Please sign in to comment.