use std::fmt;
type BoxedError = Box<dyn std::error::Error + Send + Sync>;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ErrorKind {
Usb,
DeviceNotFound,
MultipleDevicesFound,
MissingCapability,
Other,
#[doc(hidden)]
__NonExhaustive(crate::private::Private),
}
pub(crate) trait Cause {
const KIND: ErrorKind;
}
#[derive(Debug)]
pub struct Error {
kind: ErrorKind,
inner: BoxedError,
while_: Option<&'static str>,
}
impl Error {
pub(crate) fn new(kind: ErrorKind, inner: impl Into<BoxedError>) -> Self {
Self {
kind,
inner: inner.into(),
while_: None,
}
}
pub(crate) fn with_while(
kind: ErrorKind,
inner: impl Into<BoxedError>,
while_: &'static str,
) -> Self {
Self {
kind,
inner: inner.into(),
while_: Some(while_),
}
}
fn fmt_while(&self) -> String {
if let Some(while_) = self.while_ {
format!(" while {}", while_)
} else {
String::new()
}
}
pub fn kind(&self) -> ErrorKind {
self.kind
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.kind {
ErrorKind::Usb => write!(f, "USB error{}: {}", self.fmt_while(), self.inner),
_ => {
if let Some(while_) = self.while_ {
write!(f, "error{}: {}", while_, self.inner)
} else {
self.inner.fmt(f)
}
}
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.inner.source()
}
}
pub(crate) trait ResultExt<T, E> {
fn jaylink_err(self) -> Result<T, Error>
where
E: Cause + Into<BoxedError>;
fn jaylink_err_while(self, while_: &'static str) -> Result<T, Error>
where
E: Cause + Into<BoxedError>;
}
impl<T, E> ResultExt<T, E> for Result<T, E> {
fn jaylink_err(self) -> Result<T, Error>
where
E: Cause + Into<BoxedError>,
{
self.map_err(|e| Error::new(E::KIND, e))
}
fn jaylink_err_while(self, while_: &'static str) -> Result<T, Error>
where
E: Cause + Into<BoxedError>,
{
self.map_err(|e| Error::with_while(E::KIND, e, while_))
}
}
macro_rules! error_mapping {
(
$(
$errty:ty => $kind:ident,
)+
) => {
$(
impl Cause for $errty {
const KIND: ErrorKind = ErrorKind::$kind;
}
)+
};
}
error_mapping! {
rusb::Error => Usb,
String => Other,
}