pub trait RangeIndexKey: Copy + Eq + Ord {
const BITS: u32;
fn ordered_word(self) -> u64;
}
pub(super) struct OrderedWordOutsideWidth<Key> {
pub key: Key,
pub ordered_word: u64,
pub bits: u32,
}
pub(super) fn checked_ordered_word<Key: RangeIndexKey>(
key: Key,
) -> Result<u64, OrderedWordOutsideWidth<Key>> {
let ordered_word = key.ordered_word();
let fits =
Key::BITS == u64::BITS || ordered_word < 1_u64.checked_shl(Key::BITS).unwrap_or_default();
if fits {
Ok(ordered_word)
} else {
Err(OrderedWordOutsideWidth {
key,
ordered_word,
bits: Key::BITS,
})
}
}
macro_rules! unsigned_range_keys {
($($type:ty),+ $(,)?) => {
$(
impl RangeIndexKey for $type {
const BITS: u32 = <$type>::BITS;
fn ordered_word(self) -> u64 {
u64::from(self)
}
}
)+
};
}
macro_rules! signed_range_keys {
($(($signed:ty, $unsigned:ty)),+ $(,)?) => {
$(
impl RangeIndexKey for $signed {
const BITS: u32 = <$signed>::BITS;
fn ordered_word(self) -> u64 {
u64::from((self as $unsigned) ^ (<$signed>::MIN as $unsigned))
}
}
)+
};
}
unsigned_range_keys!(u8, u16, u32, u64);
signed_range_keys!((i8, u8), (i16, u16), (i32, u32), (i64, u64));