1use std::borrow::Cow;
2use std::fmt::{Debug, Display, Formatter};
3use std::panic::Location;
4
5pub type HidResult<T> = Result<T, HidError>;
7
8#[derive(Debug)]
16pub enum HidError {
17 Disconnected,
19 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}