sdmmc-core 0.5.0

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

macro_rules! range {
    ($range:ident, $range_ty:ident) => {
        ::paste::paste! {
            #[doc = "Represents ranged type over a bounded range of values."]
            #[derive(Clone, Copy, Debug, Eq, PartialEq)]
            pub struct $range<const MIN: $range_ty, const MAX: $range_ty>($range_ty);

            impl<const MIN: $range_ty, const MAX: $range_ty> $range<MIN, MAX> {
                #[doc = "Creates a new [" $range "]."]
                pub const fn new() -> Self {
                    Self(MIN)
                }

                /// Gets the minimum range value.
                pub const fn min() -> $range_ty {
                    MIN
                }

                /// Gets the maximum range value.
                pub const fn max() -> $range_ty {
                    MAX
                }

                #[doc = "Attempts to convert a raw index value into a [" $range "]."]
                pub const fn try_from_inner(val: $range_ty) -> Result<Self> {
                    if val >= MIN && val <= MAX {
                        Ok(Self(val))
                    } else {
                        Err(Error::invalid_field_value("range", val as usize, MIN as usize, MAX as usize))
                    }
                }

                #[doc = "Converts a raw index value into a [" $range "] with no bounds check."]
                #[doc = ""]
                #[doc = "# Panics"]
                #[doc = ""]
                #[doc = "Panics if the provided index is out-of-bounds."]
                #[doc = ""]
                #[doc = "Caller must ensure that the index is in the valid range."]
                pub const fn try_from_unchecked(val: $range_ty) -> Self {
                    match Self::try_from_inner(val) {
                        Ok(i) => i,
                        Err(_) => panic!("ranged value out-of-bounds"),
                    }
                }

                #[doc = "Converts a [" $range "] into a raw index value."]
                pub const fn into_inner(self) -> $range_ty {
                    self.0
                }
            }

            impl<const MIN: $range_ty, const MAX: $range_ty> Default for $range<MIN, MAX> {
                fn default() -> Self {
                    Self::new()
                }
            }

            impl<const MIN: $range_ty, const MAX: $range_ty> TryFrom<$range_ty> for $range<MIN, MAX> {
                type Error = Error;

                fn try_from(val: $range_ty) -> Result<Self> {
                    Self::try_from_inner(val)
                }
            }

            impl<const MIN: $range_ty, const MAX: $range_ty> From<$range<MIN, MAX>> for $range_ty {
                fn from(val: $range<MIN, MAX>) -> Self {
                    val.into_inner()
                }
            }

            #[cfg(test)]
            mod [<range_ $range_ty _tests>] {
                use super::*;

                #[test]
                fn test_range() {
                    const MIN: $range_ty = 1;
                    const MAX: $range_ty = $range_ty::MAX - 1;

                    type TestRange = $range<MIN, MAX>;

                    assert_eq!(TestRange::new().into_inner(), MIN);
                    assert_eq!(TestRange::default().into_inner(), MIN);

                    [MIN, MIN + 1, MAX - 1, MAX].into_iter().for_each(|index| {
                        let exp_index = TestRange::try_from(index).unwrap();

                        assert_eq!(TestRange::try_from_inner(index), Ok(exp_index));
                        assert_eq!(TestRange::try_from(index), Ok(exp_index));

                        assert_eq!(exp_index.into_inner(), index);
                        assert_eq!($range_ty::from(exp_index), index);
                    });

                    assert!(TestRange::try_from_inner(MIN - 1).is_err());
                    assert!(TestRange::try_from_inner(MAX + 1).is_err());
                }
            }
        }
    };
}

range!(RangeU8, u8);
range!(RangeU16, u16);
range!(RangeU32, u32);
range!(RangeU64, u64);
range!(RangeUsize, usize);

/// Convenience alias for a ranged index type.
pub type RangedIndex<const MIN: usize, const MAX: usize> = RangeUsize<MIN, MAX>;

range!(RangeI8, i8);
range!(RangeI16, i16);
range!(RangeI32, i32);
range!(RangeI64, i64);
range!(RangeIsize, isize);