use std::fmt::Display;
use thiserror::Error;
pub(crate) type Result<T> = std::result::Result<T, SwitchError>;
#[derive(Error, Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum SwitchError {
#[error("expected timeout error after smashing the stack")]
ExpectedError,
#[error("switch in RCM mode not found")]
SwitchNotFound,
#[error("usb device was not initialized")]
NotInit,
#[error("unable to claim interface: `{0}`")]
UsbBadInterface(u8),
#[error(
"linux environment error, typically this means the system lacks a supported USB driver"
)]
LinuxEnv,
#[error("access denied (insufficient permissions)")]
AccessDenied,
#[error("platform not supported")]
PlatformNotSupported,
#[error("wrong RCM USB driver installed (installed: `{0}` but must be libusbK)")]
WindowsWrongDriver(WindowsDriver),
#[error("udev rules not found at `/etc/udev/rules.d/99-switch.rules`")]
UdevRulesNotFound,
#[error("usb error: `{0}`")]
Usb(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WindowsDriver {
LibUsbK,
LibUsb0,
WinUsb,
LibUsb0Filter,
Count,
}
impl Display for WindowsDriver {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::LibUsbK => write!(f, "libusbK"),
Self::LibUsb0 => write!(f, "libusb0"),
Self::WinUsb => write!(f, "winusb"),
Self::LibUsb0Filter => write!(f, "libusb0 filter"),
Self::Count => write!(f, "count"),
}
}
}
#[cfg(target_os = "windows")]
impl From<libusbk::DriverId> for WindowsDriver {
fn from(driver: libusbk::DriverId) -> Self {
use libusbk::DriverId;
match driver {
DriverId::LibUsbK => Self::LibUsbK,
DriverId::LibUsb0 => Self::LibUsb0,
DriverId::WinUsb => Self::WinUsb,
DriverId::LibUsb0Filter => Self::LibUsb0Filter,
DriverId::Count => Self::Count,
}
}
}
#[cfg(target_os = "windows")]
impl From<libusbk::Error> for SwitchError {
fn from(err: libusbk::Error) -> Self {
Self::Usb(err.to_string())
}
}
#[cfg(any(target_os = "macos", target_os = "linux"))]
impl From<rusb::Error> for SwitchError {
fn from(err: rusb::Error) -> Self {
match err {
rusb::Error::Access => Self::AccessDenied,
rusb::Error::NoDevice => Self::SwitchNotFound,
rusb::Error::NotFound => Self::SwitchNotFound,
_ => Self::Usb(err.to_string()),
}
}
}