1use proc_macro::TokenStream;
26use proc_macro2::TokenStream as TokenStream2;
27use quote::quote;
28use std::sync::OnceLock;
29
30use bronzite_types::{
31 FieldInfo, InherentImplDetails, TraitDetails, TraitImplDetails, TraitInfo, TypeDetails,
32 TypeSummary,
33};
34
35static DAEMON_INITIALIZED: OnceLock<bool> = OnceLock::new();
37
38fn ensure_daemon() -> Result<(), String> {
40 DAEMON_INITIALIZED.get_or_init(|| {
41 match bronzite_client::ensure_daemon_running(None) {
42 Ok(()) => true,
43 Err(e) => {
44 eprintln!("[bronzite] Warning: Failed to start daemon: {}", e);
47 false
48 }
49 }
50 });
51
52 if *DAEMON_INITIALIZED.get().unwrap_or(&false) {
53 Ok(())
54 } else {
55 Err("Failed to initialize bronzite daemon".to_string())
56 }
57}
58
59fn get_client() -> Result<bronzite_client::BronziteClient, String> {
61 ensure_daemon()?;
62 bronzite_client::connect().map_err(|e| e.to_string())
63}
64
65fn query_trait_impls(crate_name: &str, type_path: &str) -> Result<Vec<TraitImplDetails>, String> {
70 let mut client = get_client()?;
71 client
72 .get_trait_impls(crate_name, type_path)
73 .map_err(|e| e.to_string())
74}
75
76fn query_inherent_impls(
77 crate_name: &str,
78 type_path: &str,
79) -> Result<Vec<InherentImplDetails>, String> {
80 let mut client = get_client()?;
81 client
82 .get_inherent_impls(crate_name, type_path)
83 .map_err(|e| e.to_string())
84}
85
86fn query_fields(crate_name: &str, type_path: &str) -> Result<Vec<FieldInfo>, String> {
87 let mut client = get_client()?;
88 client
89 .get_fields(crate_name, type_path)
90 .map_err(|e| e.to_string())
91}
92
93#[allow(dead_code)]
94fn query_type(crate_name: &str, type_path: &str) -> Result<TypeDetails, String> {
95 let mut client = get_client()?;
96 client
97 .get_type(crate_name, type_path)
98 .map_err(|e| e.to_string())
99}
100
101fn query_check_impl(
102 crate_name: &str,
103 type_path: &str,
104 trait_path: &str,
105) -> Result<(bool, Option<TraitImplDetails>), String> {
106 let mut client = get_client()?;
107 client
108 .check_impl(crate_name, type_path, trait_path)
109 .map_err(|e| e.to_string())
110}
111
112fn query_traits(crate_name: &str) -> Result<Vec<TraitInfo>, String> {
113 let mut client = get_client()?;
114 client.get_traits(crate_name).map_err(|e| e.to_string())
115}
116
117#[allow(dead_code)]
118fn query_trait(crate_name: &str, trait_path: &str) -> Result<TraitDetails, String> {
119 let mut client = get_client()?;
120 client
121 .get_trait(crate_name, trait_path)
122 .map_err(|e| e.to_string())
123}
124
125#[allow(dead_code)]
126fn query_find_types(crate_name: &str, pattern: &str) -> Result<Vec<TypeSummary>, String> {
127 let mut client = get_client()?;
128 client
129 .find_types(crate_name, pattern)
130 .map_err(|e| e.to_string())
131}
132
133fn query_resolve_alias(
134 crate_name: &str,
135 alias_path: &str,
136) -> Result<(String, String, Vec<String>), String> {
137 let mut client = get_client()?;
138 client
139 .resolve_alias(crate_name, alias_path)
140 .map_err(|e| e.to_string())
141}
142
143fn query_implementors(crate_name: &str, trait_path: &str) -> Result<Vec<TypeSummary>, String> {
144 let mut client = get_client()?;
145 client
146 .get_implementors(crate_name, trait_path)
147 .map_err(|e| e.to_string())
148}
149
150struct MacroArgs {
155 crate_name: String,
156 type_path: String,
157 trait_path: Option<String>,
158}
159
160fn parse_two_args(input: TokenStream) -> Result<MacroArgs, TokenStream2> {
161 let input_str = input.to_string();
162 let parts: Vec<&str> = input_str.split(',').map(|s| s.trim()).collect();
163
164 if parts.len() != 2 {
165 return Err(quote! {
166 compile_error!("Expected two arguments: crate_name, type_path")
167 });
168 }
169
170 let crate_name = parts[0].trim_matches('"').to_string();
171 let type_path = parts[1].trim_matches('"').to_string();
172
173 Ok(MacroArgs {
174 crate_name,
175 type_path,
176 trait_path: None,
177 })
178}
179
180fn parse_three_args(input: TokenStream) -> Result<MacroArgs, TokenStream2> {
181 let input_str = input.to_string();
182 let parts: Vec<&str> = input_str.split(',').map(|s| s.trim()).collect();
183
184 if parts.len() != 3 {
185 return Err(quote! {
186 compile_error!("Expected three arguments: crate_name, type_path, trait_path")
187 });
188 }
189
190 let crate_name = parts[0].trim_matches('"').to_string();
191 let type_path = parts[1].trim_matches('"').to_string();
192 let trait_path = parts[2].trim_matches('"').to_string();
193
194 Ok(MacroArgs {
195 crate_name,
196 type_path,
197 trait_path: Some(trait_path),
198 })
199}
200
201fn parse_one_arg(input: TokenStream) -> Result<String, TokenStream2> {
202 let input_str = input.to_string();
203 let crate_name = input_str.trim().trim_matches('"').to_string();
204
205 if crate_name.is_empty() {
206 return Err(quote! {
207 compile_error!("Expected one argument: crate_name")
208 });
209 }
210
211 Ok(crate_name)
212}
213
214#[proc_macro]
227pub fn bronzite_trait_names(input: TokenStream) -> TokenStream {
228 let args = match parse_two_args(input) {
229 Ok(a) => a,
230 Err(e) => return e.into(),
231 };
232
233 match query_trait_impls(&args.crate_name, &args.type_path) {
234 Ok(impls) => {
235 let names: Vec<String> = impls.iter().map(|i| i.trait_path.clone()).collect();
236
237 let output = quote! {
238 &[#(#names),*]
239 };
240 output.into()
241 }
242 Err(e) => {
243 let msg = format!("bronzite error: {}", e);
244 quote! { compile_error!(#msg) }.into()
245 }
246 }
247}
248
249#[proc_macro]
259pub fn bronzite_implements(input: TokenStream) -> TokenStream {
260 let args = match parse_three_args(input) {
261 Ok(a) => a,
262 Err(e) => return e.into(),
263 };
264
265 let trait_path = args.trait_path.unwrap();
266
267 match query_check_impl(&args.crate_name, &args.type_path, &trait_path) {
268 Ok((implements, _)) => {
269 let output = if implements {
270 quote! { true }
271 } else {
272 quote! { false }
273 };
274 output.into()
275 }
276 Err(e) => {
277 let msg = format!("bronzite error: {}", e);
278 quote! { compile_error!(#msg) }.into()
279 }
280 }
281}
282
283#[proc_macro]
292pub fn bronzite_field_names(input: TokenStream) -> TokenStream {
293 let args = match parse_two_args(input) {
294 Ok(a) => a,
295 Err(e) => return e.into(),
296 };
297
298 match query_fields(&args.crate_name, &args.type_path) {
299 Ok(fields) => {
300 let names: Vec<String> = fields.iter().filter_map(|f| f.name.clone()).collect();
301
302 let output = quote! {
303 &[#(#names),*]
304 };
305 output.into()
306 }
307 Err(e) => {
308 let msg = format!("bronzite error: {}", e);
309 quote! { compile_error!(#msg) }.into()
310 }
311 }
312}
313
314#[proc_macro]
323pub fn bronzite_method_names(input: TokenStream) -> TokenStream {
324 let args = match parse_two_args(input) {
325 Ok(a) => a,
326 Err(e) => return e.into(),
327 };
328
329 match query_inherent_impls(&args.crate_name, &args.type_path) {
330 Ok(impls) => {
331 let names: Vec<String> = impls
332 .iter()
333 .flat_map(|i| i.methods.iter())
334 .map(|m| m.name.clone())
335 .collect();
336
337 let output = quote! {
338 &[#(#names),*]
339 };
340 output.into()
341 }
342 Err(e) => {
343 let msg = format!("bronzite error: {}", e);
344 quote! { compile_error!(#msg) }.into()
345 }
346 }
347}
348
349#[proc_macro]
357pub fn bronzite_crate_traits(input: TokenStream) -> TokenStream {
358 let crate_name = match parse_one_arg(input) {
359 Ok(c) => c,
360 Err(e) => return e.into(),
361 };
362
363 match query_traits(&crate_name) {
364 Ok(traits) => {
365 let names: Vec<String> = traits.iter().map(|t| t.name.clone()).collect();
366
367 let output = quote! {
368 &[#(#names),*]
369 };
370 output.into()
371 }
372 Err(e) => {
373 let msg = format!("bronzite error: {}", e);
374 quote! { compile_error!(#msg) }.into()
375 }
376 }
377}
378
379#[proc_macro]
388pub fn bronzite_resolve_alias(input: TokenStream) -> TokenStream {
389 let args = match parse_two_args(input) {
390 Ok(a) => a,
391 Err(e) => return e.into(),
392 };
393
394 match query_resolve_alias(&args.crate_name, &args.type_path) {
395 Ok((_, resolved, _)) => {
396 let output = quote! { #resolved };
397 output.into()
398 }
399 Err(e) => {
400 let msg = format!("bronzite error: {}", e);
401 quote! { compile_error!(#msg) }.into()
402 }
403 }
404}
405
406#[proc_macro]
414pub fn bronzite_implementors(input: TokenStream) -> TokenStream {
415 let args = match parse_two_args(input) {
416 Ok(a) => a,
417 Err(e) => return e.into(),
418 };
419
420 match query_implementors(&args.crate_name, &args.type_path) {
421 Ok(types) => {
422 let paths: Vec<String> = types.iter().map(|t| t.path.clone()).collect();
423
424 let output = quote! {
425 &[#(#paths),*]
426 };
427 output.into()
428 }
429 Err(e) => {
430 let msg = format!("bronzite error: {}", e);
431 quote! { compile_error!(#msg) }.into()
432 }
433 }
434}