Skip to main content

waitup/
macros.rs

1//! Convenience macros for creating targets and configurations.
2
3/// Create TCP targets from a compact syntax.
4///
5/// Returns a `Result<Vec<Target>, WaitForError>` that contains either all valid targets
6/// or the first error encountered.
7///
8/// # Examples
9///
10/// ```rust
11/// use waitup::tcp_targets;
12///
13/// let targets = tcp_targets![
14///     "localhost" => 8080,
15///     "database" => 5432,
16///     "cache" => 6379,
17/// ]?;
18/// assert_eq!(targets.len(), 3);
19/// # Ok::<(), waitup::WaitForError>(())
20/// ```
21#[macro_export]
22macro_rules! tcp_targets {
23    ($($host:expr => $port:expr),* $(,)?) => {
24        {
25            #[expect(clippy::vec_init_then_push, reason = "macro expansion requires incremental push pattern")]
26            let result = || -> $crate::Result<Vec<$crate::Target>> {
27                let mut targets = Vec::new();
28                $(
29                    targets.push($crate::Target::tcp($host, $port)?);
30                )*
31                return Ok(targets)
32            };
33            result()
34        }
35    };
36}
37
38/// Create HTTP targets from a compact syntax.
39///
40/// Returns a `Result<Vec<Target>, WaitForError>` that contains either all valid targets
41/// or the first error encountered.
42///
43/// # Examples
44///
45/// ```rust
46/// use waitup::http_targets;
47///
48/// let targets = http_targets![
49///     "https://api.example.com/health" => 200,
50///     "http://localhost:8080/status" => 204,
51/// ]?;
52/// assert_eq!(targets.len(), 2);
53/// # Ok::<(), waitup::WaitForError>(())
54/// ```
55#[macro_export]
56macro_rules! http_targets {
57    ($($url:expr => $status:expr),* $(,)?) => {
58        {
59            #[expect(clippy::vec_init_then_push, reason = "macro expansion requires incremental push pattern")]
60            let result = || -> $crate::Result<Vec<$crate::Target>> {
61                let mut targets = Vec::new();
62                $(
63                    targets.push($crate::Target::http_url($url, $status)?);
64                )*
65                return Ok(targets)
66            };
67            result()
68        }
69    };
70}
71
72/// Create a wait configuration with a compact syntax.
73///
74/// # Examples
75///
76/// ```rust
77/// use waitup::wait_config;
78/// use std::time::Duration;
79///
80/// let config = wait_config! {
81///     timeout: Duration::from_secs(30),
82///     interval: Duration::from_millis(500),
83///     wait_for_any: false,
84/// };
85/// ```
86#[macro_export]
87macro_rules! wait_config {
88    (
89        $(timeout: $timeout:expr,)?
90        $(interval: $interval:expr,)?
91        $(max_interval: $max_interval:expr,)?
92        $(connection_timeout: $connection_timeout:expr,)?
93        $(max_retries: $max_retries:expr,)?
94        $(wait_for_any: $wait_for_any:expr,)?
95    ) => {
96        {
97            let mut builder = $crate::WaitConfig::builder();
98            $(builder = builder.timeout($timeout);)?
99            $(builder = builder.interval($interval);)?
100            $(builder = builder.max_interval($max_interval);)?
101            $(builder = builder.connection_timeout($connection_timeout);)?
102            $(builder = builder.max_retries($max_retries);)?
103            $(builder = builder.wait_for_any($wait_for_any);)?
104            builder.build()
105        }
106    };
107}
108
109/// Create common port configurations.
110///
111/// # Examples
112///
113/// ```rust
114/// use waitup::common_ports;
115///
116/// let ports = common_ports![http, https, ssh, postgres];
117/// assert_eq!(ports.len(), 4);
118/// ```
119#[macro_export]
120macro_rules! common_ports {
121    ($($port_name:ident),* $(,)?) => {
122        vec![
123            $(
124                $crate::Port::$port_name()
125            ),*
126        ]
127    };
128}
129
130/// Check that all targets in a collection are ready within a timeout.
131///
132/// Returns a `Result<WaitResult, WaitForError>` instead of panicking.
133///
134/// # Examples
135///
136/// ```rust,no_run
137/// use waitup::{check_ready, Target, WaitConfig};
138/// use std::time::Duration;
139///
140/// # #[tokio::main]
141/// # async fn main() -> Result<(), waitup::WaitForError> {
142/// let targets = vec![
143///     Target::tcp("localhost", 8080)?,
144/// ];
145///
146/// // Create config first to avoid temporary value issues
147/// let config = WaitConfig::builder()
148///     .timeout(Duration::from_secs(30))
149///     .build();
150/// let result = waitup::wait_for_connection(&targets, &config).await?;
151/// println!("All targets ready in {:?}", result.elapsed);
152/// # Ok(())
153/// # }
154/// ```
155#[macro_export]
156macro_rules! check_ready {
157    ($targets:expr, timeout: $timeout:expr) => {
158        {
159            let config = $crate::WaitConfig::builder()
160                .timeout($timeout)
161                .build();
162            $crate::wait_for_connection(&$targets, &config)
163        }
164    };
165    ($targets:expr, $($config_field:ident: $config_value:expr),+ $(,)?) => {
166        {
167            let config = $crate::wait_config! {
168                $($config_field: $config_value,)+
169            };
170            $crate::wait_for_connection(&$targets, &config)
171        }
172    };
173}
174
175/// Assert that all targets in a collection are ready within a timeout (panics on failure).
176///
177/// **Note:** This macro panics on failure. Consider using `check_ready!` for non-test code.
178///
179/// # Examples
180///
181/// ```rust,no_run
182/// use waitup::{assert_ready, Target};
183/// use std::time::Duration;
184///
185/// # #[tokio::main]
186/// # async fn main() -> Result<(), waitup::WaitForError> {
187/// let targets = vec![
188///     Target::tcp("localhost", 8080)?,
189/// ];
190///
191/// assert_ready!(targets, timeout: Duration::from_secs(30));
192/// # Ok(())
193/// # }
194/// ```
195#[macro_export]
196macro_rules! assert_ready {
197    ($targets:expr, timeout: $timeout:expr) => {
198        {
199            let config = $crate::WaitConfig::builder()
200                .timeout($timeout)
201                .build();
202            $crate::wait_for_connection(&$targets, &config)
203                .await
204                .unwrap_or_else(|e| panic!("Targets should be ready, but failed with: {}", e))
205        }
206    };
207    ($targets:expr, $($config_field:ident: $config_value:expr),+ $(,)?) => {
208        {
209            let config = $crate::wait_config! {
210                $($config_field: $config_value,)+
211            };
212            $crate::wait_for_connection(&$targets, &config)
213                .await
214                .unwrap_or_else(|e| panic!("Targets should be ready, but failed with: {}", e))
215        }
216    };
217}