#![allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
pub enum UnsignedNibbleValue {
_0 = 0x0,
_1 = 0x1,
_2 = 0x2,
_3 = 0x3,
_4 = 0x4,
_5 = 0x5,
_6 = 0x6,
_7 = 0x7,
_8 = 0x8,
_9 = 0x9,
_A = 0xa,
_B = 0xb,
_C = 0xc,
_D = 0xd,
_E = 0xe,
_F = 0xf,
}
impl UnsignedNibbleValue {
#[inline]
pub const fn signed_value(self) -> i8 {
let byte = self as u8;
let significand = byte >> 3;
let int = byte | (significand * 0xF0);
unsafe { core::mem::transmute(int) }
}
#[inline]
pub const fn get(self) -> u8 {
self as u8
}
}
macro_rules! nibble_try_from_impls {
($($int:ty),+) => {
$(
impl core::convert::TryFrom<$int> for crate::Nibble {
type Error = crate::NibbleTryFromIntError<$int>;
fn try_from(value: $int) -> Result<Self, Self::Error> {
let byte: u8 = value.try_into().map_err(|_| crate::NibbleTryFromIntError(value))?;
match Self::can_represent(byte) {
true => Ok(unsafe { Self::new_unchecked(byte) }),
false => Err(crate::NibbleTryFromIntError(value)),
}
}
}
)+
};
}
macro_rules! nibble_into_impls {
($($target:ty),+) => {
$(
impl core::convert::From<crate::Nibble> for $target {
fn from(value: crate::Nibble) -> Self {
value.get().into()
}
}
)+
};
}
macro_rules! nibble_try_into_impls {
($($target:ty),+) => {
$(
impl core::convert::TryFrom<crate::Nibble> for $target {
type Error = <$target as core::convert::TryFrom<u8>>::Error;
fn try_from(value: crate::Nibble) -> Result<Self, Self::Error> {
value.get().try_into()
}
}
)+
};
}
macro_rules! nibble_fmt_impls {
($($name:path),+) => {
$(
impl $name for crate::Nibble {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
<u8 as $name>::fmt(&self.get(), f)
}
}
)+
};
}
macro_rules! nibble_constants {
($($name:ident := $value:literal),+) => {
impl crate::Nibble {
$(
#[doc = concat!(stringify!($value), " as a [`Nibble`].")]
pub const $name: Self = unsafe { Self::new_unchecked($value) };
)+
}
};
}
macro_rules! nibble_bitshift_impls {
($($target:ty),+) => {
$(
impl core::ops::Shl<$target> for crate::Nibble {
type Output = Self;
fn shl(self, rhs: $target) -> Self::Output {
let byte = self.get() << rhs;
unsafe { Self::new_unchecked(byte & Self::BYTE_MASK) }
}
}
impl core::ops::ShlAssign<$target> for crate::Nibble {
fn shl_assign(&mut self, rhs: $target) {
let value = *self << rhs;
*self = value;
}
}
impl core::ops::Shr<$target> for crate::Nibble {
type Output = Self;
fn shr(self, rhs: $target) -> Self::Output {
let byte = self.get() >> rhs;
unsafe { Self::new_unchecked(byte & Self::BYTE_MASK) }
}
}
impl core::ops::ShrAssign<$target> for crate::Nibble {
fn shr_assign(&mut self, rhs: $target) {
let value = *self >> rhs;
*self = value;
}
}
)+
};
}
macro_rules! nibble_rhs_bitshift_impls {
($($target:ty),+) => {
$(
impl core::ops::Shl<crate::Nibble> for $target {
type Output = Self;
fn shl(self, rhs: crate::Nibble) -> Self::Output {
self << rhs.get()
}
}
impl core::ops::Shr<crate::Nibble> for $target {
type Output = Self;
fn shr(self, rhs: crate::Nibble) -> Self::Output {
self >> rhs.get()
}
}
)+
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unsigned_nibble_value_is_byte_width() {
assert_eq!(core::mem::size_of::<UnsignedNibbleValue>(), 1);
}
#[test]
fn unsigned_nibble_value_to_signed_value_is_correct() {
assert_eq!(UnsignedNibbleValue::_0.signed_value(), 0);
assert_eq!(UnsignedNibbleValue::_1.signed_value(), 1);
assert_eq!(UnsignedNibbleValue::_2.signed_value(), 2);
assert_eq!(UnsignedNibbleValue::_3.signed_value(), 3);
assert_eq!(UnsignedNibbleValue::_4.signed_value(), 4);
assert_eq!(UnsignedNibbleValue::_5.signed_value(), 5);
assert_eq!(UnsignedNibbleValue::_6.signed_value(), 6);
assert_eq!(UnsignedNibbleValue::_7.signed_value(), 7);
assert_eq!(UnsignedNibbleValue::_8.signed_value(), -8);
assert_eq!(UnsignedNibbleValue::_9.signed_value(), -7);
assert_eq!(UnsignedNibbleValue::_A.signed_value(), -6);
assert_eq!(UnsignedNibbleValue::_B.signed_value(), -5);
assert_eq!(UnsignedNibbleValue::_C.signed_value(), -4);
assert_eq!(UnsignedNibbleValue::_D.signed_value(), -3);
assert_eq!(UnsignedNibbleValue::_E.signed_value(), -2);
assert_eq!(UnsignedNibbleValue::_F.signed_value(), -1);
}
}