Skip to main content

stylex_macros/
panic_macros.rs

1//! Error handling macros for consistent error handling across the workspace.
2//!
3//! These macros provide standardized patterns for handling common error cases
4//! when working with expressions, conversions, and evaluations.
5
6use colored::Colorize;
7
8use crate::stylex_error::StyleXError;
9
10/// Macro to unwrap a Result or panic with the error message.
11/// This is a cleaner replacement for `.unwrap_or_else(|error| panic!("{}", error))`.
12///
13/// # Usage
14/// ```ignore
15/// let value = unwrap_or_panic!(expr_to_num(&arg, state, traversal_state, fns));
16/// // Or with additional context:
17/// let value = unwrap_or_panic!(expr_to_num(&arg, state, traversal_state, fns), "Converting to number");
18/// ```
19///
20/// # Arguments
21/// - `$result`: A Result type to unwrap
22/// - `$context` (optional): Additional context string to prepend to the error message
23#[macro_export]
24macro_rules! unwrap_or_panic {
25  ($result:expr) => {
26    $result.unwrap_or_else(|error| {
27      $crate::panic_macros::__stylex_panic($crate::panic_macros::stylex_err(format!("{}", error)))
28    })
29  };
30  ($result:expr, $context:expr) => {
31    $result.unwrap_or_else(|error| {
32      $crate::panic_macros::__stylex_panic($crate::panic_macros::stylex_err(format!(
33        "{}: {}",
34        $context, error
35      )))
36    })
37  };
38}
39
40// ---------------------------------------------------------------------------
41// Constructor helpers
42// ---------------------------------------------------------------------------
43
44/// Create a simple `StyleXError` with just a message.
45pub fn stylex_err(message: impl Into<String>) -> StyleXError {
46  StyleXError {
47    message: message.into(),
48    file: None,
49    key_path: None,
50    line: None,
51    col: None,
52    source_location: None,
53  }
54}
55
56/// Create a `StyleXError` with a message and file context.
57pub fn stylex_err_with_file(message: impl Into<String>, file: impl Into<String>) -> StyleXError {
58  StyleXError {
59    message: message.into(),
60    file: Some(file.into()),
61    key_path: None,
62    line: None,
63    col: None,
64    source_location: None,
65  }
66}
67
68// ---------------------------------------------------------------------------
69// Internal diverging functions (called by macros — not for direct use)
70//
71// Macros must call these via `$crate::…` paths because Rust macros cannot
72// invoke other `#[macro_export]` macros by `$crate::macro_name!()`.
73// ---------------------------------------------------------------------------
74
75#[doc(hidden)]
76#[track_caller]
77pub fn __stylex_panic(mut err: StyleXError) -> ! {
78  let caller = std::panic::Location::caller();
79
80  if err.source_location.is_none() {
81    err.source_location = Some(format!("{}:{}", caller.file(), caller.line()));
82  }
83
84  panic!("{}", err)
85}
86
87#[doc(hidden)]
88#[track_caller]
89pub fn __stylex_unimplemented(mut err: StyleXError) -> ! {
90  let caller = std::panic::Location::caller();
91  if err.source_location.is_none() {
92    err.source_location = Some(format!("{}:{}", caller.file(), caller.line()));
93  }
94  err.message = format!("{} {}", "[UNIMPLEMENTED]".dimmed().magenta(), err.message);
95
96  panic!("{}", err)
97}
98
99#[doc(hidden)]
100#[track_caller]
101pub fn __stylex_unreachable(mut err: StyleXError) -> ! {
102  let caller = std::panic::Location::caller();
103  if err.source_location.is_none() {
104    err.source_location = Some(format!("{}:{}", caller.file(), caller.line()));
105  }
106  err.message = format!("{} {}", "[UNREACHABLE]".dimmed().blue(), err.message);
107
108  panic!("{}", err)
109}
110
111// ---------------------------------------------------------------------------
112// Convenience macros
113// ---------------------------------------------------------------------------
114
115/// Like `panic!()` but produces `[StyleX] <message>`.
116///
117/// Usage:
118/// ```ignore
119/// stylex_panic!();
120/// stylex_panic!("border is not supported");
121/// stylex_panic!("Invalid value: {}", val);
122/// ```
123#[macro_export]
124macro_rules! stylex_panic {
125  () => {
126    $crate::panic_macros::__stylex_panic(
127      $crate::panic_macros::stylex_err("explicit panic")
128    )
129  };
130  ($($arg:tt)+) => {
131    $crate::panic_macros::__stylex_panic(
132      $crate::panic_macros::stylex_err(
133        format!($($arg)+)
134      )
135    )
136  };
137}
138
139#[macro_export]
140macro_rules! stylex_panic_with_file {
141  ($($arg:tt)*) => {
142    $crate::macros::panic_macros::__stylex_panic(
143      $crate::macros::panic_macros::stylex_err_with_file(
144        format!($($arg)*),
145        file!()
146      )
147    )
148  };
149}
150
151/// Like `unimplemented!()` but produces `[StyleX] [UNIMPLEMENTED] <message>`.
152#[macro_export]
153macro_rules! stylex_unimplemented {
154  () => {
155    $crate::panic_macros::__stylex_unimplemented(
156      $crate::panic_macros::stylex_err("not implemented")
157    )
158  };
159  ($($arg:tt)+) => {
160    $crate::panic_macros::__stylex_unimplemented(
161      $crate::panic_macros::stylex_err(
162        format!($($arg)+)
163      )
164    )
165  };
166}
167
168/// Like `unreachable!()` but produces `[StyleX] [UNREACHABLE] <message>`.
169#[macro_export]
170macro_rules! stylex_unreachable {
171  () => {
172    $crate::panic_macros::__stylex_unreachable(
173      $crate::panic_macros::stylex_err("entered unreachable code")
174    )
175  };
176  ($($arg:tt)+) => {
177    $crate::panic_macros::__stylex_unreachable(
178      $crate::panic_macros::stylex_err(
179        format!($($arg)+)
180      )
181    )
182  };
183}
184
185/// Like `anyhow::bail!()` but wraps the error in `StyleXError`.
186///
187/// Returns `Err(anyhow::Error)` with the `[StyleX]` prefix.
188#[macro_export]
189macro_rules! stylex_bail {
190  ($($arg:tt)*) => {
191    return Err(anyhow::anyhow!(
192      $crate::panic_macros::StyleXError {
193        message: format!($($arg)*),
194        file: None,
195        key_path: None,
196        line: None,
197        col: None,
198        source_location: None,
199      }
200    ))
201  };
202}
203
204/// Like `anyhow::anyhow!()` but wraps in `StyleXError`.
205///
206/// Returns `anyhow::Error` (not `Result`).
207#[macro_export]
208macro_rules! stylex_anyhow {
209  ($($arg:tt)*) => {
210    anyhow::anyhow!(
211      $crate::panic_macros::StyleXError {
212        message: format!($($arg)*),
213        file: None,
214        key_path: None,
215        line: None,
216        col: None,
217        source_location: None,
218      }
219    )
220  };
221}
222
223/// Unwrap a `Result` or panic with a `[StyleX]` prefixed message.
224///
225/// Drop-in replacement for the existing `unwrap_or_panic!` macro.
226///
227/// Usage:
228/// ```ignore
229/// let val = stylex_unwrap!(result);
230/// let val = stylex_unwrap!(result, "Converting value");
231/// ```
232#[macro_export]
233macro_rules! stylex_unwrap {
234  ($result:expr) => {
235    $result.unwrap_or_else(|error| {
236      $crate::panic_macros::__stylex_panic($crate::panic_macros::stylex_err(format!("{}", error)))
237    })
238  };
239  ($result:expr, $context:expr) => {
240    $result.unwrap_or_else(|error| {
241      $crate::panic_macros::__stylex_panic($crate::panic_macros::stylex_err(format!(
242        "{}: {}",
243        $context, error
244      )))
245    })
246  };
247}