maybe_fut/
macros.rs

1//! Utility macros to automatically implement the async/sync fn
2
3/// A macro to create a constructor function that can be used in both async and sync contexts.
4///
5/// It takes the documentation attributes, the function name, the arguments, the return type,
6/// the module is the internal path of a module (e.g. fs, net, etc),
7/// and finally the type name you want to create.
8///
9/// ## Examples
10///
11/// ```rust,ignore
12/// impl File {
13///     maybe_fut_constructor_result!(
14///         /// Attempts to open a file in read-only mode.
15///         /// See [`OpenOptions`] for more details.
16///         ///
17///         /// ## Errors
18///         ///
19///         /// This function will return an error if called from outside of the Tokio runtime (if async) or if path does not already exist.
20///         /// Other errors may also be returned according to OpenOptions::open.
21///         ///
22///         /// See <https://docs.rs/rustc-std-workspace-std/latest/std/fs/struct.File.html#method.open>
23///         open(path: impl AsRef<Path>) -> std::io::Result<Self>,
24///         std::fs::File::open,
25///         tokio::fs::File::open,
26///         tokio_fs
27///     );
28/// }
29/// ```
30#[macro_export]
31macro_rules! maybe_fut_constructor_result {
32    ($(#[$meta:meta])*
33        $name:ident
34        (
35            $ ( $arg_name:ident : $arg_type:ty ),*
36            $(,)?
37        )
38        -> $ret:ty,
39        $std_module:path,
40        $tokio_module:path,
41        $feature:ident
42    ) => {
43            $(#[$meta])*
44            pub async fn $name( $( $arg_name : $arg_type ),* ) -> $ret {
45                #[cfg($feature)]
46                {
47                    if $crate::is_async_context() {
48                        $tokio_module( $( $arg_name ),* ).await.map(Self::from)
49                    } else {
50                        $std_module( $( $arg_name ),* ).map(Self::from)
51                    }
52                }
53                #[cfg(not($feature))]
54                {
55                    $std_module( $( $arg_name ),* ).map(Self::from)
56                }
57            }
58        };
59}
60
61/// A macro to create a constructor function that can be used in both async and sync contexts.
62#[macro_export]
63macro_rules! maybe_fut_constructor {
64    ($(#[$meta:meta])*
65        $name:ident
66        (
67            $ ( $arg_name:ident : $arg_type:ty ),*
68            $(,)?
69        )
70        -> $ret:ty,
71        $std_module:path,
72        $tokio_module:path,
73        $feature:ident
74    ) => {
75            $(#[$meta])*
76            pub async fn $name( $( $arg_name : $arg_type ),* ) -> $ret {
77                #[cfg($feature)]
78                {
79                    if $crate::is_async_context() {
80                        $tokio_module( $( $arg_name ),* ).await.into()
81                    } else {
82                        $std_module( $( $arg_name ),* ).into()
83                    }
84                }
85                #[cfg(not($feature))]
86                {
87                    $std_module( $( $arg_name ),* ).into()
88                }
89            }
90        };
91}
92
93/// A macro to create a constructor function that can be used in both async and sync contexts.
94#[macro_export]
95macro_rules! maybe_fut_constructor_sync {
96    ($(#[$meta:meta])*
97        $name:ident
98        (
99            $ ( $arg_name:ident : $arg_type:ty ),*
100            $(,)?
101        )
102        -> $ret:ty,
103        $std_module:path,
104        $tokio_module:path,
105        $feature:ident
106    ) => {
107            $(#[$meta])*
108            pub fn $name( $( $arg_name : $arg_type ),* ) -> $ret {
109                #[cfg($feature)]
110                {
111                    if $crate::is_async_context() {
112                        $tokio_module( $( $arg_name ),* ).into()
113                    } else {
114                        $std_module( $( $arg_name ),* ).into()
115                    }
116                }
117                #[cfg(not($feature))]
118                {
119                    $std_module( $( $arg_name ),* ).into()
120                }
121            }
122        };
123}
124
125/// A macro to create a method that can be used in both async and sync contexts.
126#[macro_export]
127macro_rules! maybe_fut_method {
128    ($(#[$meta:meta])*
129        $name:ident
130        (
131            $( $arg_name:ident : $arg_type:ty ),* $(,)?
132        )
133        -> $ret:ty,
134        $sync_inner_type:path,
135        $async_inner_type:path,
136        $feature:ident
137    ) => {
138            $(#[$meta])*
139            pub async fn $name( &self, $( $arg_name : $arg_type ),* ) -> $ret {
140                match &self.0 {
141                    $sync_inner_type(inner) => inner.$name( $( $arg_name ),* ),
142                    #[cfg($feature)]
143                    $async_inner_type(inner) => inner.$name( $( $arg_name ),* ).await,
144                }
145            }
146        };
147}
148
149/// A macro to create a method that can be used in both async and sync contexts.
150#[macro_export]
151macro_rules! maybe_fut_method_sync {
152    ($(#[$meta:meta])*
153        $name:ident
154        (
155            $( $arg_name:ident : $arg_type:ty ),* $(,)?
156        )
157        -> $ret:ty,
158        $sync_inner_type:path,
159        $async_inner_type:path,
160        $feature:ident
161    ) => {
162            $(#[$meta])*
163            pub fn $name( &self, $( $arg_name : $arg_type ),* ) -> $ret {
164                match &self.0 {
165                    $sync_inner_type(inner) => inner.$name( $( $arg_name ),* ),
166                    #[cfg($feature)]
167                    $async_inner_type(inner) => inner.$name( $( $arg_name ),* ),
168                }
169            }
170        };
171}
172
173/// A macro to create a mutable method that can be used in both async and sync contexts.
174#[macro_export]
175macro_rules! maybe_fut_method_mut {
176    (
177        $(#[$meta:meta])*
178        $name:ident
179        (
180            $( $arg_name:ident : $arg_type:ty ),* $(,)?
181        )
182        -> $ret:ty,
183        $sync_inner_type:path,
184        $async_inner_type:path,
185        $feature:ident
186    ) => {
187            $(#[$meta])*
188            pub async fn $name( &mut self, $( $arg_name : $arg_type ),* ) -> $ret {
189                match &mut self.0 {
190                    $sync_inner_type(inner) => inner.$name( $( $arg_name ),* ),
191                    #[cfg($feature)]
192                    $async_inner_type(inner) => inner.$name( $( $arg_name ),* ).await,
193                }
194            }
195        };
196}
197
198#[macro_export]
199/// A macro to create a function that can be used in both async and sync contexts.
200macro_rules! maybe_fut_function {
201    (
202        $(#[$meta:meta])*
203        $name:ident
204        (
205            $( $arg_name:ident : $arg_type:ty ),* $(,)?
206        )
207        -> $ret:ty,
208        $sync_function:path,
209        $async_function:path,
210        $feature:ident
211    ) => {
212        $(#[$meta])*
213        pub async fn $name( $( $arg_name : $arg_type ),* ) -> $ret {
214            #[cfg($feature)]
215            {
216                if $crate::is_async_context() {
217                    $async_function( $( $arg_name ),* ).await
218                } else {
219                    $sync_function( $( $arg_name ),* )
220                }
221            }
222            #[cfg(not($feature))]
223            {
224                $sync_function( $( $arg_name ),* )
225            }
226        }
227    };
228}