pipecircuit 0.0.3

Correct. Robust. Fast. Portable.
Documentation
/// Maps a totally ordered value into an unsigned word with the same ordering.
///
/// Implementations must return a word confined to `BITS` low bits. Distinct
/// values must map to distinct words, and `left < right` must imply
/// `left.ordered_word() < right.ordered_word()`.
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));