-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Add bidirectional messaging proc-macro-srv #21249
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
Open
Shourya742
wants to merge
15
commits into
rust-lang:master
Choose a base branch
from
Shourya742:2025-11-27-bidirectional-protocol
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+903
−136
Open
Changes from 13 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
376bca9
Add bidirectional messaging proc-macro-srv
Shourya742 80705fb
remove salsa dependency check on proc_macro_srv_cli
Shourya742 178d6ce
make json-new as default protocol choice for proc-macro-srv-cli
Shourya742 28a3b80
add request id to requests
Shourya742 57fdf52
refactor the main loop in proc_macro-srv-cli
Shourya742 58f2e17
make imports proper
Shourya742 19e816d
change request id to u32 to make powerpc happy
Shourya742 f010e28
remove request_id, rename postcardNew to BidirectionalPostcardPrototy…
Shourya742 2a6cc5c
comment out disabled workflow
Shourya742 a79fa07
remove envelop and keep it simple
Shourya742 2c71fa8
rename PostcardNew to bidirectional-postcard-prototype
Shourya742 336f025
remove internal callbacks, and move callback to rust-analyzer level
Shourya742 1f64a69
remove channels with callbacks in proc-macro-srv
Shourya742 9b03499
chore: remove unwanted comments, extra lines and putting cli srv on d…
Shourya742 41dade9
return error on combination of bidirectional message and json framing
Shourya742 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,226 @@ | ||
| //! Bidirectional protocol methods | ||
|
|
||
| use std::{ | ||
| io::{self, BufRead, Write}, | ||
| sync::Arc, | ||
| }; | ||
|
|
||
| use paths::AbsPath; | ||
| use span::Span; | ||
|
|
||
| use crate::{ | ||
| Codec, ProcMacro, ProcMacroKind, ServerError, | ||
| bidirectional_protocol::msg::{ | ||
| BidirectionalMessage, ExpandMacro, ExpandMacroData, ExpnGlobals, Request, Response, | ||
| SubRequest, SubResponse, | ||
| }, | ||
| legacy_protocol::{ | ||
| SpanMode, | ||
| msg::{ | ||
| FlatTree, ServerConfig, SpanDataIndexMap, deserialize_span_data_index_map, | ||
| serialize_span_data_index_map, | ||
| }, | ||
| }, | ||
| process::ProcMacroServerProcess, | ||
| transport::codec::{json::JsonProtocol, postcard::PostcardProtocol}, | ||
| version, | ||
| }; | ||
|
|
||
| pub mod msg; | ||
|
|
||
| pub type SubCallback<'a> = &'a mut dyn FnMut(SubRequest) -> Result<SubResponse, ServerError>; | ||
|
|
||
| pub fn run_conversation<C: Codec>( | ||
| writer: &mut dyn Write, | ||
| reader: &mut dyn BufRead, | ||
| buf: &mut C::Buf, | ||
| msg: BidirectionalMessage, | ||
| callback: SubCallback<'_>, | ||
| ) -> Result<BidirectionalMessage, ServerError> { | ||
| let encoded = C::encode(&msg).map_err(wrap_encode)?; | ||
| C::write(writer, &encoded).map_err(wrap_io("failed to write initial request"))?; | ||
|
|
||
| loop { | ||
| let maybe_buf = C::read(reader, buf).map_err(wrap_io("failed to read message"))?; | ||
| let Some(b) = maybe_buf else { | ||
| return Err(ServerError { | ||
| message: "proc-macro server closed the stream".into(), | ||
| io: Some(Arc::new(io::Error::new(io::ErrorKind::UnexpectedEof, "closed"))), | ||
| }); | ||
| }; | ||
|
|
||
| let msg: BidirectionalMessage = C::decode(b).map_err(wrap_decode)?; | ||
|
|
||
| match msg { | ||
| BidirectionalMessage::Response(response) => { | ||
| return Ok(BidirectionalMessage::Response(response)); | ||
| } | ||
| BidirectionalMessage::SubRequest(sr) => { | ||
| let resp = callback(sr)?; | ||
| let reply = BidirectionalMessage::SubResponse(resp); | ||
| let encoded = C::encode(&reply).map_err(wrap_encode)?; | ||
| C::write(writer, &encoded).map_err(wrap_io("failed to write sub-response"))?; | ||
| } | ||
| _ => { | ||
| return Err(ServerError { | ||
| message: format!("unexpected message {:?}", msg), | ||
| io: None, | ||
| }); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fn wrap_io(msg: &'static str) -> impl Fn(io::Error) -> ServerError { | ||
| move |err| ServerError { message: msg.into(), io: Some(Arc::new(err)) } | ||
| } | ||
|
|
||
| fn wrap_encode(err: io::Error) -> ServerError { | ||
| ServerError { message: "failed to encode message".into(), io: Some(Arc::new(err)) } | ||
| } | ||
|
|
||
| fn wrap_decode(err: io::Error) -> ServerError { | ||
| ServerError { message: "failed to decode message".into(), io: Some(Arc::new(err)) } | ||
| } | ||
|
|
||
| pub(crate) fn version_check( | ||
| srv: &ProcMacroServerProcess, | ||
| callback: SubCallback<'_>, | ||
| ) -> Result<u32, ServerError> { | ||
| let request = BidirectionalMessage::Request(Request::ApiVersionCheck {}); | ||
|
|
||
| let response_payload = run_request(srv, request, callback)?; | ||
|
|
||
| match response_payload { | ||
| BidirectionalMessage::Response(Response::ApiVersionCheck(version)) => Ok(version), | ||
| other => { | ||
| Err(ServerError { message: format!("unexpected response: {:?}", other), io: None }) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Enable support for rust-analyzer span mode if the server supports it. | ||
| pub(crate) fn enable_rust_analyzer_spans( | ||
| srv: &ProcMacroServerProcess, | ||
| callback: SubCallback<'_>, | ||
| ) -> Result<SpanMode, ServerError> { | ||
| let request = BidirectionalMessage::Request(Request::SetConfig(ServerConfig { | ||
| span_mode: SpanMode::RustAnalyzer, | ||
| })); | ||
|
|
||
| let response_payload = run_request(srv, request, callback)?; | ||
|
|
||
| match response_payload { | ||
| BidirectionalMessage::Response(Response::SetConfig(ServerConfig { span_mode })) => { | ||
| Ok(span_mode) | ||
| } | ||
| _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), | ||
| } | ||
| } | ||
|
|
||
| /// Finds proc-macros in a given dynamic library. | ||
| pub(crate) fn find_proc_macros( | ||
| srv: &ProcMacroServerProcess, | ||
| dylib_path: &AbsPath, | ||
| callback: SubCallback<'_>, | ||
| ) -> Result<Result<Vec<(String, ProcMacroKind)>, String>, ServerError> { | ||
| let request = BidirectionalMessage::Request(Request::ListMacros { | ||
| dylib_path: dylib_path.to_path_buf().into(), | ||
| }); | ||
|
|
||
| let response_payload = run_request(srv, request, callback)?; | ||
|
|
||
| match response_payload { | ||
| BidirectionalMessage::Response(Response::ListMacros(it)) => Ok(it), | ||
| _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), | ||
| } | ||
| } | ||
|
|
||
| pub(crate) fn expand( | ||
| proc_macro: &ProcMacro, | ||
| subtree: tt::SubtreeView<'_, Span>, | ||
| attr: Option<tt::SubtreeView<'_, Span>>, | ||
| env: Vec<(String, String)>, | ||
| def_site: Span, | ||
| call_site: Span, | ||
| mixed_site: Span, | ||
| current_dir: String, | ||
| callback: SubCallback<'_>, | ||
| ) -> Result<Result<tt::TopSubtree<span::SpanData<span::SyntaxContext>>, String>, crate::ServerError> | ||
| { | ||
| let version = proc_macro.process.version(); | ||
| let mut span_data_table = SpanDataIndexMap::default(); | ||
| let def_site = span_data_table.insert_full(def_site).0; | ||
| let call_site = span_data_table.insert_full(call_site).0; | ||
| let mixed_site = span_data_table.insert_full(mixed_site).0; | ||
| let task = BidirectionalMessage::Request(Request::ExpandMacro(Box::new(ExpandMacro { | ||
| data: ExpandMacroData { | ||
| macro_body: FlatTree::from_subtree(subtree, version, &mut span_data_table), | ||
| macro_name: proc_macro.name.to_string(), | ||
| attributes: attr | ||
| .map(|subtree| FlatTree::from_subtree(subtree, version, &mut span_data_table)), | ||
| has_global_spans: ExpnGlobals { | ||
| serialize: version >= version::HAS_GLOBAL_SPANS, | ||
| def_site, | ||
| call_site, | ||
| mixed_site, | ||
| }, | ||
| span_data_table: if proc_macro.process.rust_analyzer_spans() { | ||
| serialize_span_data_index_map(&span_data_table) | ||
| } else { | ||
| Vec::new() | ||
| }, | ||
| }, | ||
| lib: proc_macro.dylib_path.to_path_buf().into(), | ||
| env, | ||
| current_dir: Some(current_dir), | ||
| }))); | ||
|
|
||
| let response_payload = run_request(&proc_macro.process, task, callback)?; | ||
|
|
||
| match response_payload { | ||
| BidirectionalMessage::Response(Response::ExpandMacro(it)) => Ok(it | ||
| .map(|tree| { | ||
| let mut expanded = FlatTree::to_subtree_resolved(tree, version, &span_data_table); | ||
| if proc_macro.needs_fixup_change() { | ||
| proc_macro.change_fixup_to_match_old_server(&mut expanded); | ||
| } | ||
| expanded | ||
| }) | ||
| .map_err(|msg| msg.0)), | ||
| BidirectionalMessage::Response(Response::ExpandMacroExtended(it)) => Ok(it | ||
| .map(|resp| { | ||
| let mut expanded = FlatTree::to_subtree_resolved( | ||
| resp.tree, | ||
| version, | ||
| &deserialize_span_data_index_map(&resp.span_data_table), | ||
| ); | ||
| if proc_macro.needs_fixup_change() { | ||
| proc_macro.change_fixup_to_match_old_server(&mut expanded); | ||
| } | ||
| expanded | ||
| }) | ||
| .map_err(|msg| msg.0)), | ||
| _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), | ||
| } | ||
| } | ||
|
|
||
| fn run_request( | ||
| srv: &ProcMacroServerProcess, | ||
| msg: BidirectionalMessage, | ||
| callback: SubCallback<'_>, | ||
| ) -> Result<BidirectionalMessage, ServerError> { | ||
| if let Some(server_error) = srv.exited() { | ||
| return Err(server_error.clone()); | ||
| } | ||
|
|
||
| if srv.use_postcard() { | ||
| srv.run_bidirectional::<PostcardProtocol>(msg, callback) | ||
| } else { | ||
| srv.run_bidirectional::<JsonProtocol>(msg, callback) | ||
Shourya742 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
|
|
||
| pub fn reject_subrequests(req: SubRequest) -> Result<SubResponse, ServerError> { | ||
| Err(ServerError { message: format!("{req:?} sub-request not supported here"), io: None }) | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.