use std::fmt;
use anyhow::{Result, bail};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
#[derive(Debug, Default, PartialEq, Clone)]
#[repr(u8)]
pub enum LogoutReason {
#[default]
CloseSession = 0x01,
CloseConnection = 0x02,
RemoveConnectionForRecovery = 0x03,
}
impl LogoutReason {
#[inline]
pub fn as_u8(&self) -> u8 {
match self {
LogoutReason::CloseSession => 0x01,
LogoutReason::CloseConnection => 0x02,
LogoutReason::RemoveConnectionForRecovery => 0x03,
}
}
}
impl TryFrom<u8> for LogoutReason {
type Error = anyhow::Error;
fn try_from(value: u8) -> Result<Self> {
Ok(match value {
0x01 => LogoutReason::CloseSession,
0x02 => LogoutReason::CloseConnection,
0x03 => LogoutReason::RemoveConnectionForRecovery,
other => bail!("unexpected logout code {other}"),
})
}
}
impl fmt::Display for LogoutReason {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use LogoutReason::*;
let s = match self {
CloseSession => "CloseSession",
CloseConnection => "CloseConnection",
RemoveConnectionForRecovery => "RemoveConnectionForRecovery",
};
f.write_str(s)
}
}
#[repr(transparent)]
#[derive(
Copy, Clone, Debug, PartialEq, Eq, FromBytes, IntoBytes, KnownLayout, Immutable,
)]
pub struct RawLogoutReason(u8);
impl Default for RawLogoutReason {
#[inline]
fn default() -> Self {
Self(LogoutReason::CloseSession.as_u8())
}
}
impl RawLogoutReason {
#[inline]
pub const fn raw(self) -> u8 {
self.0
}
#[inline]
pub const fn from_raw(v: u8) -> Self {
Self(v)
}
#[inline]
pub fn decode(self) -> Result<LogoutReason> {
LogoutReason::try_from(self.0)
}
#[inline]
pub fn encode(&mut self, r: LogoutReason) {
self.0 = r.as_u8();
}
}
impl TryFrom<RawLogoutReason> for LogoutReason {
type Error = anyhow::Error;
#[inline]
fn try_from(w: RawLogoutReason) -> Result<Self> {
w.decode()
}
}
impl From<LogoutReason> for RawLogoutReason {
#[inline]
fn from(r: LogoutReason) -> Self {
Self(r.as_u8())
}
}
impl From<&LogoutReason> for RawLogoutReason {
#[inline]
fn from(r: &LogoutReason) -> Self {
Self(r.as_u8())
}
}
#[derive(Debug, Default, PartialEq, Eq)]
#[repr(u8)]
pub enum LogoutResponseCode {
#[default]
Success = 0x00,
CidNotFound = 0x01,
RecoveryNotSupported = 0x02,
CleanupFailed = 0x03,
}
impl LogoutResponseCode {
#[inline]
pub fn as_u8(&self) -> u8 {
match self {
LogoutResponseCode::Success => 0x00,
LogoutResponseCode::CidNotFound => 0x01,
LogoutResponseCode::RecoveryNotSupported => 0x02,
LogoutResponseCode::CleanupFailed => 0x03,
}
}
}
impl TryFrom<u8> for LogoutResponseCode {
type Error = anyhow::Error;
fn try_from(v: u8) -> Result<Self> {
Ok(match v {
0x00 => LogoutResponseCode::Success,
0x01 => LogoutResponseCode::CidNotFound,
0x02 => LogoutResponseCode::RecoveryNotSupported,
0x03 => LogoutResponseCode::CleanupFailed,
other => bail!("invalid LogoutResponseCode: {other:#04x}"),
})
}
}
impl fmt::Display for LogoutResponseCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use LogoutResponseCode::*;
let s = match self {
Success => "Success",
CidNotFound => "CidNotFound",
RecoveryNotSupported => "RecoveryNotSupported",
CleanupFailed => "CleanupFailed",
};
f.write_str(s)
}
}
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq, Eq, FromBytes, IntoBytes, KnownLayout, Immutable)]
pub struct RawLogoutResponseCode(u8);
impl Default for RawLogoutResponseCode {
#[inline]
fn default() -> Self {
Self(LogoutResponseCode::Success.as_u8())
}
}
impl RawLogoutResponseCode {
#[inline]
pub const fn raw(self) -> u8 {
self.0
}
#[inline]
pub const fn from_raw(v: u8) -> Self {
Self(v)
}
#[inline]
pub fn decode(self) -> Result<LogoutResponseCode> {
LogoutResponseCode::try_from(self.0)
}
#[inline]
pub fn encode(&mut self, r: LogoutResponseCode) {
self.0 = r.as_u8();
}
}
impl TryFrom<RawLogoutResponseCode> for LogoutResponseCode {
type Error = anyhow::Error;
#[inline]
fn try_from(w: RawLogoutResponseCode) -> Result<Self> {
w.decode()
}
}
impl From<LogoutResponseCode> for RawLogoutResponseCode {
#[inline]
fn from(r: LogoutResponseCode) -> Self {
Self(r.as_u8())
}
}
impl From<&LogoutResponseCode> for RawLogoutResponseCode {
#[inline]
fn from(r: &LogoutResponseCode) -> Self {
Self(r.as_u8())
}
}
impl fmt::Debug for RawLogoutResponseCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let decoded = match self.decode() {
Ok(st) => format!("{st:?}"),
Err(_e) => format!("invalid(0x{:02X})", self.raw()),
};
write!(f, "RawScsiStatus {{ {:?} }}", decoded)
}
}