Skip to main content

frozen_core/
fe.rs

1//!
2//! Custom errors implementation for Frozen Codebases
3//!
4
5/// 32-bit error code used in [`FErr`]
6pub type FECode = u32;
7
8/// Custom result type w/ [`FErr`] as error type
9pub type FRes<T> = Result<T, FErr>;
10
11/// Utility trait to print the error if present
12pub trait FECheckOk {
13    /// Returns `true` when [`FRes`] is `Ok`, otherwise _prints_ the error
14    fn check_ok(self) -> bool;
15}
16
17impl<T> FECheckOk for Result<T, FErr> {
18    #[inline]
19    fn check_ok(self) -> bool {
20        const SEPERATOR: &'static str = "\n----------\n";
21        match self {
22            Err(e) => {
23                eprintln!("{SEPERATOR}FErr {{ code: {}, msg: {} }}{SEPERATOR}", e.code, e.msg);
24                false
25            }
26            Ok(_) => true,
27        }
28    }
29}
30
31/// Custom error object for frozen codebases
32#[derive(Debug, Clone, Eq, PartialEq)]
33pub struct FErr {
34    /// 32-bit error code
35    pub code: FECode,
36
37    /// error message
38    pub msg: std::borrow::Cow<'static, str>,
39}
40
41impl FErr {
42    /// Create a new error with a static message
43    #[inline]
44    pub fn new(code: FECode, msg: &'static str) -> Self {
45        Self {
46            code,
47            msg: std::borrow::Cow::Borrowed(msg),
48        }
49    }
50
51    /// Create a new error with an owned message
52    #[inline]
53    pub fn with_msg(code: FECode, msg: String) -> Self {
54        Self {
55            code,
56            msg: std::borrow::Cow::Owned(msg),
57        }
58    }
59
60    /// Create a new error from any type implementing [`std::fmt::Display`]
61    #[inline]
62    pub fn with_err<E>(code: FECode, err: E) -> Self
63    where
64        E: std::fmt::Display,
65    {
66        Self {
67            code,
68            msg: std::borrow::Cow::Owned(err.to_string()),
69        }
70    }
71}
72
73/// Construct an [`FECode`] from raw values
74///
75/// ## Notes
76///
77/// - Moudle should be <= 16
78/// - Domain should be >= 17 && <= 32
79pub const fn new_err_code(module: u8, domain: u8, reason: u16) -> FECode {
80    // sanity check
81    debug_assert!(module <= 0x10, "Module should be 0-16");
82    debug_assert!(domain >= 0x11 && domain <= 0x20, "Domain should be 17-32");
83
84    ((module as u32) << 24) | ((domain as u32) << 16) | (reason as u32)
85}
86
87#[cfg(test)]
88mod fe {
89    use super::*;
90
91    const fn from_err_code(code: FECode) -> (u8, u8, u16) {
92        let reason = code as u16;
93        let domain = (code >> 16) as u8;
94        let module = (code >> 24) as u8;
95
96        (module, domain, reason)
97    }
98
99    #[test]
100    fn err_code_roundtrip() {
101        let module: u8 = 0x0A;
102        let domain: u8 = 0x15;
103        let reason: u16 = 0xBEEF;
104
105        let code = new_err_code(module, domain, reason);
106        let (m, d, r) = from_err_code(code);
107
108        assert_eq!(m, module);
109        assert_eq!(d, domain);
110        assert_eq!(r, reason);
111        assert_eq!(code, 0x0A15BEEF);
112    }
113}