scsir 0.3.0

A simple library for issuing SCSI commands
Documentation
use std::io;

use crate::{command::sense::SenseData, error};

#[cfg(target_os = "linux")]
use crate::os::linux::{DriverStatus, HostStatus};

#[derive(Debug)]
pub struct ResultData<'a, D> {
    pub(crate) ioctl_result: i32,
    pub(crate) transfered_data_length: usize,
    pub(crate) data: &'a mut D,
    pub(crate) transfered_sense_length: usize,
    pub(crate) sense_buffer: &'a SenseData,
    pub(crate) status: Status,
    #[cfg(target_os = "linux")]
    pub(crate) host_status: HostStatus,
    #[cfg(target_os = "linux")]
    pub(crate) driver_status: DriverStatus,
}

#[allow(dead_code)]
#[derive(Clone, Copy, Debug)]
pub enum Status {
    Good,
    CheckCondition,
    ConditionMet,
    Busy,
    ReservationConflict,
    TaskSetFull,
    AcaActive,
    TaskAborted,
    Unknown(u8),
}

impl<D> ResultData<'_, D> {
    pub fn check_common_error(&self) -> crate::Result<()> {
        let mut result = String::new();

        #[cfg(target_os = "linux")]
        {
            if !matches!(self.host_status, crate::os::linux::HostStatus::Ok) {
                result.push_str(&format!("host status: {:?}. ", self.host_status));
            }

            if !self.driver_status.is_empty() {
                result.push_str(&format!("driver status: {:?}. ", self.driver_status));
            }
        }

        if !matches!(self.status, Status::Good) {
            result.push_str(&format!("Status: {:?}. ", self.status));
        }

        if self.transfered_sense_length != 0 {
            result.push_str(&format!("Sense data: {:02X?}", self.sense_buffer));
        }

        if !result.is_empty() {
            return Err(crate::Error::Other(result));
        }

        Ok(())
    }

    pub fn check_ioctl_error(&self) -> crate::Result<()> {
        match self.ioctl_result {
            0 => Ok(()),
            _ => Err(error::Error::IO(io::Error::last_os_error())),
        }
    }

    pub fn ioctl_result(&self) -> i32 {
        self.ioctl_result
    }

    pub fn transfered_data_length(&self) -> usize {
        self.transfered_data_length
    }

    pub fn data(&self) -> &D {
        self.data
    }

    pub fn transfered_sense_length(&self) -> usize {
        self.transfered_sense_length
    }

    pub fn sense_buffer(&self) -> &SenseData {
        self.sense_buffer
    }
}

impl From<u8> for Status {
    fn from(value: u8) -> Self {
        match value {
            0x00 => Self::Good,
            0x02 => Self::CheckCondition,
            0x04 => Self::ConditionMet,
            0x08 => Self::Busy,
            0x18 => Self::ReservationConflict,
            0x28 => Self::TaskSetFull,
            0x30 => Self::AcaActive,
            0x40 => Self::TaskAborted,
            _ => Self::Unknown(value),
        }
    }
}