Skip to main content

handle_this/macros/
handle.rs

1//! The `handle!` macro - main entry point for error handling.
2//!
3//! This declarative macro catches pattern keywords (which proc macros can't parse)
4//! and routes to the unified proc macro with pattern markers.
5
6/// Main error handling macro.
7///
8/// # Patterns
9///
10/// ## Basic try
11/// ```
12/// use handle_this::{handle, Result};
13///
14/// fn example() -> Result<i32> {
15///     handle! {
16///         try { Ok::<_, &str>(42)? }
17///         catch { -1 }
18///     }
19/// }
20/// assert_eq!(example().unwrap(), 42);
21/// ```
22///
23/// ## Try for (first success)
24/// ```
25/// use handle_this::{handle, Result};
26///
27/// fn example() -> Result<i32> {
28///     let items: Vec<std::result::Result<i32, &str>> = vec![Err("a"), Ok(42)];
29///     handle! {
30///         try for item in items { item? }
31///         catch { -1 }
32///     }
33/// }
34/// assert_eq!(example().unwrap(), 42);
35/// ```
36///
37/// ## Try all (collect all successes)
38/// ```
39/// use handle_this::{handle, Result};
40///
41/// fn example() -> Result<Vec<i32>> {
42///     let items = vec![1, 2, 3];
43///     handle! {
44///         try all item in items { Ok::<_, &str>(item * 2)? }
45///     }
46/// }
47/// assert_eq!(example().unwrap(), vec![2, 4, 6]);
48/// ```
49///
50/// ## Try while (retry until success or condition false)
51/// ```
52/// use handle_this::{handle, Result};
53///
54/// fn example() -> Result<&'static str> {
55///     let mut attempts = 0;
56///     handle! {
57///         try while attempts < 3 {
58///             attempts += 1;
59///             if attempts < 3 { Err("not yet")? }
60///             "success"
61///         }
62///         catch { "gave up" }
63///     }
64/// }
65/// assert_eq!(example().unwrap(), "success");
66/// ```
67#[macro_export]
68macro_rules! handle {
69    // ========================================
70    // Preconditions (require)
71    // ========================================
72
73    // require COND else "msg", rest...
74    (require $($rest:tt)+) => {
75        $crate::handle_this_macros::__handle_proc!(REQUIRE $($rest)+)
76    };
77
78    // scope "name", rest...
79    (scope $($rest:tt)+) => {
80        $crate::handle_this_macros::__handle_proc!(SCOPE $($rest)+)
81    };
82
83    // ========================================
84    // Conditional patterns
85    // ========================================
86
87    // try when CONDITION { } else when ... else { } handlers...
88    (try when $($rest:tt)+) => {
89        $crate::handle_this_macros::__handle_proc!(WHEN $($rest)+)
90    };
91
92    // ========================================
93    // Then chains, iteration patterns, and async
94    // More specific patterns (with `, then`) must come first
95    // ========================================
96
97    // async try { } , then ... (must come before general async)
98    (async try { $($body:tt)* } , then $($rest:tt)+) => {
99        $crate::handle_this_macros::__handle_proc!(THEN ASYNC { $($body)* } , then $($rest)+)
100    };
101
102    // async try { } handlers...
103    (async try { $($body:tt)* } $($rest:tt)+) => {
104        $crate::handle_this_macros::__handle_proc!(ASYNC { $($body)* } $($rest)+)
105    };
106
107    // async try { } alone
108    (async try { $($body:tt)* }) => {
109        $crate::handle_this_macros::__handle_proc!(ASYNC { $($body)* })
110    };
111
112    // try { } , then ... (basic - must come before general try)
113    (try { $($body:tt)* } , then $($rest:tt)+) => {
114        $crate::handle_this_macros::__handle_proc!(THEN BASIC { $($body)* } , then $($rest)+)
115    };
116
117    // try { } with ... (may or may not have then)
118    (try { $($body:tt)* } with $($with_and_rest:tt)+) => {
119        $crate::handle_this_macros::__then_or_sync!(BASIC { $($body)* } with $($with_and_rest)+)
120    };
121
122    // try -> T { } , then ... (direct mode with then)
123    (try -> $type:ty { $($body:tt)* } , then $($rest:tt)+) => {
124        $crate::handle_this_macros::__handle_proc!(THEN DIRECT -> $type { $($body)* } , then $($rest)+)
125    };
126
127    // try for/any/all/while - route through proc macro for then detection
128    (try for $($all:tt)+) => {
129        $crate::handle_this_macros::__then_or_iter!(FOR $($all)+)
130    };
131    (try any $($all:tt)+) => {
132        $crate::handle_this_macros::__then_or_iter!(ANY $($all)+)
133    };
134    (try all $($all:tt)+) => {
135        $crate::handle_this_macros::__then_or_iter!(ALL $($all)+)
136    };
137    (try while $($all:tt)+) => {
138        $crate::handle_this_macros::__then_or_iter!(WHILE $($all)+)
139    };
140
141    // ========================================
142    // Basic sync pattern
143    // ========================================
144
145    // try -> Type { } handlers... (explicit direct mode)
146    (try -> $type:ty { $($body:tt)* } $($rest:tt)+) => {
147        $crate::handle_this_macros::__handle_proc!(SYNC -> $type { $($body)* } $($rest)+)
148    };
149
150    // try -> Type { } alone (explicit direct mode, no handlers)
151    (try -> $type:ty { $($body:tt)* }) => {
152        $crate::handle_this_macros::__handle_proc!(SYNC -> $type { $($body)* })
153    };
154
155    // try { } handlers...
156    (try { $($body:tt)* } $($rest:tt)+) => {
157        $crate::handle_this_macros::__handle_proc!(SYNC { $($body)* } $($rest)+)
158    };
159
160    // try { } alone - just wraps with stack frame
161    (try { $($body:tt)* }) => {
162        $crate::handle_this_macros::__handle_proc!(SYNC { $($body)* })
163    };
164
165    // ========================================
166    // Error catch-all - route to proc macro for better spans
167    // ========================================
168
169    // Catch-all: first token preserved with span, proc macro determines error type
170    ($first:tt $($rest:tt)*) => {
171        $crate::handle_this_macros::__handle_proc!(ERROR $first $($rest)*)
172    };
173
174    // Empty input
175    () => {
176        $crate::handle_this_macros::__handle_proc!(ERROR_EMPTY)
177    };
178}