cairo_lang_diagnostics/error_code.rs
1use std::fmt;
2
3/// The unique and never-changing identifier of an error or warning.
4///
5/// Valid error codes must start with capital `E` followed by 4 decimal digits, e.g.: `E0001`.
6///
7/// Use the [`error_code!`][`crate::error_code!`] macro to construct a well-formed `ErrorCode` in
8/// compile-time.
9#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
10pub struct ErrorCode(&'static str);
11
12impl ErrorCode {
13 #[doc(hidden)]
14 pub const fn new(code: &'static str) -> Self {
15 assert!(
16 matches!(code.as_bytes(), [b'E', b'0'..=b'9', b'0'..=b'9', b'0'..=b'9', b'0'..=b'9']),
17 "Error codes must start with capital `E` followed by 4 decimal digits."
18 );
19 Self(code)
20 }
21
22 /// Format this error code in a way that is suitable for display in error message.
23 ///
24 /// ```
25 /// # use cairo_lang_diagnostics::error_code;
26 /// assert_eq!(error_code!(E0001).display_bracketed(), "[E0001]");
27 /// ```
28 pub fn display_bracketed(self) -> String {
29 format!("[{}]", self)
30 }
31
32 pub fn as_str(&self) -> &str {
33 self.0
34 }
35}
36
37impl fmt::Display for ErrorCode {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 fmt::Display::fmt(self.0, f)
40 }
41}
42
43/// Constructs an [`ErrorCode`].
44///
45/// ```
46/// # use cairo_lang_diagnostics::{error_code, ErrorCode};
47/// let code: ErrorCode = error_code!(E0001);
48/// # assert_eq!(format!("{code}"), "E0001");
49/// ```
50#[macro_export]
51macro_rules! error_code {
52 ($code:expr) => {{
53 use $crate::ErrorCode;
54 // NOTE: This is a magic trick to trigger the validation in compile time.
55 const ENSURE_CONST: ErrorCode = ErrorCode::new(stringify!($code));
56 ENSURE_CONST
57 }};
58}
59
60/// Utilities for `Option<ErrorCode>`.
61pub trait OptionErrorCodeExt {
62 fn display_bracketed(self) -> String;
63}
64
65impl OptionErrorCodeExt for Option<ErrorCode> {
66 /// Format this error code in a way that is suitable for display in error message.
67 ///
68 /// ```
69 /// # use cairo_lang_diagnostics::{error_code, OptionErrorCodeExt};
70 /// assert_eq!(Some(error_code!(E0001)).display_bracketed(), "[E0001]");
71 /// assert_eq!(None.display_bracketed(), "");
72 /// ```
73 fn display_bracketed(self) -> String {
74 self.map(ErrorCode::display_bracketed).unwrap_or_default()
75 }
76}