use core::fmt;
#[cfg(feature = "std")]
use std::error;
use crate::phys::{
BinaryDecodeError, BinaryDecoder, BinaryEncodeError, BinaryEncoder, SECTOR_SHIFT,
};
#[derive(Debug)]
pub struct Dva {
pub allocated: u32,
pub offset: u64,
pub is_gang: bool,
pub vdev: u32,
}
impl Dva {
pub const SIZE: usize = 16;
pub const ALLOCATED_MIN: u32 = 1;
pub const ALLOCATED_MAX: u32 = (1 << 24) - 1;
pub const OFFSET_MAX: u64 = Dva::OFFSET_MASK;
pub const VDEV_MAX: u32 = (1 << 24) - 1;
const ASIZE_MASK_DOWN_SHIFTED: u64 = (1 << 24) - 1;
const ASIZE_SHIFT: usize = 0;
const GRID_SHIFT: usize = 24;
const VDEV_MASK_DOWN_SHIFTED: u64 = (1 << 24) - 1;
const VDEV_SHIFT: usize = 32;
const PADDING_SHIFT: usize = 56;
const GANG_MASK_BIT_FLAG: u64 = 0x8000000000000000;
const OFFSET_MASK: u64 = (1 << 63) - 1;
pub fn get_size(&self) -> Option<usize> {
if let Ok(size) = usize::try_from(self.allocated) {
return size.checked_shl(SECTOR_SHIFT);
}
None
}
pub fn from_decoder(
decoder: &mut dyn BinaryDecoder<'_>,
) -> Result<Option<Dva>, DvaDecodeError> {
let a = decoder.get_u64()?;
let b = decoder.get_u64()?;
if a == 0 && b == 0 {
return Ok(None);
}
let grid = (a >> Dva::GRID_SHIFT) as u8;
if grid != 0 {
return Err(DvaDecodeError::NonZeroGrid { grid });
}
let padding = (a >> Dva::PADDING_SHIFT) as u8;
if padding != 0 {
return Err(DvaDecodeError::NonZeroPadding { padding });
}
Ok(Some(Dva {
vdev: ((a >> Dva::VDEV_SHIFT) & Dva::VDEV_MASK_DOWN_SHIFTED) as u32,
allocated: ((a >> Dva::ASIZE_SHIFT) & Dva::ASIZE_MASK_DOWN_SHIFTED) as u32,
offset: (b & Dva::OFFSET_MASK),
is_gang: (b & Dva::GANG_MASK_BIT_FLAG) != 0,
}))
}
pub fn to_encoder(&self, encoder: &mut dyn BinaryEncoder<'_>) -> Result<(), DvaEncodeError> {
if self.vdev > Dva::VDEV_MAX {
return Err(DvaEncodeError::InvalidVdev { vdev: self.vdev });
}
if self.allocated > Dva::ALLOCATED_MAX || self.allocated < Dva::ALLOCATED_MIN {
return Err(DvaEncodeError::InvalidAllocated {
allocated: self.allocated,
});
}
if self.offset > Dva::OFFSET_MAX {
return Err(DvaEncodeError::InvalidOffset {
offset: self.offset,
});
}
let a = (u64::from(self.vdev) << Dva::VDEV_SHIFT)
| (0 << Dva::GRID_SHIFT)
| (u64::from(self.allocated) << Dva::ASIZE_SHIFT);
let b = (if self.is_gang {
Dva::GANG_MASK_BIT_FLAG
} else {
0
}) | (self.offset);
encoder.put_u64(a)?;
encoder.put_u64(b)?;
Ok(())
}
pub fn empty_to_encoder(encoder: &mut dyn BinaryEncoder<'_>) -> Result<(), DvaEncodeError> {
Ok(encoder.put_zeros(Dva::SIZE)?)
}
pub fn option_to_encoder(
dva: &Option<Dva>,
encoder: &mut dyn BinaryEncoder<'_>,
) -> Result<(), DvaEncodeError> {
match dva {
Some(v) => v.to_encoder(encoder),
None => Ok(Dva::empty_to_encoder(encoder)?),
}
}
}
#[derive(Debug)]
pub enum DvaDecodeError {
Binary {
err: BinaryDecodeError,
},
InvalidOffset {
offset: u64,
},
NonZeroGrid {
grid: u8,
},
NonZeroPadding {
padding: u8,
},
}
impl From<BinaryDecodeError> for DvaDecodeError {
fn from(err: BinaryDecodeError) -> Self {
DvaDecodeError::Binary { err }
}
}
impl fmt::Display for DvaDecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DvaDecodeError::Binary { err } => {
write!(f, "DVA decode error | {err}")
}
DvaDecodeError::InvalidOffset { offset } => {
write!(f, "DVA decode error, invalid offset {offset}")
}
DvaDecodeError::NonZeroGrid { grid } => {
write!(f, "DVA decode error, non-zero grid {grid}")
}
DvaDecodeError::NonZeroPadding { padding } => {
write!(f, "DVA decode error, non-zero padding {padding}")
}
}
}
}
#[cfg(feature = "std")]
impl error::Error for DvaDecodeError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
DvaDecodeError::Binary { err } => Some(err),
_ => None,
}
}
}
#[derive(Debug)]
pub enum DvaEncodeError {
Binary {
err: BinaryEncodeError,
},
InvalidAllocated {
allocated: u32,
},
InvalidOffset {
offset: u64,
},
InvalidVdev {
vdev: u32,
},
}
impl From<BinaryEncodeError> for DvaEncodeError {
fn from(err: BinaryEncodeError) -> Self {
DvaEncodeError::Binary { err }
}
}
impl fmt::Display for DvaEncodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DvaEncodeError::Binary { err } => {
write!(f, "DVA encode error | {err}")
}
DvaEncodeError::InvalidAllocated { allocated } => {
write!(f, "DVA encode error, invalid allocated {allocated}")
}
DvaEncodeError::InvalidOffset { offset } => {
write!(f, "DVA encode error, invalid offset {offset}")
}
DvaEncodeError::InvalidVdev { vdev } => {
write!(f, "DVA encode error, invalid vdev {vdev}")
}
}
}
}
#[cfg(feature = "std")]
impl error::Error for DvaEncodeError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
DvaEncodeError::Binary { err } => Some(err),
_ => None,
}
}
}