//! Driver for proc macro server
-use crate::{expand_task, list_macros};
+use crate::ProcMacroSrv;
use ra_proc_macro::msg::{self, Message};
use std::io;
pub fn run() -> io::Result<()> {
+ let mut srv = ProcMacroSrv::default();
+
while let Some(req) = read_request()? {
let res = match req {
- msg::Request::ListMacro(task) => Ok(msg::Response::ListMacro(list_macros(&task))),
+ msg::Request::ListMacro(task) => srv.list_macros(&task).map(msg::Response::ListMacro),
msg::Request::ExpansionMacro(task) => {
- expand_task(&task).map(msg::Response::ExpansionMacro)
+ srv.expand(&task).map(msg::Response::ExpansionMacro)
}
};
type ProcMacroLibraryImpl = ProcMacroLibraryLibloading;
pub struct Expander {
- libs: Vec<ProcMacroLibraryImpl>,
+ inner: ProcMacroLibraryImpl,
}
impl Expander {
let library = ProcMacroLibraryImpl::open(&lib).map_err(|e| e.to_string())?;
- Ok(Expander { libs: vec![library] })
+ Ok(Expander { inner: library })
}
pub fn expand(
TokenStream::with_subtree(attr.clone())
});
- for lib in &self.libs {
- for proc_macro in &lib.exported_macros {
- match proc_macro {
- bridge::client::ProcMacro::CustomDerive { trait_name, client, .. }
- if *trait_name == macro_name =>
- {
- let res = client.run(
- &crate::proc_macro::bridge::server::SameThread,
- crate::rustc_server::Rustc::default(),
- parsed_body,
- );
- return res.map(|it| it.subtree);
- }
- bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => {
- let res = client.run(
- &crate::proc_macro::bridge::server::SameThread,
- crate::rustc_server::Rustc::default(),
- parsed_body,
- );
- return res.map(|it| it.subtree);
- }
- bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => {
- let res = client.run(
- &crate::proc_macro::bridge::server::SameThread,
- crate::rustc_server::Rustc::default(),
- parsed_attributes,
- parsed_body,
- );
- return res.map(|it| it.subtree);
- }
- _ => continue,
+ for proc_macro in &self.inner.exported_macros {
+ match proc_macro {
+ bridge::client::ProcMacro::CustomDerive { trait_name, client, .. }
+ if *trait_name == macro_name =>
+ {
+ let res = client.run(
+ &crate::proc_macro::bridge::server::SameThread,
+ crate::rustc_server::Rustc::default(),
+ parsed_body,
+ );
+ return res.map(|it| it.subtree);
+ }
+ bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => {
+ let res = client.run(
+ &crate::proc_macro::bridge::server::SameThread,
+ crate::rustc_server::Rustc::default(),
+ parsed_body,
+ );
+ return res.map(|it| it.subtree);
+ }
+ bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => {
+ let res = client.run(
+ &crate::proc_macro::bridge::server::SameThread,
+ crate::rustc_server::Rustc::default(),
+ parsed_attributes,
+ parsed_body,
+ );
+ return res.map(|it| it.subtree);
}
+ _ => continue,
}
}
}
pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
- self.libs
+ self.inner
+ .exported_macros
.iter()
- .flat_map(|it| &it.exported_macros)
.map(|proc_macro| match proc_macro {
bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
(trait_name.to_string(), ProcMacroKind::CustomDerive)
use proc_macro::bridge::client::TokenStream;
use ra_proc_macro::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask};
-use std::path::Path;
-
-pub(crate) fn expand_task(task: &ExpansionTask) -> Result<ExpansionResult, String> {
- let expander = create_expander(&task.lib);
+use std::{
+ collections::{hash_map::Entry, HashMap},
+ path::{Path, PathBuf},
+};
+
+#[derive(Default)]
+pub(crate) struct ProcMacroSrv {
+ expanders: HashMap<PathBuf, dylib::Expander>,
+}
- match expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref()) {
- Ok(expansion) => Ok(ExpansionResult { expansion }),
- Err(msg) => {
- Err(format!("Cannot perform expansion for {}: error {:?}", &task.macro_name, msg))
+impl ProcMacroSrv {
+ pub fn expand(&mut self, task: &ExpansionTask) -> Result<ExpansionResult, String> {
+ let expander = self.expander(&task.lib)?;
+ match expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref()) {
+ Ok(expansion) => Ok(ExpansionResult { expansion }),
+ Err(msg) => {
+ Err(format!("Cannot perform expansion for {}: error {:?}", &task.macro_name, msg))
+ }
}
}
-}
-
-pub(crate) fn list_macros(task: &ListMacrosTask) -> ListMacrosResult {
- let expander = create_expander(&task.lib);
- ListMacrosResult { macros: expander.list_macros() }
-}
+ pub fn list_macros(&mut self, task: &ListMacrosTask) -> Result<ListMacrosResult, String> {
+ let expander = self.expander(&task.lib)?;
+ Ok(ListMacrosResult { macros: expander.list_macros() })
+ }
-fn create_expander(lib: &Path) -> dylib::Expander {
- dylib::Expander::new(lib)
- .unwrap_or_else(|err| panic!("Cannot create expander for {}: {:?}", lib.display(), err))
+ fn expander(&mut self, path: &Path) -> Result<&dylib::Expander, String> {
+ Ok(match self.expanders.entry(path.to_path_buf()) {
+ Entry::Vacant(v) => v.insert(dylib::Expander::new(path).map_err(|err| {
+ format!("Cannot create expander for {}: {:?}", path.display(), err)
+ })?),
+ Entry::Occupied(e) => e.into_mut(),
+ })
+ }
}
pub mod cli;
//! utils used in proc-macro tests
use crate::dylib;
-use crate::list_macros;
+use crate::ProcMacroSrv;
pub use difference::Changeset as __Changeset;
use ra_proc_macro::ListMacrosTask;
use std::str::FromStr;
pub fn list(crate_name: &str, version: &str) -> Vec<String> {
let path = fixtures::dylib_path(crate_name, version);
let task = ListMacrosTask { lib: path };
-
- let res = list_macros(&task);
+ let mut srv = ProcMacroSrv::default();
+ let res = srv.list_macros(&task).unwrap();
res.macros.into_iter().map(|(name, kind)| format!("{} [{:?}]", name, kind)).collect()
}