Skip to main content

frozen_core/
fe.rs

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