use crate::errors::NetworkParseError;
use bytes::{Buf, BufMut, Bytes, BytesMut};
use std::fmt::{Display, Formatter, Result as FmtResult};
use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value, Visit};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SataGetFilePositionPacketBody {
file_descriptor: i32,
}
impl SataGetFilePositionPacketBody {
#[must_use]
pub const fn new(file_descriptor: i32) -> Self {
Self { file_descriptor }
}
#[must_use]
pub const fn file_descriptor(&self) -> i32 {
self.file_descriptor
}
pub const fn set_file_descriptor(&mut self, new_fd: i32) {
self.file_descriptor = new_fd;
}
}
impl From<&SataGetFilePositionPacketBody> for Bytes {
fn from(value: &SataGetFilePositionPacketBody) -> Self {
let mut buff = BytesMut::with_capacity(4);
buff.put_i32(value.file_descriptor);
buff.freeze()
}
}
impl From<SataGetFilePositionPacketBody> for Bytes {
fn from(value: SataGetFilePositionPacketBody) -> Self {
Self::from(&value)
}
}
impl TryFrom<Bytes> for SataGetFilePositionPacketBody {
type Error = NetworkParseError;
fn try_from(mut value: Bytes) -> Result<Self, Self::Error> {
if value.len() < 0x4 {
return Err(NetworkParseError::FieldNotLongEnough(
"SataGetFilePosition",
"Body",
0x4,
value.len(),
value,
));
}
if value.len() > 0x4 {
return Err(NetworkParseError::UnexpectedTrailer(
"SataGetFilePosition",
value.slice(0x4..),
));
}
let fd = value.get_i32();
Ok(Self {
file_descriptor: fd,
})
}
}
const SATA_GET_FILE_POSITION_PACKET_BODY_FIELDS: &[NamedField<'static>] = &[NamedField::new("fd")];
impl Structable for SataGetFilePositionPacketBody {
fn definition(&self) -> StructDef<'_> {
StructDef::new_static(
"SataStatFilePacketBody",
Fields::Named(SATA_GET_FILE_POSITION_PACKET_BODY_FIELDS),
)
}
}
impl Valuable for SataGetFilePositionPacketBody {
fn as_value(&self) -> Value<'_> {
Value::Structable(self)
}
fn visit(&self, visitor: &mut dyn Visit) {
visitor.visit_named_fields(&NamedValues::new(
SATA_GET_FILE_POSITION_PACKET_BODY_FIELDS,
&[Valuable::as_value(&self.file_descriptor)],
));
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Valuable)]
pub struct SataGetFilePositionResult {
position: Result<u32, u32>,
}
impl SataGetFilePositionResult {
#[must_use]
pub const fn success(pos: u32) -> Self {
Self { position: Ok(pos) }
}
#[must_use]
pub const fn error(error_code: u32) -> Self {
Self {
position: Err(error_code),
}
}
pub const fn result(&self) -> Result<u32, u32> {
self.position
}
}
impl From<&SataGetFilePositionResult> for Bytes {
fn from(value: &SataGetFilePositionResult) -> Self {
let mut response = BytesMut::with_capacity(8);
match value.position {
Ok(pos) => {
response.put_u32(0);
response.put_u32(pos);
}
Err(code) => {
response.put_u32(code);
response.put_u32(u32::from_be_bytes([0xFF, 0xFF, 0xFF, 0xFF]));
}
}
response.freeze()
}
}
impl From<SataGetFilePositionResult> for Bytes {
fn from(value: SataGetFilePositionResult) -> Self {
Self::from(&value)
}
}
impl TryFrom<Bytes> for SataGetFilePositionResult {
type Error = NetworkParseError;
fn try_from(value: Bytes) -> Result<Self, Self::Error> {
if value.len() < 0x8 {
return Err(NetworkParseError::FieldNotLongEnough(
"SataPacket",
"FilePositionResult",
0x8,
value.len(),
value,
));
}
if value.len() > 0x8 {
return Err(NetworkParseError::UnexpectedTrailer(
"SataFilePositionResult",
value.slice(0x8..),
));
}
let rc = u32::from_be_bytes([value[0], value[1], value[2], value[3]]);
let pos = u32::from_be_bytes([value[4], value[5], value[6], value[7]]);
if rc == 0 {
Ok(Self::success(pos))
} else {
Ok(Self::error(rc))
}
}
}
impl Display for SataGetFilePositionResult {
fn fmt(&self, fmt: &mut Formatter<'_>) -> FmtResult {
match self.position {
Ok(pos) => write!(fmt, "Success ({pos})"),
Err(rc) => write!(fmt, "Failure ({rc:02x})"),
}
}
}