cairo_lang_diagnostics/
error_code.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use std::fmt;

/// The unique and never-changing identifier of an error or warning.
///
/// Valid error codes must start with capital `E` followed by 4 decimal digits, e.g.: `E0001`.
///
/// Use the [`error_code!`][`crate::error_code!`] macro to construct a well-formed `ErrorCode` in
/// compile-time.
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct ErrorCode(&'static str);

impl ErrorCode {
    #[doc(hidden)]
    pub const fn new(code: &'static str) -> Self {
        assert!(
            matches!(code.as_bytes(), [b'E', b'0'..=b'9', b'0'..=b'9', b'0'..=b'9', b'0'..=b'9']),
            "Error codes must start with capital `E` followed by 4 decimal digits."
        );
        Self(code)
    }

    /// Format this error code in a way that is suitable for display in error message.
    ///
    /// ```
    /// # use cairo_lang_diagnostics::error_code;
    /// assert_eq!(error_code!(E0001).display_bracketed(), "[E0001]");
    /// ```
    pub fn display_bracketed(self) -> String {
        format!("[{}]", self)
    }

    pub fn as_str(&self) -> &str {
        self.0
    }
}

impl fmt::Display for ErrorCode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self.0, f)
    }
}

/// Constructs an [`ErrorCode`].
///
/// ```
/// # use cairo_lang_diagnostics::{error_code, ErrorCode};
/// let code: ErrorCode = error_code!(E0001);
/// # assert_eq!(format!("{code}"), "E0001");
/// ```
#[macro_export]
macro_rules! error_code {
    ($code:expr) => {{
        use $crate::ErrorCode;
        // NOTE: This is a magic trick to trigger the validation in compile time.
        const ENSURE_CONST: ErrorCode = ErrorCode::new(stringify!($code));
        ENSURE_CONST
    }};
}

/// Utilities for `Option<ErrorCode>`.
pub trait OptionErrorCodeExt {
    fn display_bracketed(self) -> String;
}

impl OptionErrorCodeExt for Option<ErrorCode> {
    /// Format this error code in a way that is suitable for display in error message.
    ///
    /// ```
    /// # use cairo_lang_diagnostics::{error_code, OptionErrorCodeExt};
    /// assert_eq!(Some(error_code!(E0001)).display_bracketed(), "[E0001]");
    /// assert_eq!(None.display_bracketed(), "");
    /// ```
    fn display_bracketed(self) -> String {
        self.map(ErrorCode::display_bracketed).unwrap_or_default()
    }
}