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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! `bisync_suffix_macro` provides a procedural macro to conditionally append suffixes to method names
//! in `.await` expressions, enabling dual support for asynchronous and blocking code paths.
//!
//! This macro is designed to work seamlessly with the `bisync` crate, which allows functions to support
//! both async and blocking execution models based on feature flags. It is particularly useful in libraries
//! like `axp192-dd`, where a single codebase needs to provide both async and blocking APIs.
//!
//! For detailed usage, see the [`suffix`] macro documentation.
use TokenStream;
use quote;
use ;
/// A procedural macro to conditionally append a suffix to method names in `.await` expressions.
///
/// The `suffix` macro is designed to work in conjunction with the `#[bisync]` attribute from the `bisync` crate,
/// enabling functions to support both asynchronous and blocking execution models based on feature flags.
///
/// When used within a function annotated with `#[bisync]`, the `suffix` macro ensures that method calls
/// in `.await` expressions are adapted to the correct execution model:
///
/// - With the `async` feature enabled, it appends the specified suffix (e.g., `"_async"`) to method names in `.await` calls,
/// ensuring the async version of the method is invoked.
/// - With the `blocking` feature enabled (and `async` disabled), the original method name is preserved without the suffix,
/// and the `#[bisync]` attribute removes the `.await` from the expression, transforming the function into a synchronous
/// version that calls the blocking method directly.
///
/// # Usage with `bisync`
///
/// Below is an example from the `axp192-dd` library:
///
/// ```ignore
/// #[bisync]
/// pub async fn get_battery_charge_current_ma(&mut self) -> Result<f32, AxpError<I2CBusErr>> {
/// let raw_fieldset = suffix!("_async", self.ll.battery_charge_current_adc().read().await?);
/// let adc_val = adc_13bit_from_raw_u16(raw_fieldset.raw());
/// Ok(adc_val as f32 * 0.5)
/// }
/// ```
///
/// In this scenario:
/// - **Async Context**: When the `async` feature is enabled, the `suffix` macro transforms the expression to
/// `self.ll.battery_charge_current_adc().read_async().await?`, calling the asynchronous `read_async` method.
/// - **Blocking Context**: When the `blocking` feature is enabled (and `async` disabled), the `suffix` macro leaves the
/// method name as `read` (no suffix is appended), and the `#[bisync]` attribute removes the `.await`, resulting in
/// `self.ll.battery_charge_current_adc().read()?`. Here, `read` is expected to be a blocking method provided by the
/// underlying implementation.
///
/// # Notes
///
/// - **Arguments**: The macro requires a string literal suffix (e.g., `"_async"`) and a valid Rust expression.
/// - **Feature Flags**: Ensure that `async` and `blocking` features are defined in your crate for conditional compilation.
/// - **Method Definitions**: Corresponding methods (e.g., `read` for blocking and `read_async` for async) must be
/// implemented to match the execution model when using `bisync`.