use super::bool::{Bool, Present, Absent};
#[macro_export]
macro_rules! for_each_nibble {
($mac:ident) => {
$mac!(X0); $mac!(X1); $mac!(X2); $mac!(X3);
$mac!(X4); $mac!(X5); $mac!(X6); $mac!(X7);
$mac!(X8); $mac!(X9); $mac!(XA); $mac!(XB);
$mac!(XC); $mac!(XD); $mac!(XE); $mac!(XF);
};
}
#[macro_export]
macro_rules! for_each_nibble_pair {
($mac:ident) => {
$mac!(X0, N0); $mac!(X1, N1); $mac!(X2, N2); $mac!(X3, N3);
$mac!(X4, N4); $mac!(X5, N5); $mac!(X6, N6); $mac!(X7, N7);
$mac!(X8, N8); $mac!(X9, N9); $mac!(XA, NA); $mac!(XB, NB);
$mac!(XC, NC); $mac!(XD, ND); $mac!(XE, NE); $mac!(XF, NF);
};
}
#[macro_export]
macro_rules! for_distinct_pairs {
($mac:ident) => {
$crate::for_distinct_pairs!(@recurse $mac, [X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, XA, XB, XC, XD, XE, XF]);
};
(@recurse $mac:ident, [$head:ident, $($tail:ident),*]) => {
$(
$mac!($head, $tail);
$mac!($tail, $head);
)*
$crate::for_distinct_pairs!(@recurse $mac, [$($tail),*]);
};
(@recurse $mac:ident, [$last:ident]) => {};
}
pub trait Nibble: 'static {}
macro_rules! define_nibble {
($n:ident) => {
pub struct $n;
impl Nibble for $n {}
};
}
for_each_nibble!(define_nibble);
pub trait ToNibble {
type Out: Nibble;
}
pub struct Map<const N: u8>;
impl ToNibble for Map<0> { type Out = X0; }
impl ToNibble for Map<1> { type Out = X1; }
impl ToNibble for Map<2> { type Out = X2; }
impl ToNibble for Map<3> { type Out = X3; }
impl ToNibble for Map<4> { type Out = X4; }
impl ToNibble for Map<5> { type Out = X5; }
impl ToNibble for Map<6> { type Out = X6; }
impl ToNibble for Map<7> { type Out = X7; }
impl ToNibble for Map<8> { type Out = X8; }
impl ToNibble for Map<9> { type Out = X9; }
impl ToNibble for Map<10> { type Out = XA; }
impl ToNibble for Map<11> { type Out = XB; }
impl ToNibble for Map<12> { type Out = XC; }
impl ToNibble for Map<13> { type Out = XD; }
impl ToNibble for Map<14> { type Out = XE; }
impl ToNibble for Map<15> { type Out = XF; }
pub trait NibbleEq<Other: Nibble>: Nibble {
type Out: Bool;
}
macro_rules! impl_eq_self {
($($n:ident),*) => { $(impl NibbleEq<$n> for $n { type Out = Present; })* };
}
impl_eq_self!(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, XA, XB, XC, XD, XE, XF);
macro_rules! impl_neq { ($a:ident, $b:ident) => { impl NibbleEq<$b> for $a { type Out = Absent; } }; }
for_distinct_pairs!(impl_neq);
pub trait HexAnd<Other: Nibble>: Nibble { type Out: Nibble; }
macro_rules! hex_and_table {
($($row:ident => [$($val:ident),*]),* $(,)?) => {
$(
hex_and_table!(@impl $row, [$($val),*], [X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, XA, XB, XC, XD, XE, XF]);
)*
};
(@impl $row:ident, [$($val:ident),*], [$($col:ident),*]) => {
$(impl HexAnd<$col> for $row { type Out = $val; })*
};
}
hex_and_table! {
X0 => [ X0, X0, X0, X0, X0, X0, X0, X0, X0, X0, X0, X0, X0, X0, X0, X0 ],
X1 => [ X0, X1, X0, X1, X0, X1, X0, X1, X0, X1, X0, X1, X0, X1, X0, X1 ],
X2 => [ X0, X0, X2, X2, X0, X0, X2, X2, X0, X0, X2, X2, X0, X0, X2, X2 ],
X3 => [ X0, X1, X2, X3, X0, X1, X2, X3, X0, X1, X2, X3, X0, X1, X2, X3 ],
X4 => [ X0, X0, X0, X0, X4, X4, X4, X4, X0, X0, X0, X0, X4, X4, X4, X4 ],
X5 => [ X0, X1, X0, X1, X4, X5, X4, X5, X0, X1, X0, X1, X4, X5, X4, X5 ],
X6 => [ X0, X0, X2, X2, X4, X4, X6, X6, X0, X0, X2, X2, X4, X4, X6, X6 ],
X7 => [ X0, X1, X2, X3, X4, X5, X6, X7, X0, X1, X2, X3, X4, X5, X6, X7 ],
X8 => [ X0, X0, X0, X0, X0, X0, X0, X0, X8, X8, X8, X8, X8, X8, X8, X8 ],
X9 => [ X0, X1, X0, X1, X0, X1, X0, X1, X8, X9, X8, X9, X8, X9, X8, X9 ],
XA => [ X0, X0, X2, X2, X0, X0, X2, X2, X8, X8, XA, XA, X8, X8, XA, XA ],
XB => [ X0, X1, X2, X3, X0, X1, X2, X3, X8, X9, XA, XB, X8, X9, XA, XB ],
XC => [ X0, X0, X0, X0, X4, X4, X4, X4, X8, X8, X8, X8, XC, XC, XC, XC ],
XD => [ X0, X1, X0, X1, X4, X5, X4, X5, X8, X9, X8, X9, XC, XD, XC, XD ],
XE => [ X0, X0, X2, X2, X4, X4, X6, X6, X8, X8, XA, XA, XC, XC, XE, XE ],
XF => [ X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, XA, XB, XC, XD, XE, XF ],
}