use crate::command;
use failure::{bail, Error};
use serde::{
de::{Deserialize, Deserializer, Error as DeError},
ser::{Serialize, Serializer},
};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Code {
Success(command::Code),
MemoryError,
InitError,
ConnectionError,
ConnectorNotFound,
InvalidParameters,
WrongLength,
BufferTooSmall,
CryptogramMismatch,
SessionAuthenticationFailed,
MacMismatch,
DeviceOK,
DeviceInvalidCommand,
DeviceInvalidData,
DeviceInvalidSession,
DeviceAuthenticationFailed,
DeviceSessionsFull,
DeviceSessionFailed,
DeviceStorageFailed,
DeviceWrongLength,
DeviceInsufficientPermissions,
DeviceLogFull,
DeviceObjectNotFound,
DeviceInvalidId,
DeviceInvalidOtp,
DeviceDemoMode,
DeviceCommandUnexecuted,
GenericError,
DeviceObjectExists,
ConnectorError,
DeviceSshCaConstraintViolation,
}
impl Code {
pub fn from_u8(byte: u8) -> Result<Self, Error> {
let code = i16::from(byte).checked_sub(0x80).unwrap() as i8;
Ok(match code {
0..=0x7F => Code::Success(command::Code::from_u8(code as u8)?),
-1 => Code::MemoryError,
-2 => Code::InitError,
-3 => Code::ConnectionError,
-4 => Code::ConnectorNotFound,
-5 => Code::InvalidParameters,
-6 => Code::WrongLength,
-7 => Code::BufferTooSmall,
-8 => Code::CryptogramMismatch,
-9 => Code::SessionAuthenticationFailed,
-10 => Code::MacMismatch,
-11 => Code::DeviceOK,
-12 => Code::DeviceInvalidCommand,
-13 => Code::DeviceInvalidData,
-14 => Code::DeviceInvalidSession,
-15 => Code::DeviceAuthenticationFailed,
-16 => Code::DeviceSessionsFull,
-17 => Code::DeviceSessionFailed,
-18 => Code::DeviceStorageFailed,
-19 => Code::DeviceWrongLength,
-20 => Code::DeviceInsufficientPermissions,
-21 => Code::DeviceLogFull,
-22 => Code::DeviceObjectNotFound,
-23 => Code::DeviceInvalidId,
-24 => Code::DeviceInvalidOtp,
-25 => Code::DeviceDemoMode,
-26 => Code::DeviceCommandUnexecuted,
-27 => Code::GenericError,
-28 => Code::DeviceObjectExists,
-29 => Code::ConnectorError,
-30 => Code::DeviceSshCaConstraintViolation,
_ => bail!("invalid response code: {}", code),
})
}
pub fn to_u8(self) -> u8 {
let code: i8 = match self {
Code::Success(cmd_type) => cmd_type as i8,
Code::MemoryError => -1,
Code::InitError => -2,
Code::ConnectionError => -3,
Code::ConnectorNotFound => -4,
Code::InvalidParameters => -5,
Code::WrongLength => -6,
Code::BufferTooSmall => -7,
Code::CryptogramMismatch => -8,
Code::SessionAuthenticationFailed => -9,
Code::MacMismatch => -10,
Code::DeviceOK => -11,
Code::DeviceInvalidCommand => -12,
Code::DeviceInvalidData => -13,
Code::DeviceInvalidSession => -14,
Code::DeviceAuthenticationFailed => -15,
Code::DeviceSessionsFull => -16,
Code::DeviceSessionFailed => -17,
Code::DeviceStorageFailed => -18,
Code::DeviceWrongLength => -19,
Code::DeviceInsufficientPermissions => -20,
Code::DeviceLogFull => -21,
Code::DeviceObjectNotFound => -22,
Code::DeviceInvalidId => -23,
Code::DeviceInvalidOtp => -24,
Code::DeviceDemoMode => -25,
Code::DeviceCommandUnexecuted => -26,
Code::GenericError => -27,
Code::DeviceObjectExists => -28,
Code::ConnectorError => -29,
Code::DeviceSshCaConstraintViolation => -30,
};
(i16::from(code) + 0x80) as u8
}
pub fn is_success(self) -> bool {
match self {
Code::Success(_) => true,
_ => false,
}
}
pub fn is_err(self) -> bool {
!self.is_success()
}
}
impl Serialize for Code {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u8(self.to_u8())
}
}
impl<'de> Deserialize<'de> for Code {
fn deserialize<D>(deserializer: D) -> Result<Code, D::Error>
where
D: Deserializer<'de>,
{
let value = u8::deserialize(deserializer)?;
Code::from_u8(value)
.or_else(|_| Code::from_u8(Code::DeviceOK.to_u8() - value))
.or_else(|e| Err(D::Error::custom(format!("{}", e))))
}
}