eztry_macros/lib.rs
1use function_info::FunctionInfo;
2use proc_macro::TokenStream;
3use proc_macro2::Ident;
4use syn::{parse_macro_input, ItemFn};
5
6mod function_info;
7mod parser;
8
9/// converts a function to a struct containing the original function, and associated retry policies
10/// useful if you want to pass the arguments to a function and define the policy procedurally then execute it elsewhere
11///
12/// The return type of the original function must be of the form ```RetryResult<T, E>```,
13/// and the return type of the new function will be ```Result<T, E>``` where T and E are the types of the original function.
14///
15/// the Retryable and Abort results are of type E, and the Success result is of type T
16///
17/// if the function returns Retryable results but fails >= the number of retries on the policy, the function will return the last E as a Result<_, E>
18///
19/// if the function returns any Abort results, the function will return the first Abort result as a Result<_, E>
20///
21/// The function will return the first Success result as a Result<T, _>
22///
23/// Example:
24/// ```ignore
25///
26/// #[retry_prepare]
27/// async fn prepared_executor(agent: DemoStructWithAsync) -> RetryResult<u32, u32> {
28/// let res = agent.execute_async().await;
29/// match res {
30/// Ok(val) => Success(val.get().unwrap() as u32),
31/// Err(val) => {
32/// let v = val.get().unwrap() as u32;
33/// if v == 0 {
34/// Abort(v)
35/// } else {
36/// Retry(v)
37/// }
38/// },
39/// }
40/// }
41///
42/// async fn prepared_function() {
43/// let agent = get_async_demo_agent();
44/// let res = prepared_executor(agent).retry_with_default_policy().await;
45/// assert!(res.is_ok())
46/// }
47///
48///```
49///
50#[proc_macro_attribute]
51pub fn retry_prepare(_attr: TokenStream, item: TokenStream) -> TokenStream {
52 let original_tokens: proc_macro2::TokenStream = item.clone().into();
53 let input_fn = parse_macro_input!(item as ItemFn);
54 let retryable_data = FunctionInfo::from_function(input_fn, original_tokens);
55 let expanded = retryable_data.expand_prepared();
56 TokenStream::from(expanded)
57}
58
59/// Builds a retryable function with the given policy (or the default policy if none is provided).
60/// The function build will use the same name and arguments as the original function, and can be ```.await```ed directly
61///
62/// The return type of the original function must be of the form ```RetryResult<T, E>```,
63/// and the return type of the new function will be ```Result<T, E>``` where T and E are the types of the original function.
64///
65///
66///
67///
68/// the Retryable and Abort results are of type E, and the Success result is of type T
69///
70/// if the function returns Retryable results but fails >= the number of retries on the policy, the function will return the last E as a Result<_, E>
71///
72/// if the function returns any Abort results, the function will return the first Abort result as a Result<_, E>
73///
74/// The function will return the first Success result as a Result<T, _>
75///
76/// Example:
77/// ```ignore
78///
79/// #[retry]
80/// async fn retryable_function(agent: DemoStructWithAsync) -> RetryResult<u32, u32> {
81/// let res = agent.execute_async().await;
82/// match res {
83/// Ok(val) => Success(val.get().unwrap() as u32),
84/// Err(val) => {
85/// let v = val.get().unwrap() as u32;
86/// if v == 0 {
87/// Abort(v)
88/// } else {
89/// Retry(v)
90/// }
91/// },
92/// }
93/// }
94///
95/// async fn retry_function() {
96/// let agent = get_async_demo_agent();
97/// let res = retryable_function(agent).await;
98/// assert!(res.is_ok())
99/// }
100///
101#[proc_macro_attribute]
102pub fn retry(attr: TokenStream, item: TokenStream) -> TokenStream {
103 let policy_fn = if attr.is_empty() {
104 None
105 } else {
106 Some(parse_macro_input!(attr as Ident))
107 };
108
109 let original_tokens: proc_macro2::TokenStream = item.clone().into();
110 let input_fn = parse_macro_input!(item as ItemFn);
111
112 let retryable_data = FunctionInfo::from_function(input_fn, original_tokens);
113 let expanded = retryable_data.expand_retry(policy_fn);
114
115 TokenStream::from(expanded)
116}