async_hid/
error.rs

1use std::borrow::Cow;
2use std::fmt::{Debug, Display, Formatter};
3use std::panic::Location;
4
5/// Specialized result type used for many functions in this library
6pub type HidResult<T> = Result<T, HidError>;
7
8/// The main error type of this library
9/// Currently mostly a wrapper around a platform specific error
10///
11/// **Warning**
12/// All mappings from platform specific errors to platform independent error
13/// such as `Disconnected` or `NotConnected` are performed on a best effort basis,
14/// as it is generally poorly documented by platform apis which operations can throw which errors and in what circumstances
15#[derive(Debug)]
16pub enum HidError {
17    /// This error occurs when trying to perform an action on a device which was diconnected after being opened
18    Disconnected,
19    /// This error occurs when trying to open a device which is no longer connected
20    NotConnected,
21    Message(Cow<'static, str>),
22    Other(Box<dyn std::error::Error + Send + Sync>)
23}
24
25impl HidError {
26    pub fn message(msg: impl Into<Cow<'static, str>>) -> Self {
27        Self::Message(msg.into())
28    }
29
30    #[track_caller]
31    pub fn from_backend(error: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Self {
32        let error = error.into();
33        log::trace!("Backend error: {} at {}", error, Location::caller());
34        Self::Other(error)
35    }
36}
37
38impl Display for HidError {
39    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
40        match self {
41            HidError::Message(msg) => f.write_str(msg),
42            HidError::Other(err) => Display::fmt(err, f),
43            HidError::Disconnected => f.write_str("The device was disconnected"),
44            HidError::NotConnected => f.write_str("The device is not connected")
45        }
46    }
47}
48
49impl std::error::Error for HidError {
50    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
51        match self {
52            HidError::Other(err) => Some(err.as_ref()),
53            _ => None
54        }
55    }
56}
57
58impl From<std::io::Error> for HidError {
59    #[track_caller]
60    fn from(value: std::io::Error) -> Self {
61        HidError::from_backend(value)
62    }
63}
64
65#[cfg(target_os = "windows")]
66impl From<windows::core::Error> for HidError {
67    #[track_caller]
68    fn from(error: windows::core::Error) -> Self {
69        const DISCONNECTED: windows::core::HRESULT = windows::core::HRESULT::from_win32(windows::Win32::Foundation::ERROR_DEVICE_NOT_CONNECTED.0);
70        match error.code() {
71            DISCONNECTED => HidError::Disconnected,
72            _ => HidError::from_backend(error)
73        }
74    }
75}
76
77#[cfg(target_os = "linux")]
78impl From<nix::errno::Errno> for HidError {
79    #[track_caller]
80    fn from(error: nix::errno::Errno) -> Self {
81        HidError::from_backend(nix::Error::from(error))
82    }
83}
84
85#[doc(hidden)]
86#[macro_export]
87macro_rules! ensure {
88    ($cond:expr, $result:expr) => {
89        if !($cond) {
90            return Err($result);
91        }
92    };
93    ($cond:expr) => {
94        if !($cond) {
95            return None;
96        }
97    };
98}