diff options
Diffstat (limited to 'crates/ra_proc_macro_srv/src/lib.rs')
-rw-r--r-- | crates/ra_proc_macro_srv/src/lib.rs | 48 |
1 files changed, 33 insertions, 15 deletions
diff --git a/crates/ra_proc_macro_srv/src/lib.rs b/crates/ra_proc_macro_srv/src/lib.rs index 3aca859db..922bb84bb 100644 --- a/crates/ra_proc_macro_srv/src/lib.rs +++ b/crates/ra_proc_macro_srv/src/lib.rs | |||
@@ -21,28 +21,46 @@ mod dylib; | |||
21 | 21 | ||
22 | use proc_macro::bridge::client::TokenStream; | 22 | use proc_macro::bridge::client::TokenStream; |
23 | use ra_proc_macro::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask}; | 23 | use ra_proc_macro::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask}; |
24 | use std::path::Path; | 24 | use std::{ |
25 | collections::{hash_map::Entry, HashMap}, | ||
26 | fs, | ||
27 | path::{Path, PathBuf}, | ||
28 | time::SystemTime, | ||
29 | }; | ||
25 | 30 | ||
26 | pub(crate) fn expand_task(task: &ExpansionTask) -> Result<ExpansionResult, String> { | 31 | #[derive(Default)] |
27 | let expander = create_expander(&task.lib); | 32 | pub(crate) struct ProcMacroSrv { |
33 | expanders: HashMap<(PathBuf, SystemTime), dylib::Expander>, | ||
34 | } | ||
28 | 35 | ||
29 | match expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref()) { | 36 | impl ProcMacroSrv { |
30 | Ok(expansion) => Ok(ExpansionResult { expansion }), | 37 | pub fn expand(&mut self, task: &ExpansionTask) -> Result<ExpansionResult, String> { |
31 | Err(msg) => { | 38 | let expander = self.expander(&task.lib)?; |
32 | Err(format!("Cannot perform expansion for {}: error {:?}", &task.macro_name, msg)) | 39 | match expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref()) { |
40 | Ok(expansion) => Ok(ExpansionResult { expansion }), | ||
41 | Err(msg) => { | ||
42 | Err(format!("Cannot perform expansion for {}: error {:?}", &task.macro_name, msg)) | ||
43 | } | ||
33 | } | 44 | } |
34 | } | 45 | } |
35 | } | ||
36 | 46 | ||
37 | pub(crate) fn list_macros(task: &ListMacrosTask) -> ListMacrosResult { | 47 | pub fn list_macros(&mut self, task: &ListMacrosTask) -> Result<ListMacrosResult, String> { |
38 | let expander = create_expander(&task.lib); | 48 | let expander = self.expander(&task.lib)?; |
49 | Ok(ListMacrosResult { macros: expander.list_macros() }) | ||
50 | } | ||
39 | 51 | ||
40 | ListMacrosResult { macros: expander.list_macros() } | 52 | fn expander(&mut self, path: &Path) -> Result<&dylib::Expander, String> { |
41 | } | 53 | let time = fs::metadata(path).and_then(|it| it.modified()).map_err(|err| { |
54 | format!("Failed to get file metadata for {}: {:?}", path.display(), err) | ||
55 | })?; | ||
42 | 56 | ||
43 | fn create_expander(lib: &Path) -> dylib::Expander { | 57 | Ok(match self.expanders.entry((path.to_path_buf(), time)) { |
44 | dylib::Expander::new(lib) | 58 | Entry::Vacant(v) => v.insert(dylib::Expander::new(path).map_err(|err| { |
45 | .unwrap_or_else(|err| panic!("Cannot create expander for {}: {:?}", lib.display(), err)) | 59 | format!("Cannot create expander for {}: {:?}", path.display(), err) |
60 | })?), | ||
61 | Entry::Occupied(e) => e.into_mut(), | ||
62 | }) | ||
63 | } | ||
46 | } | 64 | } |
47 | 65 | ||
48 | pub mod cli; | 66 | pub mod cli; |