use core::{
cmp::Ordering,
fmt::{self, Display},
ops::{AddAssign, SubAssign},
};
mod lt_private {
use core::{
fmt::Display,
ops::{AddAssign, SubAssign},
};
pub trait LengthTypeBase:
Copy
+ Send
+ Sync
+ Clone
+ PartialEq<usize>
+ PartialOrd<usize>
+ Eq
+ Ord
+ AddAssign<usize>
+ SubAssign<usize>
+ Display
{
const MAX: usize;
type U;
fn new(value: usize) -> Self;
fn checked_add_usize(&self, rhs: usize) -> Option<Self>;
fn next_power_of_two_or_max(&self) -> Self;
fn as_usize(&self) -> usize;
fn set(&mut self, val: usize);
}
}
use lt_private::LengthTypeBase;
pub trait LengthType: LengthTypeBase {}
macro_rules! length_type {
($(#[$outer:meta])* $N:ident, $U:ty) => {
$(#[$outer])*
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct $N($U);
impl PartialEq<usize> for $N {
#[inline]
fn eq(&self, other: &usize) -> bool {
return self.0 as usize == *other
}
}
impl PartialOrd<usize> for $N {
#[inline]
fn partial_cmp(&self, other: &usize) -> Option<Ordering> {
(self.0 as usize).partial_cmp(other)
}
}
impl LengthTypeBase for $N {
const MAX: usize = <$U>::MAX as usize;
type U = $U;
#[inline]
fn new(val: usize) -> $N {
debug_assert!(val <= Self::MAX);
$N(val as $U)
}
#[inline]
fn checked_add_usize(&self, rhs: usize) -> Option<Self> {
<$U>::try_from(rhs)
.ok()
.and_then(|v| self.0.checked_add(v))
.map(|u| $N(u))
}
#[inline]
fn next_power_of_two_or_max(&self) -> Self {
$N(self.0.checked_next_power_of_two().unwrap_or(<$U>::MAX))
}
#[inline]
fn as_usize(&self) -> usize {
self.0 as usize
}
#[inline]
fn set(&mut self, val: usize) {
debug_assert!(val <= Self::MAX);
self.0 = val as $U;
}
}
impl LengthType for $N {}
impl AddAssign<usize> for $N {
#[inline]
fn add_assign(&mut self, rhs: usize) {
debug_assert!((rhs <= <Self as LengthTypeBase>::MAX) &&
self.0.checked_add(rhs as $U).is_some());
self.0 += rhs as $U
}
}
impl SubAssign<usize> for $N {
#[inline]
fn sub_assign(&mut self, rhs: usize) {
debug_assert!(self.0 as usize >= rhs);
self.0 -= rhs as $U
}
}
impl Display for $N {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
Display::fmt(&(self.0 as $U), f)
}
}
};
}
length_type!(
U8,
u8
);
length_type!(
U16,
u16
);
length_type!(
U32,
u32
);
length_type!(
U64,
u64
);
length_type!(
Usize,
usize
);
#[cfg(all(test, feature = "std"))]
mod testing {
use super::*;
macro_rules! check_display {
($LT:expr, $C:literal) => {
let lt = $LT($C);
let s = format!("{}", lt);
assert_eq!(s, $C.to_string());
};
}
#[test]
fn test_display() {
check_display!(U8, 7);
check_display!(U16, 707);
check_display!(U32, 70707);
check_display!(U64, 7070707);
check_display!(Usize, 707070707);
}
}