1use std::fmt::Display;
2
3use thiserror::Error;
4
5pub(crate) type Result<T> = std::result::Result<T, SwitchError>;
7
8#[derive(Error, Debug, Clone, PartialEq, Eq)]
10#[non_exhaustive]
11pub enum SwitchError {
12 #[error("expected timeout error after smashing the stack")]
14 ExpectedError,
15
16 #[error("switch in RCM mode not found")]
18 SwitchNotFound,
19
20 #[error("usb device was not initialized")]
22 NotInit,
23
24 #[error("unable to claim interface: `{0}`")]
26 UsbBadInterface(u8),
27
28 #[error(
30 "linux environment error, typically this means the system lacks a supported USB driver"
31 )]
32 LinuxEnv,
33
34 #[error("access denied (insufficient permissions)")]
37 AccessDenied,
38
39 #[error("platform not supported")]
41 PlatformNotSupported,
42
43 #[error("wrong RCM USB driver installed (installed: `{0}` but must be libusbK)")]
46 WindowsWrongDriver(WindowsDriver),
47
48 #[error("udev rules not found at `/etc/udev/rules.d/99-switch.rules`")]
50 UdevRulesNotFound,
51
52 #[error("usb error: `{0}`")]
55 Usb(String),
56}
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub enum WindowsDriver {
61 LibUsbK,
62 LibUsb0,
63 WinUsb,
64 LibUsb0Filter,
65 Count,
66}
67
68impl Display for WindowsDriver {
69 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70 match self {
71 Self::LibUsbK => write!(f, "libusbK"),
72 Self::LibUsb0 => write!(f, "libusb0"),
73 Self::WinUsb => write!(f, "winusb"),
74 Self::LibUsb0Filter => write!(f, "libusb0 filter"),
75 Self::Count => write!(f, "count"),
76 }
77 }
78}
79
80#[cfg(target_os = "windows")]
81impl From<libusbk::DriverId> for WindowsDriver {
82 fn from(driver: libusbk::DriverId) -> Self {
83 use libusbk::DriverId;
84
85 match driver {
86 DriverId::LibUsbK => Self::LibUsbK,
87 DriverId::LibUsb0 => Self::LibUsb0,
88 DriverId::WinUsb => Self::WinUsb,
89 DriverId::LibUsb0Filter => Self::LibUsb0Filter,
90 DriverId::Count => Self::Count,
91 }
92 }
93}
94
95#[cfg(target_os = "windows")]
96impl From<libusbk::Error> for SwitchError {
97 fn from(err: libusbk::Error) -> Self {
98 Self::Usb(err.to_string())
99 }
100}
101
102#[cfg(any(target_os = "macos", target_os = "linux"))]
103impl From<rusb::Error> for SwitchError {
104 fn from(err: rusb::Error) -> Self {
105 match err {
106 rusb::Error::Access => Self::AccessDenied,
107 rusb::Error::NoDevice => Self::SwitchNotFound,
108 rusb::Error::NotFound => Self::SwitchNotFound,
109 _ => Self::Usb(err.to_string()),
110 }
111 }
112}