use crate::result::{Error, Result};
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RangedIndex<const MIN: usize, const MAX: usize>(usize);
impl<const MIN: usize, const MAX: usize> RangedIndex<MIN, MAX> {
pub const fn new() -> Self {
Self(MIN)
}
pub const fn min() -> usize {
MIN
}
pub const fn max() -> usize {
MAX
}
pub const fn try_from_inner(val: usize) -> Result<Self> {
if val >= MIN && val <= MAX {
Ok(Self(val))
} else {
Err(Error::invalid_field_value("index", val, MIN, MAX))
}
}
pub const fn try_from_unchecked(val: usize) -> Self {
match Self::try_from_inner(val) {
Ok(i) => i,
Err(_) => panic!("ranged index out-of-bounds"),
}
}
pub const fn into_inner(self) -> usize {
self.0
}
}
impl<const MIN: usize, const MAX: usize> Default for RangedIndex<MIN, MAX> {
fn default() -> Self {
Self::new()
}
}
impl<const MIN: usize, const MAX: usize> TryFrom<usize> for RangedIndex<MIN, MAX> {
type Error = Error;
fn try_from(val: usize) -> Result<Self> {
Self::try_from_inner(val)
}
}
impl<const MIN: usize, const MAX: usize> From<RangedIndex<MIN, MAX>> for usize {
fn from(val: RangedIndex<MIN, MAX>) -> Self {
val.into_inner()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ranged_index() {
const MIN: usize = 1;
const MAX: usize = 256;
type TestIndex = RangedIndex<MIN, MAX>;
assert_eq!(TestIndex::new().into_inner(), MIN);
assert_eq!(TestIndex::default().into_inner(), MIN);
(MIN..=MAX).for_each(|index| {
let exp_index = TestIndex::try_from(index).unwrap();
assert_eq!(TestIndex::try_from_inner(index), Ok(exp_index));
assert_eq!(TestIndex::try_from(index), Ok(exp_index));
assert_eq!(exp_index.into_inner(), index);
assert_eq!(usize::from(exp_index), index);
});
}
}