sdmmc-core 0.5.0

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

pub const OID_LEN: usize = 2;

/// Represents an 16-bit, 2-character ASCII OEM ID and/or card contents.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct OemId(u16);

impl OemId {
    /// Creates a new [OemId].
    pub const fn new() -> Self {
        Self(0)
    }

    /// Gets the bit value of the [OemId].
    pub const fn bits(&self) -> u16 {
        self.0
    }

    /// Converts the [OemId] into a byte array.
    pub const fn bytes(&self) -> [u8; OID_LEN] {
        self.0.to_be_bytes()
    }

    /// Attempts to convert a [`u16`] into a [OemId].
    pub const fn try_from_bits(val: u16) -> Result<Self> {
        match check_ascii(&val.to_be_bytes(), OID_LEN) {
            Ok(_) => Ok(Self(val)),
            Err(err) => Err(err),
        }
    }

    /// Attempts to convert a byte slice into a [OemId].
    pub const fn try_from_bytes(val: &[u8]) -> Result<Self> {
        match check_ascii(val, OID_LEN) {
            Ok(_) => Ok(Self(u16::from_be_bytes([val[0], val[1]]))),
            Err(err) => Err(err),
        }
    }
}

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

impl From<OemId> for u16 {
    fn from(val: OemId) -> Self {
        val.bits()
    }
}

impl From<OemId> for [u8; OID_LEN] {
    fn from(val: OemId) -> Self {
        val.bytes()
    }
}

impl TryFrom<u16> for OemId {
    type Error = Error;

    fn try_from(val: u16) -> Result<Self> {
        Self::try_from_bits(val)
    }
}

impl TryFrom<&[u8]> for OemId {
    type Error = Error;

    fn try_from(val: &[u8]) -> Result<Self> {
        Self::try_from_bytes(val)
    }
}

impl<const N: usize> TryFrom<[u8; N]> for OemId {
    type Error = Error;

    fn try_from(val: [u8; N]) -> Result<Self> {
        Self::try_from_bytes(val.as_ref())
    }
}

impl<const N: usize> TryFrom<&[u8; N]> for OemId {
    type Error = Error;

    fn try_from(val: &[u8; N]) -> Result<Self> {
        Self::try_from_bytes(val.as_ref())
    }
}

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

    #[test]
    fn test_valid() {
        (0..u16::MAX)
            .filter(|c| check_ascii(&c.to_be_bytes(), OID_LEN).is_ok())
            .for_each(|oid| {
                let raw_oid = oid.to_be_bytes();
                let exp_oid = OemId(oid);

                assert_eq!(OemId::try_from_bits(oid), Ok(exp_oid));
                assert_eq!(OemId::try_from_bytes(raw_oid.as_ref()), Ok(exp_oid));
                assert_eq!(OemId::try_from(raw_oid.as_ref()), Ok(exp_oid));
                assert_eq!(OemId::try_from(&raw_oid), Ok(exp_oid));
                assert_eq!(OemId::try_from(raw_oid), Ok(exp_oid));

                assert_eq!(u16::from(exp_oid), oid);
                assert_eq!(<[u8; OID_LEN]>::from(exp_oid), raw_oid);

                assert_eq!(exp_oid.bits(), oid);
                assert_eq!(exp_oid.bytes(), raw_oid);
            });
    }

    #[test]
    fn test_invalid() {
        (0..u16::MAX)
            .filter(|c| check_ascii(&c.to_be_bytes(), OID_LEN).is_err())
            .for_each(|oid| {
                let raw_oid = oid.to_be_bytes();
                let err = check_ascii(raw_oid.as_ref(), OID_LEN).map(|_| OemId::new());

                assert!(err.is_err());

                assert_eq!(OemId::try_from_bits(oid), err);
                assert_eq!(OemId::try_from_bytes(raw_oid.as_ref()), err);
                assert_eq!(OemId::try_from(raw_oid.as_ref()), err);
                assert_eq!(OemId::try_from(&raw_oid), err);
                assert_eq!(OemId::try_from(raw_oid), err);
            });
    }
}