1pub type FrozenRes<T> = Result<T, FrozenErr>;
5
6#[derive(Clone, Eq, PartialEq)]
8pub struct FrozenErr {
9 module: u8,
10 domain: u8,
11 reason: u16,
12 detail: &'static [u8],
13 errmsg: Vec<u8>,
14}
15
16impl FrozenErr {
17 #[inline]
28 pub fn new(module: u8, domain: u8, reason: u16, detail: &'static [u8], errmsg: Vec<u8>) -> Self {
29 Self {
30 module,
31 domain,
32 reason,
33 detail,
34 errmsg,
35 }
36 }
37
38 #[inline]
50 pub fn cmp(&self, reason: u16) -> bool {
51 self.reason == reason
52 }
53
54 #[inline]
71 pub const fn error_id(&self) -> u32 {
72 ((self.module as u32) << 24) | ((self.domain as u32) << 16) | (self.reason as u32)
73 }
74}
75
76impl core::fmt::Display for FrozenErr {
77 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
78 let detail = core::str::from_utf8(&self.errmsg).unwrap_or("<non-utf8>");
79 let errmsg = core::str::from_utf8(&self.errmsg).unwrap_or("<non-utf8>");
80
81 #[cfg(test)]
82 return write!(
83 f,
84 "[m={}, d={}, c={}] ({detail}) {errmsg}",
85 self.module, self.domain, self.reason
86 );
87
88 #[cfg(not(test))]
89 write!(f, "[{}] ({detail}) {errmsg}", self.error_id())
90 }
91}
92
93impl core::fmt::Debug for FrozenErr {
94 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
95 write!(f, "\n----------\n")?;
96 core::fmt::Display::fmt(self, f)?;
97 write!(f, "\n----------\n")
98 }
99}
100
101#[cfg(test)]
106pub const TEST_MID: u8 = 0x00;
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[inline]
113 const fn from_error_id(eid: u32) -> (u8, u8, u16) {
114 let module = ((eid >> 24) & 0xff) as u8;
115 let domain = ((eid >> 16) & 0xff) as u8;
116 let reason = (eid & 0xffff) as u16;
117 (module, domain, reason)
118 }
119
120 #[test]
121 fn ok_error_id_roundtrip_basic() {
122 let err = FrozenErr::new(0x01, 0x02, 0x0033, b"io", Vec::new());
123 let eid = err.error_id();
124
125 assert_eq!(eid, 0x0102_0033);
126
127 let (m, d, r) = from_error_id(eid);
128 assert_eq!(m, 0x01);
129 assert_eq!(d, 0x02);
130 assert_eq!(r, 0x0033);
131 }
132
133 #[test]
134 fn ok_error_id_roundtrip_edges() {
135 let err = FrozenErr::new(0xff, 0x00, 0xffff, b"edge", Vec::new());
136 let eid = err.error_id();
137
138 assert_eq!(eid, 0xff00_ffff);
139
140 let (m, d, r) = from_error_id(eid);
141 assert_eq!(m, 0xff);
142 assert_eq!(d, 0x00);
143 assert_eq!(r, 0xffff);
144 }
145
146 #[test]
147 fn ok_error_id_reason_only_changes_low_bits() {
148 let e1 = FrozenErr::new(1, 2, 1, b"", Vec::new()).error_id();
149 let e2 = FrozenErr::new(1, 2, 2, b"", Vec::new()).error_id();
150
151 assert_eq!(e1 & 0xffff_0000, e2 & 0xffff_0000);
152 assert_ne!(e1 & 0x0000_ffff, e2 & 0x0000_ffff);
153 }
154}