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}