struct Choice<const C: bool>;
trait Impl<T> {
type Inner;
}
macro_rules! lossless_integer {
(
$(#[$attr:meta])*
$sizet:ident $str_name:literal
pub struct $name:ident ($under:ty)
) => {
impl Impl<$name> for Choice<true> {
type Inner = $under;
}
impl Impl<$name> for Choice<false> {
type Inner = $sizet;
}
$(#[$attr])*
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct $name(
<
Choice<{core::mem::size_of::<$under>() < core::mem::size_of::<$sizet>()}>
as Impl<$name>
>::Inner
);
impl $name {
#[doc = $str_name]
pub fn new(val: $under) -> Option<Self> {
if <$sizet as core::convert::TryFrom<_>>::try_from(val).is_ok() {
Some($name(val as _))
} else {
None
}
}
#[doc = $str_name]
pub fn get(self) -> $sizet {
self.0 as $sizet
}
pub fn into_inner(self) -> $under {
self.0 as $under
}
}
impl From<$name> for $sizet {
fn from(val: $name) -> $sizet {
val.get()
}
}
impl From<$name> for $under {
fn from(val: $name) -> $under {
val.into_inner()
}
}
impl PartialEq<$under> for $name {
fn eq(&self, other: &$under) -> bool {
self.into_inner() == *other
}
}
impl PartialEq<$name> for $under {
fn eq(&self, other: &$name) -> bool {
*self == other.into_inner()
}
}
impl PartialEq<$sizet> for $name {
fn eq(&self, other: &$sizet) -> bool {
self.get() == *other
}
}
impl PartialEq<$name> for $sizet {
fn eq(&self, other: &$name) -> bool {
*self == other.get()
}
}
impl PartialOrd<$under> for $name {
fn partial_cmp(&self, other: &$under) -> Option<core::cmp::Ordering> {
self.into_inner().partial_cmp(other)
}
}
impl PartialOrd<$name> for $under {
fn partial_cmp(&self, other: &$name) -> Option<core::cmp::Ordering> {
self.partial_cmp(&other.into_inner())
}
}
impl PartialOrd<$sizet> for $name {
fn partial_cmp(&self, other: &$sizet) -> Option<core::cmp::Ordering> {
self.get().partial_cmp(other)
}
}
impl PartialOrd<$name> for $sizet {
fn partial_cmp(&self, other: &$name) -> Option<core::cmp::Ordering> {
self.partial_cmp(&other.get())
}
}
impl core::fmt::Display for $name {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
self.get().fmt(f)
}
}
};
}
macro_rules! integer_mem {
($(#[$attr:meta])* pub struct $name:ident ($under:ty)) => {
lossless_integer!($(#[$attr])*
usize "usize"
pub struct $name ($under));
impl<T> core::ops::Index<$name> for [T] {
type Output = T;
fn index(&self, idx: $name) -> &Self::Output {
&self[idx.get()]
}
}
}
}
macro_rules! integer_diff {
($(#[$attr:meta])* pub struct $name:ident ($under:ty)) => {
lossless_integer!($(#[$attr])*
isize "isize"
pub struct $name ($under));
}
}
integer_mem!(
pub struct Imem8(i8)
);
integer_mem!(
pub struct Umem8(u8)
);
integer_mem!(
pub struct Imem16(i16)
);
integer_mem!(
pub struct Umem16(u16)
);
integer_mem!(
pub struct Imem32(i32)
);
integer_mem!(
pub struct Umem32(u32)
);
integer_mem!(
pub struct Imem64(i64)
);
integer_mem!(
pub struct Umem64(u64)
);
integer_mem!(
pub struct Imem128(i128)
);
integer_mem!(
pub struct Umem128(u128)
);
integer_mem!(
pub struct Imem(isize)
);
integer_diff!(
pub struct Idiff8(i8)
);
integer_diff!(
pub struct Udiff8(u8)
);
integer_diff!(
pub struct Idiff16(i16)
);
integer_diff!(
pub struct Udiff16(u16)
);
integer_diff!(
pub struct Idiff32(i32)
);
integer_diff!(
pub struct Udiff32(u32)
);
integer_diff!(
pub struct Idiff64(i64)
);
integer_diff!(
pub struct Udiff64(u64)
);
integer_diff!(
pub struct Udiff(usize)
);
integer_diff!(
pub struct Idiff128(i128)
);
integer_diff!(
pub struct Udiff128(u128)
);
#[test]
fn mem_128_operations() {
let x = Umem128::new(16).unwrap();
assert!(x == x);
assert!(x <= x);
assert!(x <= 16u128);
assert!(16u128 <= x);
assert!(x == 16u128);
assert!(16u128 == x);
assert!(x <= 16usize);
assert!(16usize <= x);
assert!(x == 16usize);
assert!(16usize == x);
}
#[cfg(feature = "alloc")]
#[test]
fn fmt_128() {
let x = Umem128::new(16).unwrap();
assert!(alloc::format!("{x}") == "16");
}