aboutsummaryrefslogtreecommitdiff
path: root/crates/proc_macro_api/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/proc_macro_api/src/lib.rs')
-rw-r--r--crates/proc_macro_api/src/lib.rs111
1 files changed, 111 insertions, 0 deletions
diff --git a/crates/proc_macro_api/src/lib.rs b/crates/proc_macro_api/src/lib.rs
new file mode 100644
index 000000000..15db57eb2
--- /dev/null
+++ b/crates/proc_macro_api/src/lib.rs
@@ -0,0 +1,111 @@
1//! Client-side Proc-Macro crate
2//!
3//! We separate proc-macro expanding logic to an extern program to allow
4//! different implementations (e.g. wasm or dylib loading). And this crate
5//! is used to provide basic infrastructure for communication between two
6//! processes: Client (RA itself), Server (the external program)
7
8mod rpc;
9mod process;
10pub mod msg;
11
12use std::{
13 ffi::OsStr,
14 io,
15 path::{Path, PathBuf},
16 sync::Arc,
17};
18
19use tt::{SmolStr, Subtree};
20
21use crate::process::{ProcMacroProcessSrv, ProcMacroProcessThread};
22
23pub use rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind};
24
25#[derive(Debug, Clone)]
26pub struct ProcMacroProcessExpander {
27 process: Arc<ProcMacroProcessSrv>,
28 dylib_path: PathBuf,
29 name: SmolStr,
30}
31
32impl Eq for ProcMacroProcessExpander {}
33impl PartialEq for ProcMacroProcessExpander {
34 fn eq(&self, other: &Self) -> bool {
35 self.name == other.name
36 && self.dylib_path == other.dylib_path
37 && Arc::ptr_eq(&self.process, &other.process)
38 }
39}
40
41impl tt::TokenExpander for ProcMacroProcessExpander {
42 fn expand(
43 &self,
44 subtree: &Subtree,
45 _attr: Option<&Subtree>,
46 ) -> Result<Subtree, tt::ExpansionError> {
47 self.process.custom_derive(&self.dylib_path, subtree, &self.name)
48 }
49}
50
51#[derive(Debug)]
52enum ProcMacroClientKind {
53 Process { process: Arc<ProcMacroProcessSrv>, thread: ProcMacroProcessThread },
54 Dummy,
55}
56
57#[derive(Debug)]
58pub struct ProcMacroClient {
59 kind: ProcMacroClientKind,
60}
61
62impl ProcMacroClient {
63 pub fn extern_process(
64 process_path: PathBuf,
65 args: impl IntoIterator<Item = impl AsRef<OsStr>>,
66 ) -> io::Result<ProcMacroClient> {
67 let (thread, process) = ProcMacroProcessSrv::run(process_path, args)?;
68 Ok(ProcMacroClient {
69 kind: ProcMacroClientKind::Process { process: Arc::new(process), thread },
70 })
71 }
72
73 pub fn dummy() -> ProcMacroClient {
74 ProcMacroClient { kind: ProcMacroClientKind::Dummy }
75 }
76
77 pub fn by_dylib_path(&self, dylib_path: &Path) -> Vec<(SmolStr, Arc<dyn tt::TokenExpander>)> {
78 match &self.kind {
79 ProcMacroClientKind::Dummy => vec![],
80 ProcMacroClientKind::Process { process, .. } => {
81 let macros = match process.find_proc_macros(dylib_path) {
82 Err(err) => {
83 eprintln!("Failed to find proc macros. Error: {:#?}", err);
84 return vec![];
85 }
86 Ok(macros) => macros,
87 };
88
89 macros
90 .into_iter()
91 .filter_map(|(name, kind)| {
92 // FIXME: Support custom derive only for now.
93 match kind {
94 ProcMacroKind::CustomDerive => {
95 let name = SmolStr::new(&name);
96 let expander: Arc<dyn tt::TokenExpander> =
97 Arc::new(ProcMacroProcessExpander {
98 process: process.clone(),
99 name: name.clone(),
100 dylib_path: dylib_path.into(),
101 });
102 Some((name, expander))
103 }
104 _ => None,
105 }
106 })
107 .collect()
108 }
109 }
110 }
111}