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