sdmmc-core 0.5.0

SD/MMC core data structures and algorithms
Documentation
use super::BlockMode;
use crate::result::{Error, Result};

/// Represents the `byte/block count` field of the [Argument](super::Argument).
#[repr(u16)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Count {
    /// Represents the bytes transferred.
    Bytes(u16),
    /// Represents the blocks transferred.
    Blocks(u16),
    /// Represents an infinite number of blocks transferred until an `I/O abort` is sent.
    Infinite,
}

impl Count {
    /// Represents the minimal count value.
    pub const MIN: u16 = 1;
    /// Represents the maximal count value (other than special value assigned to zero).
    pub const MAX: u16 = 511;
    /// Represents the maximum byte count indicated by zero in the raw value.
    pub const MAX_BYTES: u16 = 512;

    /// Creates a new [Count].
    pub const fn new() -> Self {
        Self::Bytes(Self::MIN)
    }

    /// Attempts to convert component parts into a [Count].
    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)),
        }
    }

    /// Converts the component parts into a [Count].
    ///
    /// # Safety
    ///
    /// User must verify that `val` is in the valid range: `0 - 511`.
    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),
        }
    }

    /// Converts the [Count] into component parts.
    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));
    }
}