use anyhow::Result;
use enum_dispatch::enum_dispatch;
use zerocopy::{BigEndian, U32, U64};
use crate::models::opcode::BhsOpcode;
pub const HEADER_LEN: usize = 48;
pub type InitiatorTaskTag = U32<BigEndian>;
pub type TargetTaskTag = U32<BigEndian>;
pub type LogicalUnitNumber = U64<BigEndian>;
#[enum_dispatch]
pub trait SendingData: Sized {
fn get_final_bit(&self) -> bool;
fn set_final_bit(&mut self);
fn get_continue_bit(&self) -> bool;
fn set_continue_bit(&mut self);
}
#[enum_dispatch]
pub trait BasicHeaderSegment: Sized + SendingData {
fn to_bhs_bytes(&self, buf: &mut [u8]) -> Result<()>;
fn get_opcode(&self) -> Result<BhsOpcode>;
fn get_initiator_task_tag(&self) -> u32;
fn get_ahs_length_bytes(&self) -> usize;
fn set_ahs_length_bytes(&mut self, len: u8);
fn get_data_length_bytes(&self) -> usize;
fn set_data_length_bytes(&mut self, len: u32);
#[inline]
fn total_length_bytes(&self) -> usize {
let padding_ahs = (4 - (self.get_ahs_length_bytes() % 4)) % 4;
let padding_data_segment = (4 - (self.get_data_length_bytes() % 4)) % 4;
HEADER_LEN
+ self.get_ahs_length_bytes()
+ padding_ahs
+ self.get_data_length_bytes()
+ padding_data_segment
}
#[inline]
fn get_header_diggest(&self, enable_header_digest: bool) -> usize {
4 * enable_header_digest as usize
}
#[inline]
fn get_data_diggest(&self, enable_data_digest: bool) -> usize {
4 * (self.get_data_length_bytes() > 0) as usize * enable_data_digest as usize
}
}
impl<T: SendingData> SendingData for &mut T {
#[inline]
fn get_final_bit(&self) -> bool {
(**self).get_final_bit()
}
#[inline]
fn set_final_bit(&mut self) {
(**self).set_final_bit()
}
#[inline]
fn get_continue_bit(&self) -> bool {
(**self).get_continue_bit()
}
#[inline]
fn set_continue_bit(&mut self) {
(**self).set_continue_bit()
}
}
impl<T: BasicHeaderSegment> BasicHeaderSegment for &mut T {
#[inline]
fn to_bhs_bytes(&self, buf: &mut [u8]) -> anyhow::Result<()> {
(**self).to_bhs_bytes(buf)
}
#[inline]
fn get_opcode(&self) -> anyhow::Result<BhsOpcode> {
(**self).get_opcode()
}
#[inline]
fn get_initiator_task_tag(&self) -> u32 {
(**self).get_initiator_task_tag()
}
#[inline]
fn get_ahs_length_bytes(&self) -> usize {
(**self).get_ahs_length_bytes()
}
#[inline]
fn set_ahs_length_bytes(&mut self, len: u8) {
(**self).set_ahs_length_bytes(len)
}
#[inline]
fn get_data_length_bytes(&self) -> usize {
(**self).get_data_length_bytes()
}
#[inline]
fn set_data_length_bytes(&mut self, len: u32) {
(**self).set_data_length_bytes(len)
}
#[inline]
fn total_length_bytes(&self) -> usize {
(**self).total_length_bytes()
}
#[inline]
fn get_header_diggest(&self, en: bool) -> usize {
(**self).get_header_diggest(en)
}
#[inline]
fn get_data_diggest(&self, en: bool) -> usize {
(**self).get_data_diggest(en)
}
}
pub trait Builder: Sized {
type Header: AsRef<[u8]>;
type Body: AsRef<[u8]>;
fn append_data(&mut self, more: &[u8]);
fn build(
&mut self,
max_recv_data_segment_length: usize,
) -> Result<(Self::Header, Self::Body)>;
}