use std::{fmt::Display, io, num::NonZeroU32};
use crate::{platform::format_os_error_code, transfer::TransferError};
#[derive(Debug, Clone)]
pub struct Error {
pub(crate) kind: ErrorKind,
pub(crate) code: Option<NonZeroU32>,
pub(crate) message: &'static str,
}
impl Error {
pub(crate) fn new(kind: ErrorKind, message: &'static str) -> Self {
Self {
kind,
code: None,
message,
}
}
#[track_caller]
pub(crate) fn log_error(self) -> Self {
log::error!("{}", self);
self
}
#[track_caller]
pub(crate) fn log_debug(self) -> Self {
log::debug!("{}", self);
self
}
pub fn kind(&self) -> ErrorKind {
self.kind
}
pub fn os_error(&self) -> Option<u32> {
self.code.map(|c| c.get())
}
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.message)?;
if let Some(code) = self.code {
write!(f, " (")?;
format_os_error_code(f, code.get())?;
write!(f, ")")?;
}
Ok(())
}
}
impl std::error::Error for Error {}
impl From<Error> for io::Error {
fn from(err: Error) -> Self {
let kind = match err.kind {
ErrorKind::Disconnected => io::ErrorKind::NotConnected,
ErrorKind::Busy => io::ErrorKind::Other, ErrorKind::PermissionDenied => io::ErrorKind::PermissionDenied,
ErrorKind::NotFound => io::ErrorKind::NotFound,
ErrorKind::Unsupported => io::ErrorKind::Unsupported,
ErrorKind::Other => io::ErrorKind::Other,
};
io::Error::new(kind, err)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum ErrorKind {
Disconnected,
Busy,
PermissionDenied,
NotFound,
Unsupported,
Other,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ActiveConfigurationError {
pub(crate) configuration_value: u8,
}
impl Display for ActiveConfigurationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.configuration_value == 0 {
write!(f, "device is not configured")
} else {
write!(
f,
"no descriptor found for active configuration {}",
self.configuration_value
)
}
}
}
impl std::error::Error for ActiveConfigurationError {}
impl From<ActiveConfigurationError> for Error {
fn from(value: ActiveConfigurationError) -> Self {
let message = if value.configuration_value == 0 {
"device is not configured"
} else {
"no descriptor found for active configuration"
};
Error::new(ErrorKind::Other, message)
}
}
impl From<ActiveConfigurationError> for std::io::Error {
fn from(value: ActiveConfigurationError) -> Self {
std::io::Error::other(value)
}
}
#[derive(Debug, Copy, Clone)]
pub enum GetDescriptorError {
Transfer(TransferError),
InvalidDescriptor,
}
impl Display for GetDescriptorError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GetDescriptorError::Transfer(e) => write!(f, "{}", e),
GetDescriptorError::InvalidDescriptor => write!(f, "invalid descriptor"),
}
}
}
impl std::error::Error for GetDescriptorError {}
impl From<GetDescriptorError> for std::io::Error {
fn from(value: GetDescriptorError) -> Self {
match value {
GetDescriptorError::Transfer(e) => e.into(),
GetDescriptorError::InvalidDescriptor => {
std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid descriptor")
}
}
}
}