use super::BlockMode;
use crate::result::{Error, Result};
#[repr(u16)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Count {
Bytes(u16),
Blocks(u16),
Infinite,
}
impl Count {
pub const MIN: u16 = 1;
pub const MAX: u16 = 511;
pub const MAX_BYTES: u16 = 512;
pub const fn new() -> Self {
Self::Bytes(Self::MIN)
}
pub const fn from_parts(mode: BlockMode, val: u16) -> Result<Self> {
match (mode, val) {
(_, v) if v > Self::MAX => Err(Error::invalid_field_value(
"command::arg::count",
val as usize,
0,
Self::MAX as usize,
)),
(BlockMode::Byte, 0) => Ok(Self::Bytes(Self::MAX_BYTES)),
(BlockMode::Byte, v) => Ok(Self::Bytes(v)),
(BlockMode::Block, 0) => Ok(Self::Infinite),
(BlockMode::Block, v) => Ok(Self::Blocks(v)),
}
}
pub const fn from_parts_unchecked(mode: BlockMode, val: u16) -> Self {
match (mode, val) {
(BlockMode::Byte, 0) => Self::Bytes(Self::MAX_BYTES),
(BlockMode::Byte, v) => Self::Bytes(v),
(BlockMode::Block, 0) => Self::Infinite,
(BlockMode::Block, v) => Self::Blocks(v),
}
}
pub const fn into_parts(self) -> (BlockMode, u16) {
match self {
Self::Bytes(v) if v == Self::MAX_BYTES => (BlockMode::Byte, 0),
Self::Bytes(v) => (BlockMode::Byte, v),
Self::Blocks(v) => (BlockMode::Block, v),
Self::Infinite => (BlockMode::Block, 0),
}
}
}
impl Default for Count {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_count() {
(Count::MIN..=Count::MAX).for_each(|raw_count| {
[BlockMode::Byte, BlockMode::Block]
.into_iter()
.for_each(|mode| {
let exp_cnt = match mode {
BlockMode::Byte => Count::Bytes(raw_count),
BlockMode::Block => Count::Blocks(raw_count),
};
assert_eq!(Count::from_parts(mode, raw_count), Ok(exp_cnt));
assert_eq!(exp_cnt.into_parts(), (mode, raw_count));
});
});
let max_byte_cnt = Count::Bytes(Count::MAX_BYTES);
let max_block_cnt = Count::Infinite;
assert_eq!(Count::from_parts(BlockMode::Byte, 0), Ok(max_byte_cnt));
assert_eq!(max_byte_cnt.into_parts(), (BlockMode::Byte, 0));
assert_eq!(Count::from_parts(BlockMode::Block, 0), Ok(max_block_cnt));
assert_eq!(max_block_cnt.into_parts(), (BlockMode::Block, 0));
}
}