embedded_hal_error/
lib.rs1#![no_std]
2#![deny(rust_2018_compatibility)]
3#![deny(rust_2018_idioms)]
4#![warn(missing_docs)]
5#![forbid(unsafe_code)]
6
7use core::{error, fmt};
10
11pub struct Error<E, K> {
16 inner: E,
17 kind: K,
18}
19
20impl<E, K> Error<E, K> {
21 pub fn into_inner(self) -> E {
23 self.inner
24 }
25}
26
27impl<E, K> core::ops::Deref for Error<E, K> {
28 type Target = E;
29 fn deref(&self) -> &Self::Target {
30 &self.inner
31 }
32}
33
34impl<E: fmt::Debug, K> fmt::Display for Error<E, K> {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 fmt::Debug::fmt(&self.inner, f)
37 }
38}
39
40impl<E: fmt::Debug, K> fmt::Debug for Error<E, K> {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 fmt::Debug::fmt(&self.inner, f)
43 }
44}
45
46impl<E: fmt::Debug, K: error::Error + 'static> error::Error for Error<E, K> {
47 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
48 Some(&self.kind as &dyn error::Error)
49 }
50}
51
52macro_rules! impl_from {
53 ($($mod:ident)::+) => {
54 impl<E: $($mod ::)+ Error> From<E> for Error<E, $($mod ::)+ ErrorKind> {
55 fn from(inner: E) -> Self {
56 let kind = inner.kind();
57 Self { inner, kind }
58 }
59 }
60 };
61}
62
63impl_from!(embedded_hal::digital);
64impl_from!(embedded_hal::i2c);
65impl_from!(embedded_hal::pwm);
66impl_from!(embedded_hal::spi);
67impl_from!(embedded_can);
68impl_from!(embedded_hal_nb::serial);
69impl_from!(embedded_io);
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use core::error::Error as _;
75 use embedded_hal::digital::{self, Error as _};
76 use thiserror::Error;
77
78 #[derive(Debug)]
80 struct PinError;
81 impl digital::Error for PinError {
82 fn kind(&self) -> digital::ErrorKind {
83 digital::ErrorKind::Other
84 }
85 }
86 struct Pin;
87 impl digital::ErrorType for Pin {
88 type Error = PinError;
89 }
90 impl digital::OutputPin for Pin {
91 fn set_high(&mut self) -> Result<(), Self::Error> {
92 Err(PinError)
93 }
94 fn set_low(&mut self) -> Result<(), Self::Error> {
95 Ok(())
96 }
97 }
98
99 #[derive(Debug, Error)]
101 enum DriverError<E: digital::Error> {
102 #[error("Hal")]
103 Hal(#[from] Error<E, digital::ErrorKind>),
104 #[error("logic")]
105 Logic,
106 }
107 impl<E: digital::Error> From<E> for DriverError<E> {
108 fn from(value: E) -> Self {
109 Error::from(value).into()
110 }
111 }
112
113 fn driver<P: digital::OutputPin>(pin: &mut P) -> Result<(), DriverError<P::Error>> {
114 pin.set_low().or(Err(DriverError::Logic))?;
115 Ok(pin.set_high()?)
116 }
117
118 #[test]
120 fn it_works() {
121 let driver_err = driver(&mut Pin).unwrap_err();
122 let pin_err = driver_err.source().unwrap();
123 assert!(matches!(
124 pin_err
125 .downcast_ref::<Error<PinError, digital::ErrorKind>>()
126 .unwrap()
127 .kind(), digital::ErrorKind::Other
129 ));
130 let kind = pin_err.source().unwrap();
131 assert!(matches!(
132 kind.downcast_ref::<digital::ErrorKind>().unwrap(),
133 digital::ErrorKind::Other
134 ));
135 assert!(kind.source().is_none());
136 }
138
139 #[test]
140 #[ignore]
141 fn with_anyhow() -> anyhow::Result<()> {
142 Ok(driver(&mut Pin)?)
143 }
144}