Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: add doc to proc-macro-api #19329

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/proc-macro-api/src/legacy_protocol/json.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Protocol functions for json.
use std::io::{self, BufRead, Write};

/// Reads a JSON message from the input stream.
pub fn read_json<'a>(
inp: &mut impl BufRead,
buf: &'a mut String,
Expand All @@ -26,6 +27,7 @@ pub fn read_json<'a>(
}
}

/// Writes a JSON message to the output stream.
pub fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> {
tracing::debug!("> {}", msg);
out.write_all(msg.as_bytes())?;
Expand Down
44 changes: 43 additions & 1 deletion crates/proc-macro-api/src/legacy_protocol/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,69 +20,103 @@ pub const VERSION_CHECK_VERSION: u32 = 1;
pub const ENCODE_CLOSE_SPAN_VERSION: u32 = 2;
pub const HAS_GLOBAL_SPANS: u32 = 3;
pub const RUST_ANALYZER_SPAN_SUPPORT: u32 = 4;
/// Whether literals encode their kind as an additional u32 field and idents their rawness as a u32 field
/// Whether literals encode their kind as an additional u32 field and idents their rawness as a u32 field.
pub const EXTENDED_LEAF_DATA: u32 = 5;

/// Current API version of the proc-macro protocol.
pub const CURRENT_API_VERSION: u32 = EXTENDED_LEAF_DATA;

/// Represents requests sent from the client to the proc-macro-srv.
#[derive(Debug, Serialize, Deserialize)]
pub enum Request {
/// Retrieves a list of macros from a given dynamic library.
/// Since [`NO_VERSION_CHECK_VERSION`]
ListMacros { dylib_path: Utf8PathBuf },

/// Expands a procedural macro.
/// Since [`NO_VERSION_CHECK_VERSION`]
ExpandMacro(Box<ExpandMacro>),

/// Performs an API version check between the client and the server.
/// Since [`VERSION_CHECK_VERSION`]
ApiVersionCheck {},

/// Sets server-specific configurations.
/// Since [`RUST_ANALYZER_SPAN_SUPPORT`]
SetConfig(ServerConfig),
}

/// Defines the mode used for handling span data.
#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)]
pub enum SpanMode {
/// Default mode, where spans are identified by an ID.
#[default]
Id,

/// Rust Analyzer-specific span handling mode.
RustAnalyzer,
}

/// Represents responses sent from the proc-macro-srv to the client.
#[derive(Debug, Serialize, Deserialize)]
pub enum Response {
/// Returns a list of available macros in a dynamic library.
/// Since [`NO_VERSION_CHECK_VERSION`]
ListMacros(Result<Vec<(String, ProcMacroKind)>, String>),

/// Returns result of a macro expansion.
/// Since [`NO_VERSION_CHECK_VERSION`]
ExpandMacro(Result<FlatTree, PanicMessage>),

/// Returns the API version supported by the server.
/// Since [`NO_VERSION_CHECK_VERSION`]
ApiVersionCheck(u32),

/// Confirms the application of a configuration update.
/// Since [`RUST_ANALYZER_SPAN_SUPPORT`]
SetConfig(ServerConfig),

/// Returns the result of a macro expansion, including extended span data.
/// Since [`RUST_ANALYZER_SPAN_SUPPORT`]
ExpandMacroExtended(Result<ExpandMacroExtended, PanicMessage>),
}

/// Configuration settings for the proc-macro-srv.
#[derive(Debug, Serialize, Deserialize, Default)]
#[serde(default)]
pub struct ServerConfig {
/// Defines how span data should be handled.
pub span_mode: SpanMode,
}

/// Represents an extended macro expansion response, including span data mappings.
#[derive(Debug, Serialize, Deserialize)]
pub struct ExpandMacroExtended {
/// The expanded syntax tree.
pub tree: FlatTree,
/// Additional span data mappings.
pub span_data_table: Vec<u32>,
}

/// Represents an error message when a macro expansion results in a panic.
#[derive(Debug, Serialize, Deserialize)]
pub struct PanicMessage(pub String);

/// Represents a macro expansion request sent from the client.
#[derive(Debug, Serialize, Deserialize)]
pub struct ExpandMacro {
/// The path to the dynamic library containing the macro.
pub lib: Utf8PathBuf,
/// Environment variables to set during macro expansion.
pub env: Vec<(String, String)>,
/// The current working directory for the macro expansion.
pub current_dir: Option<String>,
/// Macro expansion data, including the macro body, name and attributes.
#[serde(flatten)]
pub data: ExpandMacroData,
}

/// Represents the input data required for expanding a macro.
#[derive(Debug, Serialize, Deserialize)]
pub struct ExpandMacroData {
/// Argument of macro call.
Expand All @@ -103,18 +137,24 @@ pub struct ExpandMacroData {
#[serde(skip_serializing_if = "ExpnGlobals::skip_serializing_if")]
#[serde(default)]
pub has_global_spans: ExpnGlobals,
/// Table of additional span data.
#[serde(skip_serializing_if = "Vec::is_empty")]
#[serde(default)]
pub span_data_table: Vec<u32>,
}

/// Represents global expansion settings, including span resolution.
#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)]
pub struct ExpnGlobals {
/// Determines whether to serialize the expansion settings.
#[serde(skip_serializing)]
#[serde(default)]
pub serialize: bool,
/// Defines the `def_site` span location.
pub def_site: usize,
/// Defines the `call_site` span location.
pub call_site: usize,
/// Defines the `mixed_site` span location.
pub mixed_site: usize,
}

Expand Down Expand Up @@ -150,9 +190,11 @@ pub trait Message: serde::Serialize + DeserializeOwned {
impl Message for Request {}
impl Message for Response {}

/// Type alias for a function that reads protocol messages from a buffered input stream.
#[allow(type_alias_bounds)]
type ProtocolRead<R: BufRead> =
for<'i, 'buf> fn(inp: &'i mut R, buf: &'buf mut String) -> io::Result<Option<&'buf String>>;
/// Type alias for a function that writes protocol messages to an output stream.
#[allow(type_alias_bounds)]
type ProtocolWrite<W: Write> = for<'o, 'msg> fn(out: &'o mut W, msg: &'msg str) -> io::Result<()>;

Expand Down
12 changes: 12 additions & 0 deletions crates/proc-macro-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ use crate::{
process::ProcMacroServerProcess,
};

/// 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 {
/// A macro that derives implementations for a struct or enum.
CustomDerive,
/// An attribute-like procedural macro.
Attr,
// This used to be called FuncLike, so that's what the server expects currently.
#[serde(alias = "Bang")]
Expand All @@ -46,11 +49,13 @@ pub struct ProcMacroClient {
path: AbsPathBuf,
}

/// Represents a dynamically loaded library containing procedural macros.
pub struct MacroDylib {
path: AbsPathBuf,
}

impl MacroDylib {
/// Creates a new MacroDylib instance with the given path.
pub fn new(path: AbsPathBuf) -> MacroDylib {
MacroDylib { path }
}
Expand Down Expand Up @@ -78,6 +83,7 @@ impl PartialEq for ProcMacro {
}
}

/// Represents errors encountered when communicating with the proc-macro server.
#[derive(Clone, Debug)]
pub struct ServerError {
pub message: String,
Expand Down Expand Up @@ -106,6 +112,7 @@ impl ProcMacroClient {
Ok(ProcMacroClient { process: Arc::new(process), path: process_path.to_owned() })
}

/// Returns the absolute path to the proc-macro server.
pub fn server_path(&self) -> &AbsPath {
&self.path
}
Expand All @@ -130,20 +137,25 @@ impl ProcMacroClient {
}
}

/// Checks if the proc-macro server has exited.
pub fn exited(&self) -> Option<&ServerError> {
self.process.exited()
}
}

impl ProcMacro {
/// Returns the name of the procedural macro.
pub fn name(&self) -> &str {
&self.name
}

/// Returns the type of procedural macro.
pub fn kind(&self) -> ProcMacroKind {
self.kind
}

/// Expands the procedural macro by sending an expansion request to the server.
/// This includes span information and environmental context.
pub fn expand(
&self,
subtree: tt::SubtreeView<'_, Span>,
Expand Down
14 changes: 14 additions & 0 deletions crates/proc-macro-api/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::{
ProcMacroKind, ServerError,
};

/// Represents a process handling proc-macro communication.
#[derive(Debug)]
pub(crate) struct ProcMacroServerProcess {
/// The state of the proc-macro server process, the protocol is currently strictly sequential
Expand All @@ -32,6 +33,7 @@ pub(crate) struct ProcMacroServerProcess {
exited: OnceLock<AssertUnwindSafe<ServerError>>,
}

/// Maintains the state of the proc-macro server process.
#[derive(Debug)]
struct ProcessSrvState {
process: Process,
Expand All @@ -40,6 +42,7 @@ struct ProcessSrvState {
}

impl ProcMacroServerProcess {
/// Starts the proc-macro server and performs a version check
pub(crate) fn run(
process_path: &AbsPath,
env: impl IntoIterator<Item = (impl AsRef<std::ffi::OsStr>, impl AsRef<std::ffi::OsStr>)>
Expand Down Expand Up @@ -85,14 +88,17 @@ impl ProcMacroServerProcess {
}
}

/// Returns the server error if the process has exited.
pub(crate) fn exited(&self) -> Option<&ServerError> {
self.exited.get().map(|it| &it.0)
}

/// Retrieves the API version of the proc-macro server.
pub(crate) fn version(&self) -> u32 {
self.version
}

/// Checks the API version of the running proc-macro server.
fn version_check(&self) -> Result<u32, ServerError> {
let request = Request::ApiVersionCheck {};
let response = self.send_task(request)?;
Expand All @@ -103,6 +109,7 @@ impl ProcMacroServerProcess {
}
}

/// Enable support for rust-analyzer span mode if the server supports it.
fn enable_rust_analyzer_spans(&self) -> Result<SpanMode, ServerError> {
let request = Request::SetConfig(ServerConfig { span_mode: SpanMode::RustAnalyzer });
let response = self.send_task(request)?;
Expand All @@ -113,6 +120,7 @@ impl ProcMacroServerProcess {
}
}

/// Finds proc-macros in a given dynamic library.
pub(crate) fn find_proc_macros(
&self,
dylib_path: &AbsPath,
Expand All @@ -127,6 +135,7 @@ impl ProcMacroServerProcess {
}
}

/// Sends a request to the proc-macro server and waits for a response.
pub(crate) fn send_task(&self, req: Request) -> Result<Response, ServerError> {
if let Some(server_error) = self.exited.get() {
return Err(server_error.0.clone());
Expand Down Expand Up @@ -177,12 +186,14 @@ impl ProcMacroServerProcess {
}
}

/// Manages the execution of the proc-macro server process.
#[derive(Debug)]
struct Process {
child: JodChild,
}

impl Process {
/// Runs a new proc-macro server process with the specified environment variables.
fn run(
path: &AbsPath,
env: impl IntoIterator<Item = (impl AsRef<std::ffi::OsStr>, impl AsRef<std::ffi::OsStr>)>,
Expand All @@ -191,6 +202,7 @@ impl Process {
Ok(Process { child })
}

/// Retrieves stdin and stdout handles for the process.
fn stdio(&mut self) -> Option<(ChildStdin, BufReader<ChildStdout>)> {
let stdin = self.child.stdin.take()?;
let stdout = self.child.stdout.take()?;
Expand All @@ -200,6 +212,7 @@ impl Process {
}
}

/// Creates and configures a new child process for the proc-macro server.
fn mk_child(
path: &AbsPath,
env: impl IntoIterator<Item = (impl AsRef<std::ffi::OsStr>, impl AsRef<std::ffi::OsStr>)>,
Expand All @@ -221,6 +234,7 @@ fn mk_child(
cmd.spawn()
}

/// Sends a request to the server and reads the response.
fn send_request(
mut writer: &mut impl Write,
mut reader: &mut impl BufRead,
Expand Down