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}