1pub mod legacy_protocol {
9 pub mod json;
10 pub mod msg;
11}
12mod process;
13
14use paths::{AbsPath, AbsPathBuf};
15use span::Span;
16use std::{fmt, io, sync::Arc};
17
18use crate::{
19 legacy_protocol::msg::{
20 deserialize_span_data_index_map, flat::serialize_span_data_index_map, ExpandMacro,
21 ExpandMacroData, ExpnGlobals, FlatTree, PanicMessage, Request, Response, SpanDataIndexMap,
22 HAS_GLOBAL_SPANS, RUST_ANALYZER_SPAN_SUPPORT,
23 },
24 process::ProcMacroServerProcess,
25};
26
27#[derive(Copy, Clone, Eq, PartialEq, Debug, serde_derive::Serialize, serde_derive::Deserialize)]
28pub enum ProcMacroKind {
29 CustomDerive,
30 Attr,
31 #[serde(alias = "Bang")]
33 #[serde(rename(serialize = "FuncLike", deserialize = "FuncLike"))]
34 Bang,
35}
36
37#[derive(Debug)]
40pub struct ProcMacroClient {
41 process: Arc<ProcMacroServerProcess>,
46 path: AbsPathBuf,
47}
48
49pub struct MacroDylib {
50 path: AbsPathBuf,
51}
52
53impl MacroDylib {
54 pub fn new(path: AbsPathBuf) -> MacroDylib {
55 MacroDylib { path }
56 }
57}
58
59#[derive(Debug, Clone)]
64pub struct ProcMacro {
65 process: Arc<ProcMacroServerProcess>,
66 dylib_path: Arc<AbsPathBuf>,
67 name: Box<str>,
68 kind: ProcMacroKind,
69}
70
71impl Eq for ProcMacro {}
72impl PartialEq for ProcMacro {
73 fn eq(&self, other: &Self) -> bool {
74 self.name == other.name
75 && self.kind == other.kind
76 && Arc::ptr_eq(&self.dylib_path, &other.dylib_path)
77 && Arc::ptr_eq(&self.process, &other.process)
78 }
79}
80
81#[derive(Clone, Debug)]
82pub struct ServerError {
83 pub message: String,
84 pub io: Option<Arc<io::Error>>,
85}
86
87impl fmt::Display for ServerError {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 self.message.fmt(f)?;
90 if let Some(io) = &self.io {
91 f.write_str(": ")?;
92 io.fmt(f)?;
93 }
94 Ok(())
95 }
96}
97
98impl ProcMacroClient {
99 pub fn spawn(
101 process_path: &AbsPath,
102 env: impl IntoIterator<Item = (impl AsRef<std::ffi::OsStr>, impl AsRef<std::ffi::OsStr>)>
103 + Clone,
104 ) -> io::Result<ProcMacroClient> {
105 let process = ProcMacroServerProcess::run(process_path, env)?;
106 Ok(ProcMacroClient { process: Arc::new(process), path: process_path.to_owned() })
107 }
108
109 pub fn server_path(&self) -> &AbsPath {
110 &self.path
111 }
112
113 pub fn load_dylib(&self, dylib: MacroDylib) -> Result<Vec<ProcMacro>, ServerError> {
115 let _p = tracing::info_span!("ProcMacroServer::load_dylib").entered();
116 let macros = self.process.find_proc_macros(&dylib.path)?;
117
118 let dylib_path = Arc::new(dylib.path);
119 match macros {
120 Ok(macros) => Ok(macros
121 .into_iter()
122 .map(|(name, kind)| ProcMacro {
123 process: self.process.clone(),
124 name: name.into(),
125 kind,
126 dylib_path: dylib_path.clone(),
127 })
128 .collect()),
129 Err(message) => Err(ServerError { message, io: None }),
130 }
131 }
132
133 pub fn exited(&self) -> Option<&ServerError> {
134 self.process.exited()
135 }
136}
137
138impl ProcMacro {
139 pub fn name(&self) -> &str {
140 &self.name
141 }
142
143 pub fn kind(&self) -> ProcMacroKind {
144 self.kind
145 }
146
147 pub fn expand(
148 &self,
149 subtree: tt::SubtreeView<'_, Span>,
150 attr: Option<tt::SubtreeView<'_, Span>>,
151 env: Vec<(String, String)>,
152 def_site: Span,
153 call_site: Span,
154 mixed_site: Span,
155 current_dir: Option<String>,
156 ) -> Result<Result<tt::TopSubtree<Span>, PanicMessage>, ServerError> {
157 let version = self.process.version();
158
159 let mut span_data_table = SpanDataIndexMap::default();
160 let def_site = span_data_table.insert_full(def_site).0;
161 let call_site = span_data_table.insert_full(call_site).0;
162 let mixed_site = span_data_table.insert_full(mixed_site).0;
163 let task = ExpandMacro {
164 data: ExpandMacroData {
165 macro_body: FlatTree::new(subtree, version, &mut span_data_table),
166 macro_name: self.name.to_string(),
167 attributes: attr
168 .map(|subtree| FlatTree::new(subtree, version, &mut span_data_table)),
169 has_global_spans: ExpnGlobals {
170 serialize: version >= HAS_GLOBAL_SPANS,
171 def_site,
172 call_site,
173 mixed_site,
174 },
175 span_data_table: if version >= RUST_ANALYZER_SPAN_SUPPORT {
176 serialize_span_data_index_map(&span_data_table)
177 } else {
178 Vec::new()
179 },
180 },
181 lib: self.dylib_path.to_path_buf().into(),
182 env,
183 current_dir,
184 };
185
186 let response = self.process.send_task(Request::ExpandMacro(Box::new(task)))?;
187
188 match response {
189 Response::ExpandMacro(it) => {
190 Ok(it.map(|tree| FlatTree::to_subtree_resolved(tree, version, &span_data_table)))
191 }
192 Response::ExpandMacroExtended(it) => Ok(it.map(|resp| {
193 FlatTree::to_subtree_resolved(
194 resp.tree,
195 version,
196 &deserialize_span_data_index_map(&resp.span_data_table),
197 )
198 })),
199 _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
200 }
201 }
202}