core_crypto_macros/
idempotent.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use crate::{compile_error, doc_attributes, items};
use proc_macro::TokenStream;

const ASYNC_ERROR_MSG: &str = "This requires access to the keystore, it has to be async";

pub(crate) fn idempotent(item: TokenStream) -> TokenStream {
    let ast = match syn::parse2::<syn::ItemFn>(item.clone().into()) {
        Ok(ast) => ast,
        Err(e) => return compile_error(item, e),
    };
    if ast.sig.asyncness.is_none() {
        return compile_error(item, syn::Error::new_spanned(ast, ASYNC_ERROR_MSG));
    }

    let doc_attributes = doc_attributes(&ast);
    let (ret, name, inputs, body, attrs, vis) = items(&ast);

    let result: proc_macro2::TokenStream = quote::quote! {
        #(#doc_attributes)*
        #(#attrs)*
        #vis async fn #name(#inputs) #ret {
            let prev_count = self.count_entities().await;

            let _result = #body;

            let next_count = self.count_entities().await;
            assert_eq!(prev_count, next_count, "'{}()' leaks entities", stringify!(#name));

            _result
        }
    };
    result.into()
}

pub(crate) fn dispotent(item: TokenStream) -> TokenStream {
    let ast = match syn::parse2::<syn::ItemFn>(item.clone().into()) {
        Ok(ast) => ast,
        Err(e) => return compile_error(item, e),
    };
    if ast.sig.asyncness.is_none() {
        return compile_error(item, syn::Error::new_spanned(ast, ASYNC_ERROR_MSG));
    }

    let doc_attributes = doc_attributes(&ast);
    let (ret, name, inputs, body, attrs, vis) = items(&ast);

    let result: proc_macro2::TokenStream = quote::quote! {
        #(#doc_attributes)*
        #(#attrs)*
        #vis async fn #name(#inputs) #ret {
            let prev_count = self.count_entities().await;

            let _result = #body;

            let next_count = self.count_entities().await;
            assert_ne!(prev_count, next_count, "'{}()' does not create entities", stringify!(#name));

            _result
        }
    };
    result.into()
}