use std::{error, fmt};
use crate::command::Command;
#[derive(Debug)]
pub enum Error {
CommandError(CommandError),
DeviceError(DeviceError),
HidError(hidapi::HidError),
RequestError(RequestError),
ResponseError(ResponseError),
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::CommandError(error) => Some(error),
Self::DeviceError(error) => Some(error),
Self::HidError(error) => Some(error),
Self::RequestError(error) => Some(error),
Self::ResponseError(error) => Some(error),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::CommandError(_) => "command executionf ailed",
Self::DeviceError(_) => "CTAPHID transaction failed",
Self::HidError(_) => "HID communication failed",
Self::RequestError(_) => "failed to receive CTAPHID response",
Self::ResponseError(_) => "failed to send CTAPHID request",
}
.fmt(f)
}
}
impl From<CommandError> for Error {
fn from(error: CommandError) -> Self {
Self::CommandError(error)
}
}
impl From<DeviceError> for Error {
fn from(error: DeviceError) -> Self {
Self::DeviceError(error)
}
}
impl From<RequestError> for Error {
fn from(error: RequestError) -> Self {
Self::RequestError(error)
}
}
impl From<ResponseError> for Error {
fn from(error: ResponseError) -> Self {
Self::ResponseError(error)
}
}
impl From<hidapi::HidError> for Error {
fn from(error: hidapi::HidError) -> Self {
Self::HidError(error)
}
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum CommandError {
InvalidNonce,
InvalidPingData,
}
impl error::Error for CommandError {}
impl fmt::Display for CommandError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidNonce => "received an init response with a wrong nonce",
Self::InvalidPingData => "received a ping response with wrong data",
}
.fmt(f)
}
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum DeviceError {
InvalidCommand,
InvalidParameter,
InvalidLength,
InvalidSequence,
MessageTimeout,
ChannelBusy,
LockRequired,
InvalidChannel,
Other,
Unknown(u8),
}
impl From<u8> for DeviceError {
fn from(error: u8) -> Self {
match error {
0x01 => Self::InvalidCommand,
0x02 => Self::InvalidParameter,
0x03 => Self::InvalidLength,
0x04 => Self::InvalidSequence,
0x05 => Self::MessageTimeout,
0x06 => Self::ChannelBusy,
0x0a => Self::LockRequired,
0x0b => Self::InvalidChannel,
0x7f => Self::Other,
error => Self::Unknown(error),
}
}
}
impl error::Error for DeviceError {}
impl fmt::Display for DeviceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidCommand => "the command in the request is invalid".fmt(f),
Self::InvalidParameter => "the parameter(s) in the request is invalid".fmt(f),
Self::InvalidLength => "the length field is invalid for the request".fmt(f),
Self::InvalidSequence => "the sequence does not match expected value".fmt(f),
Self::MessageTimeout => "the message has timed out".fmt(f),
Self::ChannelBusy => "the device is busy for the requesting channel".fmt(f),
Self::LockRequired => "command requires channel lock".fmt(f),
Self::InvalidChannel => "CID is not valid".fmt(f),
Self::Other => "unspecified error".fmt(f),
Self::Unknown(value) => write!(f, "unknown error code 0x{:x}", value),
}
}
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum RequestError {
BufferTooSmall,
DataTooLong,
IncompleteWrite,
}
impl error::Error for RequestError {}
impl fmt::Display for RequestError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::BufferTooSmall => "the buffer for serializing the request is too small",
Self::DataTooLong => "the request contains too much data",
Self::IncompleteWrite => "the request could not be written completely",
}
.fmt(f)
}
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum ResponseError {
NotEnoughData,
MissingErrorCode,
UnexpectedChannel {
expected: u32,
actual: u32,
},
UnexpectedCommand {
expected: Command,
actual: Command,
},
UnexpectedPacketType,
UnexpectedSequence {
expected: u8,
actual: u8,
},
}
impl error::Error for ResponseError {}
impl fmt::Display for ResponseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NotEnoughData => "a response packet does not contain enough data".fmt(f),
Self::MissingErrorCode => "an error packet does not contain an error code".fmt(f),
Self::UnexpectedChannel { expected, actual } => write!(
f,
"expected a response packet for channel 0x{:x} but received 0x{:x}",
expected, actual
),
Self::UnexpectedCommand { expected, actual } => write!(
f,
"expected a response packet for command {:?} but received {:?}",
expected, actual
),
Self::UnexpectedPacketType => "received a response packet of the wrong type".fmt(f),
Self::UnexpectedSequence { expected, actual } => write!(
f,
"expected a response packet with sequence 0x{:x} but received 0x{:x}",
expected, actual
),
}
}
}