embedded_hal_error/
lib.rs

1#![no_std]
2#![deny(rust_2018_compatibility)]
3#![deny(rust_2018_idioms)]
4#![warn(missing_docs)]
5#![forbid(unsafe_code)]
6
7//! Provide `core::error::Error` for `embedded-hal` Errors using a newtype wrapper.
8
9use core::{error, fmt};
10
11/// Wrap a HAL `Error` and store its `ErrorKind` to provide [`core::error::Error`]
12///
13/// Uses `E: Debug` for `Debug` and `Display` and the
14/// stored `ErrorKind` as [`core::error::Error::source()`].
15pub struct Error<E, K> {
16    inner: E,
17    kind: K,
18}
19
20impl<E, K> Error<E, K> {
21    /// Extract the inner `Error`
22    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    // hal
79    #[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    // driver
100    #[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    // user
119    #[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(), // Deref
128            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        // println!("{driver_err:?}: {driver_err}\n{pin_err:?}: {pin_err}\n{kind:?}: {kind}");
137    }
138
139    #[test]
140    #[ignore]
141    fn with_anyhow() -> anyhow::Result<()> {
142        Ok(driver(&mut Pin)?)
143    }
144}