pub type Smaller<T> = <T as traits::Smaller>::T;
pub type Larger<T> = <T as traits::Larger>::T;
pub type SmallerSaturate<T> = <T as traits::SmallerSaturate>::T;
pub type LargerSaturate<T> = <T as traits::LargerSaturate>::T;
pub type SmallerCycle<T> = <T as traits::SmallerCycle>::T;
pub type LargerCycle<T> = <T as traits::LargerCycle>::T;
pub type Signed<T> = <T as traits::Signed>::T;
pub type Unsigned<T> = <T as traits::Unsigned>::T;
pub type Ptr<T> = <T as traits::Ptr>::T;
mod seal {
pub trait Sealed {}
macro_rules! impl_sealed {
($($T:ty)*) => {
$(impl Sealed for $T {})*
};
}
impl_sealed!(
u8 u16 u32 u64 u128
i8 i16 i32 i64 i128
f32 f64
usize isize
);
}
mod ptr {
#[cfg(target_pointer_width = "32")]
pub type Signed = i32;
#[cfg(target_pointer_width = "64")]
pub type Signed = i64;
pub type Unsigned = <Signed as super::traits::Unsigned>::T;
}
pub mod traits {
use super::seal::Sealed;
use super::ptr;
pub trait Smaller: Sealed {
type T;
}
pub trait Larger: Sealed {
type T;
}
pub trait SmallerSaturate: Sealed {
type T;
}
pub trait LargerSaturate: Sealed {
type T;
}
pub trait SmallerCycle: Sealed {
type T;
}
pub trait LargerCycle: Sealed {
type T;
}
pub trait Signed: Sealed {
type T;
}
pub trait Unsigned: Sealed {
type T;
}
pub trait Ptr: Sealed {
type T;
}
macro_rules! impl_smaller_larger {
($T:ty, $U:ty) => {
impl Larger for $T {
type T = $U;
}
impl LargerSaturate for $T {
type T = $U;
}
impl LargerCycle for $T {
type T = $U;
}
impl Smaller for $U {
type T = $T;
}
impl SmallerSaturate for $U {
type T = $T;
}
impl SmallerCycle for $U {
type T = $T;
}
};
(@bounds $Min:ty, $Max:ty) => {
impl SmallerSaturate for $Min {
type T = $Min;
}
impl SmallerCycle for $Min {
type T = $Max;
}
impl LargerSaturate for $Max {
type T = $Max;
}
impl LargerCycle for $Max {
type T = $Min;
}
};
}
impl_smaller_larger!(u8, u16);
impl_smaller_larger!(u16, u32);
impl_smaller_larger!(u32, u64);
impl_smaller_larger!(u64, u128);
impl_smaller_larger!(@bounds u8, u128);
impl_smaller_larger!(i8, i16);
impl_smaller_larger!(i16, i32);
impl_smaller_larger!(i32, i64);
impl_smaller_larger!(i64, i128);
impl_smaller_larger!(@bounds i8, i128);
impl_smaller_larger!(f32, f64);
impl_smaller_larger!(@bounds f32, f64);
macro_rules! impl_signed_unsigned {
($Signed:ty, $Unsigned:ty) => {
impl Signed for $Signed {
type T = $Signed;
}
impl Unsigned for $Unsigned {
type T = $Unsigned;
}
impl Signed for $Unsigned {
type T = $Signed;
}
impl Unsigned for $Signed {
type T = $Unsigned;
}
};
}
impl_signed_unsigned!(i8, u8);
impl_signed_unsigned!(i16, u16);
impl_signed_unsigned!(i32, u32);
impl_signed_unsigned!(i64, u64);
impl_signed_unsigned!(i128, u128);
macro_rules! impl_ptr {
($Ptr:ty, $T:ty) => {
impl Larger for $Ptr {
type T = <$T as Larger>::T;
}
impl LargerSaturate for $Ptr {
type T = <$T as LargerSaturate>::T;
}
impl LargerCycle for $Ptr {
type T = <$T as LargerCycle>::T;
}
impl Smaller for $Ptr {
type T = <$T as Smaller>::T;
}
impl SmallerSaturate for $Ptr {
type T = <$T as SmallerSaturate>::T;
}
impl SmallerCycle for $Ptr {
type T = <$T as SmallerCycle>::T;
}
impl Signed for $Ptr {
type T = <$T as Signed>::T;
}
impl Unsigned for $Ptr {
type T = <$T as Unsigned>::T;
}
};
}
impl_ptr!(isize, ptr::Signed);
impl_ptr!(usize, ptr::Unsigned);
impl Ptr for isize {
type T = ptr::Signed;
}
impl Ptr for usize {
type T = ptr::Unsigned;
}
}
#[cfg(test)]
mod tests {
use crate::type_eq;
use super::ptr;
use super::{
Larger, LargerCycle, LargerSaturate, Ptr, Signed, Smaller, SmallerCycle, SmallerSaturate,
Unsigned,
};
#[test]
fn smaller_larger() {
macro_rules! check {
($T:ty, $U:ty) => {
type_eq::<Larger<$T>, $U>();
type_eq::<LargerSaturate<$T>, $U>();
type_eq::<LargerCycle<$T>, $U>();
type_eq::<Smaller<$U>, $T>();
type_eq::<SmallerSaturate<$U>, $T>();
type_eq::<SmallerCycle<$U>, $T>();
};
(@bounds $Min:ty, $Max:ty) => {
type_eq::<SmallerSaturate<$Min>, $Min>();
type_eq::<SmallerCycle<$Min>, $Max>();
type_eq::<LargerSaturate<$Max>, $Max>();
type_eq::<LargerCycle<$Max>, $Min>();
};
}
check!(u8, u16);
check!(u16, u32);
check!(u32, u64);
check!(u64, u128);
check!(@bounds u8, u128);
check!(i8, i16);
check!(i16, i32);
check!(i32, i64);
check!(i64, i128);
check!(@bounds i8, i128);
check!(f32, f64);
check!(@bounds f32, f64);
}
#[test]
fn signed_unsigned() {
macro_rules! check {
($Signed:ty, $Unsigned:ty) => {
type_eq::<Signed<$Signed>, $Signed>();
type_eq::<Unsigned<$Unsigned>, $Unsigned>();
type_eq::<Signed<$Unsigned>, $Signed>();
type_eq::<Unsigned<$Signed>, $Unsigned>();
};
}
check!(i8, u8);
check!(i16, u16);
check!(i32, u32);
check!(i64, u64);
check!(i128, u128);
}
#[test]
fn ptr() {
macro_rules! check {
($Ptr:ty, $T:ty) => {
type_eq::<Ptr<$Ptr>, $T>();
type_eq::<Larger<$Ptr>, Larger<$T>>();
type_eq::<LargerSaturate<$Ptr>, LargerSaturate<$T>>();
type_eq::<LargerCycle<$Ptr>, LargerCycle<$T>>();
type_eq::<Smaller<$Ptr>, Smaller<$T>>();
type_eq::<SmallerSaturate<$Ptr>, SmallerSaturate<$T>>();
type_eq::<SmallerCycle<$Ptr>, SmallerCycle<$T>>();
type_eq::<Signed<$Ptr>, Signed<$T>>();
type_eq::<Unsigned<$Ptr>, Unsigned<$T>>();
};
}
check!(isize, ptr::Signed);
check!(usize, ptr::Unsigned);
}
}