anodized_core/instrument/
mod.rs1use proc_macro2::TokenStream;
2use quote::{ToTokens, quote};
3use syn::{Attribute, Meta};
4
5pub mod fns;
6pub mod traits;
7
8pub struct Backend {
9 pub build_check: fn(Option<&Meta>, &TokenStream, &str, &TokenStream) -> TokenStream,
10}
11
12impl Backend {
13 pub const CHECK_AND_PANIC: Backend = Backend {
14 build_check: build_assert,
15 };
16
17 pub const CHECK_AND_PRINT: Backend = Backend {
18 build_check: build_eprint,
19 };
20
21 pub const NO_CHECK: Backend = Backend {
22 build_check: build_inert,
23 };
24}
25
26pub fn make_item_error<T: ToTokens>(tokens: &T, item_descr: &str) -> syn::Error {
28 let msg = format!(
29 r#"The #[spec] attribute doesn't yet support this item: {}.
30If this is a problem for your use case, please open a feature
31request at https://github.com/mkovaxx/anodized/issues/new"#,
32 item_descr
33 );
34 syn::Error::new_spanned(tokens, msg)
35}
36
37fn find_spec_attr(attrs: Vec<Attribute>) -> syn::Result<(Option<Attribute>, Vec<Attribute>)> {
41 let mut spec_attr = None;
42 let mut other_attrs = Vec::new();
43
44 for attr in attrs {
45 if attr.path().is_ident("spec") {
46 if spec_attr.is_some() {
47 return Err(syn::Error::new_spanned(
48 attr,
49 "multiple `#[spec]` attributes on a single item are not supported",
50 ));
51 }
52 spec_attr = Some(attr);
53 } else {
54 other_attrs.push(attr);
55 }
56 }
57
58 Ok((spec_attr, other_attrs))
59}
60
61fn build_assert(
62 cfg: Option<&Meta>,
63 expr: &TokenStream,
64 message: &str,
65 repr: &TokenStream,
66) -> TokenStream {
67 let repr_str = repr.to_string();
68 let check = quote! { assert!(#expr, #message, #repr_str); };
69 guard_check(cfg, check)
70}
71
72fn build_eprint(
73 cfg: Option<&Meta>,
74 expr: &TokenStream,
75 message: &str,
76 repr: &TokenStream,
77) -> TokenStream {
78 let repr_str = repr.to_string();
79 let check = quote! {
80 if !(#expr) {
81 eprintln!(#message, #repr_str);
82 }
83 };
84 guard_check(cfg, check)
85}
86
87fn build_inert(
88 _cfg: Option<&Meta>,
90 expr: &TokenStream,
91 message: &str,
92 repr: &TokenStream,
93) -> TokenStream {
94 let repr_str = repr.to_string();
95 quote! {
96 if false {
97 assert!(#expr, #message, #repr_str);
98 }
99 }
100}
101
102fn guard_check(cfg: Option<&Meta>, check: TokenStream) -> TokenStream {
103 if let Some(cfg) = cfg {
104 quote! { if cfg!(#cfg) { #check } }
105 } else {
106 check
107 }
108}