pre_proc_macro/
lib.rs

1//! This crate contains the implementation for attributes used in the `pre` crate.
2//!
3//! Refer to the documentation of the `pre` crate for more information.
4//!
5//! This crate is not designed to be used as a standalone crate and might not work, when used
6//! without the `pre` crate.
7
8#![forbid(unsafe_code)]
9
10use proc_macro::TokenStream;
11use proc_macro2::TokenStream as TokenStream2;
12use proc_macro_error::{abort_call_site, proc_macro_error};
13use quote::quote;
14use syn::{parse_macro_input, visit_mut::VisitMut, File};
15
16use crate::pre_attr::PreAttrVisitor;
17
18mod call;
19mod call_handling;
20mod documentation;
21mod extern_crate;
22mod helpers;
23mod pre_attr;
24mod precondition;
25
26cfg_if::cfg_if! {
27    if #[cfg(nightly)] {
28        mod const_generics_impl;
29        pub(crate) use crate::const_generics_impl::{render_assure, render_pre};
30    } else {
31        mod struct_impl;
32        pub(crate) use crate::struct_impl::{render_assure, render_pre};
33    }
34}
35
36#[proc_macro_attribute]
37#[proc_macro_error]
38pub fn pre(attr: TokenStream, file: TokenStream) -> TokenStream {
39    let dummy_file: TokenStream2 = file.clone().into();
40    proc_macro_error::set_dummy(quote! {
41        #dummy_file
42    });
43
44    let mut file = parse_macro_input!(file as File);
45
46    PreAttrVisitor::new(attr.into()).visit_file_mut(&mut file);
47
48    let output = quote! {
49        #file
50    };
51
52    // Reset the dummy here, in case errors were emitted while generating the code.
53    // This will use the most up-to-date version of the generated code.
54    proc_macro_error::set_dummy(quote! {
55        #output
56    });
57
58    output.into()
59}
60
61#[proc_macro_attribute]
62#[proc_macro_error]
63pub fn assure(_: TokenStream, _: TokenStream) -> TokenStream {
64    // This macro currently only has two purposes:
65    // - Exist as a place to put documentation for the actual `assure` attribute, which is
66    // implemented inside the `pre` attribute.
67    // - Emit an error with a more helpful message than "attribute not found", if the user uses
68    // `assure` in the wrong place.
69    abort_call_site!(
70        "this attribute by itself is currently non-functional";
71        help = "use it on an expression in an item wrapped by a `pre` attribute"
72    )
73}
74
75#[proc_macro_attribute]
76#[proc_macro_error]
77pub fn forward(_: TokenStream, _: TokenStream) -> TokenStream {
78    // This macro currently only has two purposes:
79    // - Exist as a place to put documentation for the actual `forward` attribute, which is
80    // implemented inside the `pre` attribute.
81    // - Emit an error with a more helpful message than "attribute not found", if the user uses
82    // `forward` in the wrong place.
83    abort_call_site!(
84        "this attribute by itself is currently non-functional";
85        help = "use it on an expression in an item wrapped by a `pre` attribute"
86    )
87}
88
89#[proc_macro_attribute]
90#[proc_macro_error]
91pub fn extern_crate(attr: TokenStream, module: TokenStream) -> TokenStream {
92    let attr = parse_macro_input!(attr as extern_crate::ExternCrateAttr);
93    let module = parse_macro_input!(module as extern_crate::Module);
94
95    let output = module.render(attr);
96
97    // Reset the dummy here, in case errors were emitted while generating the code.
98    // This will use the most up-to-date version of the generated code.
99    proc_macro_error::set_dummy(quote! {
100        #output
101    });
102
103    output.into()
104}