sdmmc-core 0.5.0

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

/// Represents the `addr` field of the [Argument](super::Argument).
///
/// The address space is split based on the `mio` field:
///
/// - [Memory](super::Mio::Memory) space
/// - [I/O](super::Mio::Io) space
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Address {
    /// Memory space address, range: 0-128KiB.
    Memory(usize),
    /// I/O space address, range: 0-128KiB.
    Io(usize),
}

impl Address {
    /// Represents the minimum address value.
    pub const MIN: usize = 0;
    /// Represents the maximum address value.
    pub const MAX: usize = 0x1ffff;

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

    /// Gets the memory address.
    ///
    /// # Note
    ///
    /// Only valid if the [Address] is set for the [Memory](Self::Memory) space.
    pub const fn memory(self) -> usize {
        match self {
            Self::Memory(addr) => addr,
            _ => 0,
        }
    }

    /// Gets the I/O address.
    ///
    /// # Note
    ///
    /// Only valid if the [Address] is set for the [I/O](Self::Io) space.
    pub const fn io(self) -> usize {
        match self {
            Self::Io(addr) => addr,
            _ => 0,
        }
    }

    /// Converts the component parts into an [Address].
    ///
    /// # Note
    ///
    /// Panics if `addr` is outside valid range: [Self::MIN] to [Self::MAX].
    pub const fn from_parts(mio: Mio, addr: usize) -> Self {
        match Self::try_from_parts(mio, addr) {
            Ok(addr) => addr,
            Err(_err) => panic!("command::arg::address: invalid field value, min: 0, max: 0x1ffff"),
        }
    }

    /// Attempts to convert the component parts into an [Address].
    ///
    /// # Note
    ///
    /// Returns an error if `addr` is outside valid range: [Self::MIN] to [Self::MAX].
    pub const fn try_from_parts(mio: Mio, addr: usize) -> Result<Self> {
        if addr > Self::MAX {
            Err(Error::invalid_field_value(
                "command::arg::address",
                addr,
                Self::MIN,
                Self::MAX,
            ))
        } else {
            match mio {
                Mio::Memory => Ok(Self::Memory(addr)),
                Mio::Io => Ok(Self::Io(addr)),
            }
        }
    }

    /// Converts the [Address] into component parts.
    pub const fn into_parts(self) -> (Mio, usize) {
        match self {
            Self::Memory(addr) => (Mio::Memory, addr),
            Self::Io(addr) => (Mio::Io, addr),
        }
    }
}

impl Default for Address {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_fields() {
        (1..=usize::BITS)
            .map(|r| ((1u128 << r) - 1) as usize)
            .for_each(|addr| match Address::try_from_parts(Mio::Memory, addr) {
                Ok(exp_addr) => {
                    let exp_mem = Address::Memory(addr);
                    let exp_io = Address::Io(addr);

                    assert_eq!(Address::try_from_parts(Mio::Memory, addr), Ok(exp_mem));
                    assert_eq!(Address::from_parts(Mio::Memory, addr), exp_mem);
                    assert_eq!(exp_mem.into_parts(), (Mio::Memory, addr));

                    assert_eq!(Address::try_from_parts(Mio::Io, addr), Ok(exp_io));
                    assert_eq!(Address::from_parts(Mio::Io, addr), exp_io);
                    assert_eq!(exp_io.into_parts(), (Mio::Io, addr));
                }
                Err(exp_err) => {
                    assert_eq!(Address::try_from_parts(Mio::Memory, addr), Err(exp_err));
                    assert_eq!(Address::try_from_parts(Mio::Io, addr), Err(exp_err));
                }
            });
    }
}