use core::fmt::Debug;
pub trait Address: Copy + Default + Eq + Ord + Debug + 'static {
const BITS_LOG2: u8;
const MIN: Self;
const MAX: Self;
fn from_u64_wrap(n: u64) -> Self;
fn to_u64(self) -> u64;
fn to_usize_checked(self) -> Option<usize>;
}
macro_rules! impl_address {
($ty:ty, $bits_log2:expr) => {
impl Address for $ty {
const BITS_LOG2: u8 = $bits_log2;
const MIN: Self = <$ty>::MIN;
const MAX: Self = <$ty>::MAX;
fn from_u64_wrap(n: u64) -> Self {
n as $ty
}
fn to_u64(self) -> u64 {
self as u64
}
fn to_usize_checked(self) -> Option<usize> {
usize::try_from(self as u64).ok()
}
}
};
}
impl_address!(u8, 3);
impl_address!(u16, 4);
impl_address!(u32, 5);
impl_address!(u64, 6);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn u8_address_basics() {
assert_eq!(<u8 as Address>::BITS_LOG2, 3);
assert_eq!(<u8 as Address>::MAX, u8::MAX);
assert_eq!(<u8 as Address>::from_u64_wrap(0x1234), 0x34_u8);
assert_eq!(<u8 as Address>::to_u64(42_u8), 42_u64);
}
#[test]
fn u16_address_basics() {
assert_eq!(<u16 as Address>::BITS_LOG2, 4);
assert_eq!(<u16 as Address>::from_u64_wrap(0x12345), 0x2345_u16);
}
#[test]
fn u32_address_basics() {
assert_eq!(<u32 as Address>::BITS_LOG2, 5);
assert_eq!(<u32 as Address>::from_u64_wrap(0x1_0000_0001), 1_u32);
}
#[test]
fn u64_address_basics() {
assert_eq!(<u64 as Address>::BITS_LOG2, 6);
assert_eq!(<u64 as Address>::from_u64_wrap(0x1234), 0x1234_u64);
}
#[test]
fn to_usize_checked_succeeds_within_host_bounds() {
assert_eq!((42_u32).to_usize_checked(), Some(42_usize));
}
#[test]
fn bits_log2_matches_runtime_constant() {
assert_eq!(<u8 as Address>::BITS_LOG2, 3);
assert_eq!(<u16 as Address>::BITS_LOG2, 4);
assert_eq!(<u32 as Address>::BITS_LOG2, 5);
assert_eq!(<u64 as Address>::BITS_LOG2, 6);
}
}