proc_lock_macro/
lib.rs

1mod macro_args;
2
3use crate::macro_args::MacroArgs;
4use darling::FromMeta;
5use proc_macro::TokenStream;
6use quote::quote;
7use syn::{AttributeArgs, ItemFn};
8
9/// Wraps the annotated function with a blocking lock that is released when
10/// the function is returned.
11///
12///  _⚠ Use with caution - this macro panics on error - See `Panics` section below._
13///
14/// # Args:
15/// - `name`: The name of the lock. Can be any relative / absolute path.
16/// - `absolute`: Indicates whether the provided `name` should be created at the [`temp_dir`](std::env::temp_dir())
17/// or as an absolute path (at the root directory). Default is `false`.
18/// # Example
19/// ```rust,ignore
20///
21/// #[proc_lock(name = "my_lock.lock", absolute = false)]
22/// fn my_locked_function() {}
23/// ```
24/// # Panics
25/// This macro will panic if the underlying locking function call fails.
26#[proc_macro_attribute]
27pub fn proc_lock(args: TokenStream, input: TokenStream) -> TokenStream {
28    let options = syn::parse_macro_input!(args as AttributeArgs);
29    let function = syn::parse_macro_input!(input as ItemFn);
30
31    let MacroArgs { name, absolute } = match MacroArgs::from_list(&options) {
32        Ok(v) => v,
33        Err(e) => return TokenStream::from(e.write_errors()),
34    };
35
36    let locking_code = quote! {
37        use proc_lock::{lock, try_lock, LockPath};
38        let lock_path = if #absolute {
39            LockPath::FullPath(#name)
40        } else {
41            LockPath::Tmp(#name)
42        };
43
44        let _guard = lock(&lock_path).unwrap();
45    };
46
47    let ItemFn {
48        attrs,
49        vis,
50        sig,
51        block: body,
52    } = &function;
53
54    let result = quote! {
55        #(#attrs)*
56        #vis #sig {
57            #locking_code
58            #body
59        }
60    };
61
62    let res: proc_macro::TokenStream = result.into();
63    res
64}