Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/proc-macro-api/src/pool.rs')
-rw-r--r--crates/proc-macro-api/src/pool.rs91
1 files changed, 91 insertions, 0 deletions
diff --git a/crates/proc-macro-api/src/pool.rs b/crates/proc-macro-api/src/pool.rs
new file mode 100644
index 0000000000..a637bc0e48
--- /dev/null
+++ b/crates/proc-macro-api/src/pool.rs
@@ -0,0 +1,91 @@
+//! A pool of proc-macro server processes
+use std::sync::Arc;
+
+use crate::{
+ MacroDylib, ProcMacro, ServerError, bidirectional_protocol::SubCallback,
+ process::ProcMacroServerProcess,
+};
+
+#[derive(Debug, Clone)]
+pub(crate) struct ProcMacroServerPool {
+ workers: Arc<[ProcMacroServerProcess]>,
+ version: u32,
+}
+
+impl ProcMacroServerPool {
+ pub(crate) fn new(workers: Vec<ProcMacroServerProcess>) -> Self {
+ let version = workers[0].version();
+ Self { workers: workers.into(), version }
+ }
+}
+
+impl ProcMacroServerPool {
+ pub(crate) fn exited(&self) -> Option<&ServerError> {
+ for worker in &*self.workers {
+ worker.exited()?;
+ }
+ self.workers[0].exited()
+ }
+
+ pub(crate) fn pick_process(&self) -> Result<&ProcMacroServerProcess, ServerError> {
+ let mut best: Option<&ProcMacroServerProcess> = None;
+ let mut best_load = u32::MAX;
+
+ for w in self.workers.iter().filter(|w| w.exited().is_none()) {
+ let load = w.number_of_active_req();
+
+ if load == 0 {
+ return Ok(w);
+ }
+
+ if load < best_load {
+ best = Some(w);
+ best_load = load;
+ }
+ }
+
+ best.ok_or_else(|| ServerError {
+ message: "all proc-macro server workers have exited".into(),
+ io: None,
+ })
+ }
+
+ pub(crate) fn load_dylib(
+ &self,
+ dylib: &MacroDylib,
+ callback: Option<SubCallback<'_>>,
+ ) -> Result<Vec<ProcMacro>, ServerError> {
+ let _span = tracing::info_span!("ProcMacroServer::load_dylib").entered();
+
+ let dylib_path = Arc::new(dylib.path.clone());
+ let dylib_last_modified =
+ std::fs::metadata(dylib_path.as_path()).ok().and_then(|m| m.modified().ok());
+
+ let (first, rest) = self.workers.split_first().expect("worker pool must not be empty");
+
+ let macros = first
+ .find_proc_macros(&dylib.path, callback)?
+ .map_err(|e| ServerError { message: e, io: None })?;
+
+ for worker in rest {
+ worker
+ .find_proc_macros(&dylib.path, callback)?
+ .map_err(|e| ServerError { message: e, io: None })?;
+ }
+
+ Ok(macros
+ .into_iter()
+ .map(|(name, kind)| ProcMacro {
+ pool: self.clone(),
+ name: name.into(),
+ kind,
+ dylib_path: dylib_path.clone(),
+ dylib_last_modified,
+ })
+ .collect())
+ }
+
+ pub(crate) fn version(&self) -> u32 {
+ self.version
+ }
+}