use thiserror::Error;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
#[repr(u8)]
enum AllowedIndexValue {
_00,
_01,
_02,
_03,
_04,
_05,
_06,
_07,
_08,
_09,
_0A,
_0B,
_0C,
_0D,
_0E,
_0F,
_10,
_11,
_12,
_13,
_14,
_15,
_16,
_17,
_18,
_19,
_1A,
_1B,
_1C,
_1D,
_1E,
_1F,
_20,
_21,
_22,
_23,
_24,
_25,
_26,
_27,
_28,
_29,
_2A,
_2B,
_2C,
_2D,
_2E,
_2F,
_30,
_31,
_32,
_33,
_34,
_35,
_36,
_37,
_38,
_39,
_3A,
_3B,
_3C,
_3D,
_3E,
_3F,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
#[repr(transparent)]
pub struct Index(AllowedIndexValue);
#[derive(Debug, Error)]
#[error("Attempted to construct an Index with a value greater than 63.")]
pub struct InvalidIndexError;
impl TryFrom<u8> for Index {
type Error = InvalidIndexError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match Self::is_valid_index(value) {
true => Ok(unsafe { Self::new_unchecked(value) }),
false => Err(InvalidIndexError),
}
}
}
impl From<Index> for u8 {
fn from(value: Index) -> Self {
value.get()
}
}
impl Index {
pub const MIN: Self = Index(AllowedIndexValue::_00);
pub const MAX: Self = Index(AllowedIndexValue::_3F);
pub const fn get(&self) -> u8 {
self.0 as u8
}
pub const unsafe fn new_unchecked(value: u8) -> Self {
debug_assert!(value < 64);
unsafe { std::mem::transmute(value) }
}
#[inline(always)]
pub const fn is_valid_index(value: u8) -> bool {
(value & 0b11000000) == 0u8
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn index_is_byte_width() {
assert_eq!(std::mem::size_of::<Index>(), 1);
}
#[test]
fn niche_value_optimisation_applies_to_index() {
assert_eq!(
std::mem::size_of::<Option<Index>>(),
std::mem::size_of::<Index>()
)
}
}