1use core::{array::TryFromSliceError, fmt, str::Utf8Error};
19
20#[cfg(all(feature = "alloc", feature = "backtrace"))]
21use alloc::{boxed::Box, string::ToString};
22
23#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
32#[cfg_attr(feature = "defmt", derive(defmt::Format))]
33pub enum ErrorCode {
34 AlreadyExists,
35 AttributeNotFound,
36 AttributeIsCustom,
37 BufferTooSmall,
38 ClusterNotFound,
39 CommandNotFound,
40 Duplicate,
41 NodeNotFound,
42 EndpointNotFound,
43 EventNotFound,
44 InvalidAction,
45 InvalidCommand,
46 FailSafeRequired,
47 NeedsTimedInteraction,
48 ConstraintError,
49 DynamicConstraintError,
50 InvalidDataType,
51 UnsupportedAccess,
52 ResourceExhausted,
53 Busy,
54 DataVersionMismatch,
55 BtpError,
56 MdnsError,
57 NoCommand,
58 NoEndpoint,
59 NoExchange,
60 NoFabricId,
61 NoHandler,
62 NoNetworkInterface,
63 DBusError,
64 NoNodeId,
65 NoMemory,
66 NoSession,
67 NoSpace,
76 NoSpaceExchanges,
77 NoSpaceSessions,
78 TxTimeout,
79 RxTimeout,
80 NoTagFound,
81 NotFound,
82 PacketPoolExhaust,
83 StdIoError,
84 SysTimeFail,
85 Invalid,
86 InvalidAAD,
87 InvalidData,
88 InvalidKeyLength,
89 InvalidOpcode,
90 InvalidProto,
91 InvalidPeerAddr,
92 InvalidAuthKey,
94 InvalidSignature,
95 InvalidState,
96 InvalidTime,
97 InvalidArgument,
98 RwLock,
99 TLVNotFound,
100 TLVTypeMismatch,
101 TruncatedPacket,
102 Utf8Fail,
103 GennCommInvalidAuthentication,
104 NocInvalidNoc,
105 NocInvalidPublicKey,
106 NocMissingCsr,
107 NocFabricTableFull,
108 NocFabricConflict,
109 NocLabelConflict,
110 NocInvalidFabricIndex,
111 NocInvalidAdminSubject,
112 Failure,
113 CdInvalidFormat,
115 CdInvalidSignature,
116 CdSigningKeyNotFound,
117 CdInvalidVendorId,
118 CdInvalidProductId,
119 CdInvalidPaa,
120}
121
122impl From<ErrorCode> for Error {
123 fn from(code: ErrorCode) -> Self {
124 Self::new(code)
125 }
126}
127
128pub struct Error {
129 code: ErrorCode,
130 #[cfg(all(feature = "std", feature = "backtrace"))]
131 backtrace: std::backtrace::Backtrace,
132 #[cfg(all(feature = "alloc", feature = "backtrace"))]
133 inner: Option<Box<dyn core::error::Error + Send + Sync>>,
134}
135
136impl Error {
137 pub fn new(code: ErrorCode) -> Self {
138 Self {
139 code,
140 #[cfg(all(feature = "std", feature = "backtrace"))]
141 backtrace: std::backtrace::Backtrace::capture(),
142 #[cfg(all(feature = "alloc", feature = "backtrace"))]
143 inner: None,
144 }
145 }
146
147 #[cfg(all(feature = "alloc", feature = "backtrace"))]
148 pub fn new_with_details(
149 code: ErrorCode,
150 detailed_err: Box<dyn core::error::Error + Send + Sync>,
151 ) -> Self {
152 Self {
153 code,
154 #[cfg(feature = "std")]
155 backtrace: std::backtrace::Backtrace::capture(),
156 inner: Some(detailed_err),
157 }
158 }
159
160 pub const fn code(&self) -> ErrorCode {
161 self.code
162 }
163
164 #[cfg(all(feature = "std", feature = "backtrace"))]
165 pub const fn backtrace(&self) -> &std::backtrace::Backtrace {
166 &self.backtrace
167 }
168
169 #[cfg(all(feature = "alloc", feature = "backtrace"))]
170 pub fn details(&self) -> Option<&(dyn core::error::Error + Send + Sync)> {
171 self.inner.as_ref().map(|err| err.as_ref())
172 }
173}
174
175#[cfg(all(feature = "std", feature = "backtrace"))]
176impl From<std::io::Error> for Error {
177 fn from(e: std::io::Error) -> Self {
178 Self::new_with_details(ErrorCode::StdIoError, Box::new(e))
179 }
180}
181
182#[cfg(all(feature = "std", not(feature = "backtrace")))]
183impl From<std::io::Error> for Error {
184 fn from(_e: std::io::Error) -> Self {
185 Self::new(ErrorCode::StdIoError)
186 }
187}
188
189#[cfg(feature = "std")]
190impl<T> From<std::sync::PoisonError<T>> for Error {
191 fn from(_e: std::sync::PoisonError<T>) -> Self {
192 Self::new(ErrorCode::RwLock)
193 }
194}
195
196#[cfg(all(
197 feature = "os",
198 target_os = "linux",
199 feature = "bluer",
200 not(feature = "backtrace")
201))]
202impl From<bluer::Error> for Error {
203 fn from(e: bluer::Error) -> Self {
204 error!("Error in BTP: {}", display2format!(e));
207 Self::new(ErrorCode::BtpError)
208 }
209}
210
211#[cfg(all(
212 feature = "os",
213 target_os = "linux",
214 feature = "bluer",
215 feature = "backtrace"
216))]
217impl From<bluer::Error> for Error {
218 fn from(e: bluer::Error) -> Self {
219 Self::new_with_details(ErrorCode::BtpError, Box::new(e))
220 }
221}
222
223#[cfg(feature = "std")]
224impl From<std::time::SystemTimeError> for Error {
225 fn from(_e: std::time::SystemTimeError) -> Self {
226 Error::new(ErrorCode::SysTimeFail)
227 }
228}
229
230impl From<TryFromSliceError> for Error {
231 fn from(_e: TryFromSliceError) -> Self {
232 Self::new(ErrorCode::Invalid)
233 }
234}
235
236impl From<Utf8Error> for Error {
237 fn from(_e: Utf8Error) -> Self {
238 Self::new(ErrorCode::Utf8Fail)
239 }
240}
241
242impl<T: num_enum::TryFromPrimitive> From<num_enum::TryFromPrimitiveError<T>> for Error {
243 fn from(_e: num_enum::TryFromPrimitiveError<T>) -> Self {
244 Self::new(ErrorCode::Invalid)
245 }
246}
247
248impl fmt::Debug for Error {
249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 #[cfg(not(all(feature = "std", feature = "backtrace")))]
251 {
252 write!(f, "Error::{}", self)?;
253 }
254
255 #[cfg(all(feature = "std", feature = "backtrace"))]
256 {
257 writeln!(f, "Error::{} {{", self)?;
258 write!(f, "{}", self.backtrace())?;
259 writeln!(f, "}}")?;
260 }
261
262 Ok(())
263 }
264}
265
266impl fmt::Display for Error {
267 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
268 #[cfg(all(feature = "alloc", feature = "backtrace"))]
269 {
270 let err_msg = self
271 .inner
272 .as_ref()
273 .map_or(Default::default(), |err| err.to_string());
274
275 if err_msg.is_empty() {
276 write!(f, "{:?}", self.code())
277 } else {
278 write!(f, "{:?}: {}", self.code(), err_msg)
279 }
280 }
281 #[cfg(not(all(feature = "alloc", feature = "backtrace")))]
282 {
283 write!(f, "{:?}", self.code())
284 }
285 }
286}
287
288#[cfg(feature = "defmt")]
289impl defmt::Format for Error {
290 fn format(&self, f: defmt::Formatter<'_>) {
291 defmt::write!(f, "{:?}", self.code())
292 }
293}
294
295impl core::error::Error for Error {
296 #[cfg(all(feature = "alloc", feature = "backtrace"))]
297 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
298 self.inner
299 .as_ref()
300 .map(|e| e.as_ref() as &(dyn core::error::Error + 'static))
301 }
302}
303
304impl embedded_io_async::Error for Error {
305 fn kind(&self) -> embedded_io_async::ErrorKind {
306 embedded_io_async::ErrorKind::Other
307 }
308}