pub trait SaturatingCast<T> {
fn saturating_cast(self) -> T;
}
macro_rules! trnc_up {
($src:ty as $($dst:ty),+) => {
$(impl SaturatingCast<$dst> for $src {
fn saturating_cast(self) -> $dst {
self as $dst
}
})+
}
}
trnc_up!(u8 as u8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize);
trnc_up!(i8 as i8, i16, i32, i64, i128, isize);
trnc_up!(u16 as u16, u32, i32, u64, i64, u128, i128, usize, isize);
trnc_up!(i16 as i16, i32, i64, i128, isize);
trnc_up!(u32 as u32, u64, i64, u128, i128, usize);
trnc_up!(i32 as i32, i64, i128, isize);
trnc_up!(u64 as u64, u128, i128);
trnc_up!(i64 as i64, i128);
trnc_up!(u128 as u128);
trnc_up!(i128 as i128);
trnc_up!(usize as u64, u128, i128, usize);
trnc_up!(isize as i64, i128, isize);
#[cfg(target_pointer_width = "64")]
trnc_up!(u64 as usize);
#[cfg(target_pointer_width = "64")]
trnc_up!(i64 as isize);
#[cfg(target_pointer_width = "32")]
trnc_up!(usize as u32);
#[cfg(target_pointer_width = "32")]
trnc_up!(isize as i32);
macro_rules! trnc_s2u_up {
($src:ty as $($dst:ty),+) => {
$(impl SaturatingCast<$dst> for $src {
fn saturating_cast(self) -> $dst {
if self >= 0 {
self as $dst
} else {
0
}
}
})+
}
}
trnc_s2u_up!(i8 as u8, u16, u32, u64, u128, usize);
trnc_s2u_up!(i16 as u16, u32, u64, u128, usize);
trnc_s2u_up!(i32 as u32, u64, u128, usize);
trnc_s2u_up!(i64 as u64, u128);
trnc_s2u_up!(i128 as u128);
trnc_s2u_up!(isize as usize, u128);
#[cfg(target_pointer_width = "64")]
trnc_s2u_up!(i64 as usize);
#[cfg(target_pointer_width = "32")]
trnc_s2u_up!(isize as u32);
macro_rules! trnc_s_down {
($src:ty as $($dst:ident),+) => {
$(impl SaturatingCast<$dst> for $src {
fn saturating_cast(self) -> $dst {
if self > $dst::max_value() as $src {
$dst::max_value()
} else if self < $dst::min_value() as $src {
$dst::min_value()
} else {
self as $dst
}
}
})+
}
}
trnc_s_down!(i16 as u8, i8);
trnc_s_down!(i32 as u8, i8, u16, i16);
trnc_s_down!(i64 as u8, i8, u16, i16, u32, i32);
trnc_s_down!(i128 as u8, i8, u16, i16, u32, i32, i64, usize, isize);
trnc_s_down!(isize as u8, i8, u16, i16);
#[cfg(target_pointer_width = "64")]
trnc_s_down!(isize as u32, i32);
#[cfg(target_pointer_width = "32")]
trnc_s_down!(i64 as usize, isize);
macro_rules! trnc_u_down {
($src:ty as $($dst:ident),+) => {
$(impl SaturatingCast<$dst> for $src {
fn saturating_cast(self) -> $dst {
if self > $dst::max_value() as $src {
$dst::max_value()
} else {
self as $dst
}
}
})+
}
}
trnc_u_down!(u16 as i8, u8, i16);
trnc_u_down!(u32 as i8, u8, i16, u16, i32);
trnc_u_down!(u64 as i8, u8, i16, u16, i32, u32, i64);
trnc_u_down!(u128 as i8, u8, i16, u16, i32, u32, i64, u64, i128, usize, isize);
trnc_u_down!(usize as i8, u8, i16, u16, i32);
#[cfg(target_pointer_width = "64")]
trnc_u_down!(usize as u32, i64);
#[cfg(target_pointer_width = "32")]
trnc_u_down!(u64 as isize, usize);