Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/proc-macro-api/src/lib.rs')
-rw-r--r--crates/proc-macro-api/src/lib.rs99
1 files changed, 68 insertions, 31 deletions
diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs
index f5fcc99f14..e4b121b033 100644
--- a/crates/proc-macro-api/src/lib.rs
+++ b/crates/proc-macro-api/src/lib.rs
@@ -18,7 +18,8 @@ extern crate rustc_driver as _;
pub mod bidirectional_protocol;
pub mod legacy_protocol;
-mod process;
+pub mod pool;
+pub mod process;
pub mod transport;
use paths::{AbsPath, AbsPathBuf};
@@ -26,8 +27,9 @@ use semver::Version;
use span::{ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, Span};
use std::{fmt, io, sync::Arc, time::SystemTime};
-pub use crate::transport::codec::Codec;
-use crate::{bidirectional_protocol::SubCallback, process::ProcMacroServerProcess};
+use crate::{
+ bidirectional_protocol::SubCallback, pool::ProcMacroServerPool, process::ProcMacroServerProcess,
+};
/// The versions of the server protocol
pub mod version {
@@ -44,6 +46,26 @@ pub mod version {
pub const CURRENT_API_VERSION: u32 = HASHED_AST_ID;
}
+/// Protocol format for communication between client and server.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum ProtocolFormat {
+ /// JSON-based legacy protocol (newline-delimited JSON).
+ JsonLegacy,
+ /// Bidirectional postcard protocol with sub-request support.
+ BidirectionalPostcardPrototype,
+}
+
+impl fmt::Display for ProtocolFormat {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ ProtocolFormat::JsonLegacy => write!(f, "json-legacy"),
+ ProtocolFormat::BidirectionalPostcardPrototype => {
+ write!(f, "bidirectional-postcard-prototype")
+ }
+ }
+ }
+}
+
/// Represents different kinds of procedural macros that can be expanded by the external server.
#[derive(Copy, Clone, Eq, PartialEq, Debug, serde_derive::Serialize, serde_derive::Deserialize)]
pub enum ProcMacroKind {
@@ -65,7 +87,7 @@ pub struct ProcMacroClient {
///
/// That means that concurrent salsa requests may block each other when expanding proc macros,
/// which is unfortunate, but simple and good enough for the time being.
- process: Arc<ProcMacroServerProcess>,
+ pool: Arc<ProcMacroServerPool>,
path: AbsPathBuf,
}
@@ -87,7 +109,7 @@ impl MacroDylib {
/// we share a single expander process for all macros within a workspace.
#[derive(Debug, Clone)]
pub struct ProcMacro {
- process: Arc<ProcMacroServerProcess>,
+ pool: ProcMacroServerPool,
dylib_path: Arc<AbsPathBuf>,
name: Box<str>,
kind: ProcMacroKind,
@@ -101,7 +123,6 @@ impl PartialEq for ProcMacro {
&& self.kind == other.kind
&& self.dylib_path == other.dylib_path
&& self.dylib_last_modified == other.dylib_last_modified
- && Arc::ptr_eq(&self.process, &other.process)
}
}
@@ -131,9 +152,44 @@ impl ProcMacroClient {
Item = (impl AsRef<std::ffi::OsStr>, &'a Option<impl 'a + AsRef<std::ffi::OsStr>>),
> + Clone,
version: Option<&Version>,
+ num_process: usize,
) -> io::Result<ProcMacroClient> {
- let process = ProcMacroServerProcess::run(process_path, env, version)?;
- Ok(ProcMacroClient { process: Arc::new(process), path: process_path.to_owned() })
+ let pool_size = num_process;
+ let mut workers = Vec::with_capacity(pool_size);
+ for _ in 0..pool_size {
+ let worker = ProcMacroServerProcess::spawn(process_path, env.clone(), version)?;
+ workers.push(worker);
+ }
+
+ let pool = ProcMacroServerPool::new(workers);
+ Ok(ProcMacroClient { pool: Arc::new(pool), path: process_path.to_owned() })
+ }
+
+ /// Invokes `spawn` and returns a client connected to the resulting read and write handles.
+ ///
+ /// The `process_path` is used for `Self::server_path`. This function is mainly used for testing.
+ pub fn with_io_channels(
+ process_path: &AbsPath,
+ spawn: impl Fn(
+ Option<ProtocolFormat>,
+ ) -> io::Result<(
+ Box<dyn process::ProcessExit>,
+ Box<dyn io::Write + Send + Sync>,
+ Box<dyn io::BufRead + Send + Sync>,
+ )> + Clone,
+ version: Option<&Version>,
+ num_process: usize,
+ ) -> io::Result<ProcMacroClient> {
+ let pool_size = num_process;
+ let mut workers = Vec::with_capacity(pool_size);
+ for _ in 0..pool_size {
+ let worker =
+ ProcMacroServerProcess::run(spawn.clone(), version, || "<unknown>".to_owned())?;
+ workers.push(worker);
+ }
+
+ let pool = ProcMacroServerPool::new(workers);
+ Ok(ProcMacroClient { pool: Arc::new(pool), path: process_path.to_owned() })
}
/// Returns the absolute path to the proc-macro server.
@@ -147,31 +203,12 @@ impl ProcMacroClient {
dylib: MacroDylib,
callback: Option<SubCallback<'_>>,
) -> Result<Vec<ProcMacro>, ServerError> {
- let _p = tracing::info_span!("ProcMacroServer::load_dylib").entered();
- let macros = self.process.find_proc_macros(&dylib.path, callback)?;
-
- let dylib_path = Arc::new(dylib.path);
- let dylib_last_modified = std::fs::metadata(dylib_path.as_path())
- .ok()
- .and_then(|metadata| metadata.modified().ok());
- match macros {
- Ok(macros) => Ok(macros
- .into_iter()
- .map(|(name, kind)| ProcMacro {
- process: self.process.clone(),
- name: name.into(),
- kind,
- dylib_path: dylib_path.clone(),
- dylib_last_modified,
- })
- .collect()),
- Err(message) => Err(ServerError { message, io: None }),
- }
+ self.pool.load_dylib(&dylib, callback)
}
/// Checks if the proc-macro server has exited.
pub fn exited(&self) -> Option<&ServerError> {
- self.process.exited()
+ self.pool.exited()
}
}
@@ -187,7 +224,7 @@ impl ProcMacro {
}
fn needs_fixup_change(&self) -> bool {
- let version = self.process.version();
+ let version = self.pool.version();
(version::RUST_ANALYZER_SPAN_SUPPORT..version::HASHED_AST_ID).contains(&version)
}
@@ -231,7 +268,7 @@ impl ProcMacro {
}
}
- self.process.expand(
+ self.pool.pick_process()?.expand(
self,
subtree,
attr,