1#![cfg_attr(feature = "nightly", feature(likely_unlikely))]
3
4#[cfg(feature = "error-msg")]
5use core::fmt::{self, Write};
6use core::fmt::{Debug, Display};
7
8#[cfg(not(feature = "nightly"))]
10#[allow(unused_imports)]
11pub(crate) use core::convert::{identity as likely, identity as unlikely};
12
13#[cfg(feature = "nightly")]
14pub(crate) use core::hint::{likely, unlikely};
15
16pub type Result<T> = core::result::Result<T, Error>;
17pub use hal_api::PosixError;
18#[macro_export]
21macro_rules! bug {
22 () => {
23 panic!("BUG at {}:{}", file!(), line!());
24 };
25 ($fmt:literal $(, $arg:expr)* $(,)?) => {{
26 panic!(concat!("BUG at {}:{}: ", $fmt), file!(), line!() $(, $arg)*);
27 }};
28}
29
30#[macro_export]
31macro_rules! warn {
32 () => {
33 $crate::kprintln!("WARN at {}:{}", file!(), line!());
34 };
35 ($fmt:literal $(, $arg:expr)* $(,)?) => {{
36 $crate::kprintln!(concat!("WARN at {}:{}: ", $fmt), file!(), line!() $(, $arg)*);
37 }};
38}
39
40macro_rules! bug_on {
43 ($cond:expr) => {{
44 let cond = $cond;
45 #[allow(unused_unsafe)]
46 if unsafe { $crate::error::unlikely(cond) } {
47 panic!("BUG({}) at {}:{}", stringify!($cond), file!(), line!());
48 }
49 }};
50 ($cond:expr, $fmt:literal $(, $arg:expr)* $(,)?) => {{
51 let cond = $cond;
52 #[allow(unused_unsafe)]
53 if unsafe { $crate::error::unlikely(cond) } {
54 panic!(concat!("BUG({}) at {}:{}: ", $fmt), stringify!($cond), file!(), line!() $(, $arg)*);
55 }
56 }};
57}
58
59#[allow(unused_macros)]
60macro_rules! warn_on {
61 ($cond:expr) => {{
62 let cond = $cond;
63 #[allow(unused_unsafe)]
64 if unsafe { $crate::error::unlikely(cond) } {
65 kprintln!("WARN({}) at {}:{}", stringify!($cond), file!(), line!());
66 }
67 }};
68 ($cond:expr, $fmt:literal $(, $arg:expr)* $(,)?) => {{
69 let cond = $cond;
70 #[allow(unused_unsafe)]
71 if unsafe { $crate::error::unlikely(cond) } {
72 kprintln!(concat!("WARN({}) at {}:{}: ", $fmt), stringify!($cond), file!(), line!() $(, $arg)*);
73 }
74 }};
75}
76
77macro_rules! kerr {
78 ($posix:ident) => {
79 $crate::error::Error::new($crate::error::PosixError::$posix)
80 };
81 ($posix:ident, $msg:expr) => {{
82 #[cfg(feature = "error-msg")]
83 {
84 $crate::error::Error::new($crate::error::PosixError::$posix).with_msg($msg)
85 }
86 #[cfg(not(feature = "error-msg"))]
87 {
88 $crate::error::Error::new($crate::error::PosixError::$posix)
89 }
90 }};
91}
92
93#[derive(Clone, Eq)]
94pub struct Error {
95 pub kind: PosixError,
96 #[cfg(feature = "error-msg")]
97 msg: Option<Msg>,
98}
99
100#[cfg(feature = "error-msg")]
101struct Msg {
102 buf: [u8; 128],
103 len: usize,
104}
105
106#[cfg(feature = "error-msg")]
107impl Msg {
108 fn new(args: fmt::Arguments<'_>) -> Self {
109 let mut msg = Self {
110 buf: [0; 128],
111 len: 0,
112 };
113 let _ = msg.write_fmt(args);
114 msg
115 }
116
117 fn as_str(&self) -> &str {
118 unsafe { core::str::from_utf8_unchecked(&self.buf[..self.len]) }
121 }
122}
123
124#[cfg(feature = "error-msg")]
125impl Write for Msg {
126 fn write_str(&mut self, s: &str) -> fmt::Result {
127 let remaining = self.buf.len() - self.len;
128 let mut write_len = remaining.min(s.len());
129
130 while !s.is_char_boundary(write_len) {
131 write_len -= 1;
132 }
133
134 self.buf[self.len..self.len + write_len].copy_from_slice(&s.as_bytes()[..write_len]);
135 self.len += write_len;
136 Ok(())
137 }
138}
139
140impl Error {
141 pub fn new(kind: PosixError) -> Self {
142 #[cfg(feature = "error-msg")]
143 {
144 Self { kind, msg: None }
145 }
146 #[cfg(not(feature = "error-msg"))]
147 {
148 Self { kind }
149 }
150 }
151
152 #[cfg(feature = "error-msg")]
153 pub fn with_msg(mut self, msg: fmt::Arguments<'_>) -> Self {
154 self.msg = Some(Msg::new(msg));
155 self
156 }
157}
158
159impl Debug for Error {
160 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
161 #[cfg(feature = "error-msg")]
162 {
163 match &self.msg {
164 Some(msg) => write!(f, "{}: {}", self.kind, msg.as_str()),
165 None => write!(f, "{}", self.kind),
166 }
167 }
168 #[cfg(not(feature = "error-msg"))]
169 {
170 write!(f, "{}", self.kind)
171 }
172 }
173}
174
175impl Display for Error {
176 #[cfg(not(feature = "error-msg"))]
177 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
178 write!(f, "{}", self.kind)
179 }
180
181 #[cfg(feature = "error-msg")]
182 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
183 match &self.msg {
184 Some(msg) => write!(f, "{}: {}", self.kind, msg.as_str()),
185 None => write!(f, "{}", self.kind),
186 }
187 }
188}
189
190impl From<PosixError> for Error {
191 fn from(e: PosixError) -> Self {
192 Self::new(e)
193 }
194}
195
196impl PartialEq for Error {
197 fn eq(&self, other: &Self) -> bool {
198 self.kind == other.kind
199 }
200}
201
202#[cfg(all(test, feature = "error-msg"))]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn kerr_formats_captured_message() {
208 let compatible = "sensor";
209 let ordinal = 2usize;
210 let err = kerr!(
211 NotFound,
212 "i2c device not found: compatible={compatible}, ordinal={ordinal}"
213 );
214
215 assert_eq!(
216 format!("{err}"),
217 "Not found: i2c device not found: compatible=sensor, ordinal=2"
218 );
219 }
220}