use std::error::Error as StdError;
use std::fmt::{Display, Formatter};
use thiserror::Error;
type BoxedError = Box<dyn StdError + Send + Sync>;
#[derive(Debug)]
pub enum ErrorKind
{
TooManyDevices,
DeviceNotFound,
DeviceDisconnectDuringOperation,
DeviceSeemsInvalid(
String,
),
ReleaseMetadataInvalid,
External(ErrorSource),
}
impl ErrorKind
{
#[inline(always)]
pub fn error(self) -> Error
{
Error::new(self, None)
}
#[inline(always)]
pub fn error_from<E: StdError + Send + Sync + 'static>(self, source: E) -> Error
{
Error::new(self, Some(Box::new(source)))
}
}
impl From<ErrorKind> for Error
{
fn from(other: ErrorKind) -> Self
{
other.error()
}
}
impl Display for ErrorKind
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result
{
use ErrorKind::*;
match self {
TooManyDevices => write!(
f,
"current operation only supports one Black Magic Probe device but more than one device was found"
)?,
DeviceNotFound => write!(f, "Black Magic Probe device not found (check connection?)")?,
DeviceDisconnectDuringOperation => write!(f, "Black Magic Probe device found disconnected")?,
DeviceSeemsInvalid(thing) => {
write!(
f,
"\nBlack Magic Probe device returned bad data ({}) during configuration.\nThis generally \
shouldn't be possible. Maybe cable is bad, or OS is messing with things?",
thing,
)?;
},
ReleaseMetadataInvalid => write!(f, "Black Magic Debug release metadata was mallformed")?,
External(source) => {
use ErrorSource::*;
match source {
Nusb(e) => {
write!(f, "unhandled nusb error: {}", e)?;
},
DfuNusb(e) => {
write!(f, "unhandled dfu_nusb error: {}", e)?;
},
DfuCore(e) => {
write!(f, "unhandled dfu_core error: {}", e)?;
},
};
},
};
Ok(())
}
}
#[derive(Debug)]
pub struct Error
{
pub kind: ErrorKind,
pub source: Option<BoxedError>,
pub context: Option<String>,
}
impl Error
{
#[inline(always)]
pub fn new(kind: ErrorKind, source: Option<BoxedError>) -> Self
{
Self {
kind,
source,
context: None,
}
}
}
impl Display for Error
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result
{
if let Some(ctx) = &self.context {
write!(f, "(while {}): {}", ctx, self.kind)?;
} else {
write!(f, "{}", self.kind)?;
}
if let Some(source) = &self.source {
writeln!(f, "\nCaused by: {}", source)?;
}
Ok(())
}
}
impl StdError for Error
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)>
{
self.source.as_deref().map(|e| e as &dyn StdError)
}
}
impl From<dfu_nusb::Error> for Error
{
fn from(other: dfu_nusb::Error) -> Self
{
use ErrorKind::*;
use dfu_nusb::Error as Source;
match other {
Source::Nusb(source) => External(ErrorSource::Nusb(source)).error(),
Source::AltSettingNotFound => {
DeviceSeemsInvalid("DFU interface (alt mode) not found".into()).error_from(other)
},
Source::FunctionalDescriptorNotFound => {
DeviceSeemsInvalid("DFU functional descriptor not found".into()).error_from(other)
},
Source::FunctionalDescriptor(source) => {
DeviceSeemsInvalid("DFU functional interface descriptor".into()).error_from(source)
},
anything_else => External(ErrorSource::DfuNusb(anything_else)).error(),
}
}
}
impl From<dfu_core::Error> for Error
{
fn from(other: dfu_core::Error) -> Self
{
use ErrorKind::*;
use dfu_core::Error as Source;
match other {
Source::MemoryLayout(source) => {
DeviceSeemsInvalid(String::from("DFU interface memory layout string")).error_from(source)
},
Source::InvalidAddress => DeviceSeemsInvalid("DFU interface memory layout string".into()).error_from(other),
Source::InvalidInterfaceString => {
DeviceSeemsInvalid("DFU interface memory layout string".into()).error_from(other)
},
anything_else => External(ErrorSource::DfuCore(anything_else)).error(),
}
}
}
#[derive(Debug, Error)]
pub enum ErrorSource
{
#[error(transparent)]
Nusb(#[from] nusb::Error),
#[error(transparent)]
DfuNusb(#[from] dfu_nusb::Error),
#[error(transparent)]
DfuCore(#[from] dfu_core::Error),
}