1use core::{ffi, fmt, num::NonZeroI32, str};
2
3use crate::{esp_err_t, esp_err_to_name, ESP_OK};
4
5#[repr(transparent)]
10#[derive(Copy, Clone, Eq, PartialEq, Hash)]
11pub struct EspError(NonZeroI32);
12
13const _: () = if ESP_OK != 0 {
14 panic!("ESP_OK *has* to be 0")
15};
16
17impl EspError {
18 pub const fn from(error: esp_err_t) -> Option<Self> {
20 match NonZeroI32::new(error) {
21 None => None,
22 Some(err) => Some(Self(err)),
23 }
24 }
25
26 pub const fn from_non_zero(error: NonZeroI32) -> Self {
28 Self(error)
29 }
30
31 pub const fn from_infallible<const E: esp_err_t>() -> Self {
33 struct Dummy<const D: esp_err_t>;
35 impl<const D: esp_err_t> Dummy<D> {
36 pub const ERR: EspError = match EspError::from(D) {
37 Some(err) => err,
38 None => panic!("ESP_OK can't be an error"),
39 };
40 }
41 Dummy::<E>::ERR
42 }
43
44 pub fn check_and_return<T>(error: esp_err_t, value: T) -> Result<T, Self> {
49 match NonZeroI32::new(error) {
50 None => Ok(value),
51 Some(err) => Err(Self(err)),
52 }
53 }
54
55 pub fn convert(error: esp_err_t) -> Result<(), Self> {
60 EspError::check_and_return(error, ())
61 }
62
63 #[track_caller]
65 pub fn panic(&self) {
66 panic!("ESP-IDF ERROR: {self}");
67 }
68
69 pub fn code(&self) -> esp_err_t {
71 self.0.get()
72 }
73}
74
75impl core::error::Error for EspError {}
76
77impl fmt::Display for EspError {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 unsafe {
80 let s = ffi::CStr::from_ptr(esp_err_to_name(self.code()));
81 core::fmt::Display::fmt(&str::from_utf8_unchecked(s.to_bytes()), f)
82 }
83 }
84}
85
86impl fmt::Debug for EspError {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 write!(f, "{} (error code {})", self, self.code())
89 }
90}
91
92#[macro_export]
96macro_rules! esp {
97 ($err:expr) => {{
98 $crate::EspError::convert($err as $crate::esp_err_t)
99 }};
100}
101
102#[macro_export]
106macro_rules! esp_result {
107 ($err:expr, $value:expr) => {{
108 $crate::EspError::check_and_return($err as $crate::esp_err_t, $value)
109 }};
110}
111
112#[macro_export]
116macro_rules! esp_nofail {
117 ($err:expr) => {{
118 if let ::core::option::Option::Some(error) =
119 $crate::EspError::from($err as $crate::esp_err_t)
120 {
121 error.panic();
122 }
123 }};
124}