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 PRODUCT_NAME_LEN: usize = 5;

/// Represents the product name as a 5-character ASCII string.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ProductName {
    name: [u8; PRODUCT_NAME_LEN],
}

impl ProductName {
    /// Creates a new [ProductName].
    pub const fn new() -> Self {
        Self {
            name: [0; PRODUCT_NAME_LEN],
        }
    }

    /// Gets a reference to the name of the [ProductName].
    pub const fn name(&self) -> &[u8] {
        &self.name
    }

    /// Converts a [ProductName] into a byte array.
    pub const fn bytes(self) -> [u8; PRODUCT_NAME_LEN] {
        self.name
    }

    /// Attempts to convert a byte slice into a [ProductName].
    pub const fn try_from_bytes(val: &[u8]) -> Result<Self> {
        match check_ascii(val, PRODUCT_NAME_LEN) {
            Ok(_) => Ok(Self {
                name: [val[0], val[1], val[2], val[3], val[4]],
            }),
            Err(err) => Err(err),
        }
    }
}

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

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

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

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

impl<const N: usize> TryFrom<[u8; N]> for ProductName {
    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 ProductName {
    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..=u8::MAX)
            .filter(|&c| (c as char).is_ascii())
            .for_each(|c| {
                let name = [c; PRODUCT_NAME_LEN];
                let exp_name = ProductName { name };

                assert_eq!(ProductName::try_from_bytes(name.as_ref()), Ok(exp_name));
                assert_eq!(ProductName::try_from(name.as_ref()), Ok(exp_name));
                assert_eq!(ProductName::try_from(name), Ok(exp_name));

                assert_eq!(exp_name.bytes(), name);
                assert_eq!(exp_name.name(), name.as_ref());
            });
    }

    #[test]
    fn test_invalid() {
        (0..=u8::MAX)
            .filter(|&c| !(c as char).is_ascii())
            .for_each(|c| {
                let name = [c; PRODUCT_NAME_LEN];

                assert_eq!(
                    ProductName::try_from_bytes(name.as_ref()),
                    Err(Error::InvalidVariant(c as usize))
                );
                assert_eq!(
                    ProductName::try_from(name.as_ref()),
                    Err(Error::InvalidVariant(c as usize))
                );
                assert_eq!(
                    ProductName::try_from(name),
                    Err(Error::InvalidVariant(c as usize))
                );
            });
    }
}