Skip to main content

mira_macros/
lib.rs

1//! Procedural macros for [Mira](https://docs.rs/mira-eval).
2//!
3//! This crate is an implementation detail of `mira-eval`; use it through the
4//! re-export `mira::eval`, not directly.
5
6use proc_macro::TokenStream;
7use quote::quote;
8use syn::{ItemFn, parse_macro_input};
9
10/// Register an eval factory for `cargo test`-style discovery.
11///
12/// `#[eval]` annotates a `fn() -> Eval` (or `-> EvalBuilder`) factory. It leaves
13/// the function untouched and additionally submits it to the global registry, so
14/// [`Study::registered`] / [`registered_evals`] pick it up with no central list.
15/// It is the ergonomic form of [`register_eval!`]; these are equivalent:
16///
17/// ```ignore
18/// #[eval]
19/// fn greet() -> Eval { /* … */ }
20///
21/// // …is the same as:
22/// fn greet() -> Eval { /* … */ }
23/// register_eval!(greet);
24/// ```
25///
26/// [`Study::registered`]: ../mira/struct.Study.html#method.registered
27/// [`registered_evals`]: ../mira/fn.registered_evals.html
28/// [`register_eval!`]: ../mira/macro.register_eval.html
29#[proc_macro_attribute]
30pub fn eval(args: TokenStream, item: TokenStream) -> TokenStream {
31    if !args.is_empty() {
32        let msg = "#[eval] takes no arguments; configure the eval inside the function body \
33                   (e.g. `.targets(...)`, `.axis(...)`)";
34        let err = syn::Error::new(proc_macro2::Span::call_site(), msg);
35        return err.to_compile_error().into();
36    }
37
38    let func = parse_macro_input!(item as ItemFn);
39    let name = &func.sig.ident;
40
41    quote! {
42        #func
43        ::mira::register_eval!(#name);
44    }
45    .into()
46}