sdmmc-core 0.5.0

SD/MMC core data structures and algorithms
Documentation
/// Convenience macro to define a library enum.
#[macro_export]
macro_rules! lib_enum {
    (
        $(#[$enum_meta:meta])+
        $enum_ty:ident: $base_ty:ident {
            default: $default_variant:ident,
            error: $err_ty:ident,
            $(
                $(#[$var_doc:meta])*
                $variant:ident = $value:literal$(,)?
            )+
        }
    ) => {
        paste::paste! {
            $(#[$enum_meta])+
            #[repr($base_ty)]
            #[derive(Clone, Copy, Debug, Eq, PartialEq)]
            pub enum $enum_ty {
                $(
                    $(#[$var_doc])*
                    $variant = $value,
                )+
            }

            impl $enum_ty {
                #[doc = "Creates a new [" $enum_ty "]."]
                pub const fn new() -> Self {
                    Self::$default_variant
                }

                #[doc = "Converts a [`" $base_ty "`] into a [" $enum_ty "]."]
                #[doc = ""]
                #[doc = "# Panics"]
                #[doc = ""]
                #[doc = "Panics if the passed value is an invalid variant"]
                pub const fn from_raw_unchecked(val: $base_ty) -> Self {
                    match Self::from_raw(val) {
                        Ok(v) => v,
                        Err(err) => panic!("invalid variant"),
                    }
                }

                #[doc = "Attempts to convert a [`" $base_ty "`] into a [" $enum_ty "]."]
                pub const fn from_raw(val: $base_ty) -> ::core::result::Result<Self, $err_ty> {
                    match val {
                        $(
                            $value => Ok(Self::$variant),
                        )+
                        _ => Err($err_ty::InvalidVariant(val as usize)),
                    }
                }

                #[doc = "Converts a [" $enum_ty "] into a [`" $base_ty "`]."]
                pub const fn into_raw(self) -> $base_ty {
                    self as $base_ty
                }
            }

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

            impl TryFrom<$base_ty> for $enum_ty {
                type Error = $err_ty;

                fn try_from(val: $base_ty) -> ::core::result::Result<Self, Self::Error> {
                    Self::from_raw(val)
                }
            }

            impl From<$enum_ty> for $base_ty {
                fn from(val: $enum_ty) -> Self {
                    val.into_raw()
                }
            }

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

                #[test]
                fn test_variants() {
                    let raw = [
                        $($value,)+
                    ];

                    let exp = [
                        $($enum_ty::$variant,)+
                    ];

                    raw.into_iter().zip(exp).for_each(|(r, e)| {
                        assert_eq!($enum_ty::from_raw(r), Ok(e));
                        assert_eq!($enum_ty::try_from(r), Ok(e));

                        assert_eq!(e.into_raw(), r);
                        assert_eq!($base_ty::from(e), r);
                    });
                }

                #[test]
                fn test_invalid_variants() {
                    let raw = [
                        $($value,)+
                    ];

                    // set the upper limit to be at most 10-bits wide (1023 = 0x3ff)
                    let upper = match $base_ty::BITS {
                        128 | 64 | 32 | 16 => $base_ty::MAX >> ($base_ty::BITS - 10),
                        _ => $base_ty::MAX,
                    };

                    (0..=upper).chain([$base_ty::MAX]).filter(|r| !raw.iter().any(|v| v == r)).for_each(|r| {
                        assert_eq!($enum_ty::from_raw(r), Err($err_ty::InvalidVariant(r as usize)));
                        assert_eq!($enum_ty::try_from(r), Err($err_ty::InvalidVariant(r as usize)));
                    });
                }
            }
        }
    };
}

/// Convenience macro to define a library boolean enum.
#[macro_export]
macro_rules! lib_bool_enum {
    (
        $(#[$enum_meta:meta])+
        $enum_ty:ident {
            $(#[$false_var_doc:meta])*
            $false_variant:ident = false,
            $(#[$true_var_doc:meta])*
            $true_variant:ident = true,
        }
    ) => {
        paste::paste! {
            $(#[$enum_meta])+
            #[repr(u8)]
            #[derive(Clone, Copy, Debug, Eq, PartialEq)]
            pub enum $enum_ty {
                $(#[$false_var_doc])+
                $false_variant = 0,
                $(#[$true_var_doc])+
                $true_variant = 1,
            }

            impl $enum_ty {
                #[doc = "Creates a new [" $enum_ty "]."]
                pub const fn new() -> Self {
                    Self::$false_variant
                }

                #[doc = "Attempts to convert a [`bool`] into a [" $enum_ty "]."]
                pub const fn from_bool(val: bool) -> Self {
                    match val {
                        false => Self::$false_variant,
                        true => Self::$true_variant,
                    }
                }

                #[doc = "Converts a [" $enum_ty "] into a [`bool`]."]
                pub const fn into_bool(self) -> bool {
                    match self {
                        Self::$false_variant => false,
                        Self::$true_variant => true,
                    }
                }

                #[doc = " Attempts to convert a [`u8`] into a [" $enum_ty "]."]
                pub const fn try_from_u8(val: u8) -> $crate::result::Result<Self> {
                    match val {
                        0 => Ok(Self::$false_variant),
                        1 => Ok(Self::$true_variant),
                        _ => Err($crate::result::Error::invalid_field_variant(stringify!($enum_ty), val as usize)),
                    }
                }

                #[doc = "Converts a [" $enum_ty "] into a [`u8`]."]
                pub const fn into_u8(self) -> u8 {
                    self as u8
                }
            }

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

            impl From<bool> for $enum_ty {
                fn from(val: bool) -> Self {
                    Self::from_bool(val)
                }
            }

            impl From<$enum_ty> for bool {
                fn from(val: $enum_ty) -> Self {
                    val.into_bool()
                }
            }

            impl TryFrom<u8> for $enum_ty {
                type Error = $crate::result::Error;

                fn try_from(val: u8) -> ::core::result::Result<Self, Self::Error> {
                    Self::try_from_u8(val)
                }
            }

            impl From<$enum_ty> for u8 {
                fn from(val: $enum_ty) -> Self {
                    val.into_u8()
                }
            }

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

                #[test]
                fn test_variants() {
                    let raw = [0, 1];

                    let exp = [$enum_ty::$false_variant, $enum_ty::$true_variant];

                    raw.into_iter().zip(exp).for_each(|(r, e)| {
                        let raw_bool = r != 0;

                        assert_eq!($enum_ty::from_bool(raw_bool), e);
                        assert_eq!($enum_ty::from(raw_bool), e);

                        assert_eq!($enum_ty::try_from_u8(r), Ok(e));
                        assert_eq!($enum_ty::try_from(r), Ok(e));

                        assert_eq!(e.into_bool(), raw_bool);
                        assert_eq!(bool::from(e), raw_bool);

                        assert_eq!(e.into_u8(), r);
                        assert_eq!(u8::from(e), r);
                    });
                }

                #[test]
                fn test_invalid_variants() {
                    (2..=u8::MAX).for_each(|r| {
                        let exp_err = $crate::result::Error::invalid_field_variant(stringify!($enum_ty), r as usize);
                        assert_eq!($enum_ty::try_from_u8(r), Err(exp_err));
                        assert_eq!($enum_ty::try_from(r), Err(exp_err));
                    });
                }
            }
        }
    };
}