Skip to content

Instantly share code, notes, and snippets.

@kathampy
Last active October 23, 2019 17:19
Show Gist options
  • Save kathampy/b988118d555c5ccd0f7e64ae2d3f48db to your computer and use it in GitHub Desktop.
Save kathampy/b988118d555c5ccd0f7e64ae2d3f48db to your computer and use it in GitHub Desktop.
Saturating Casts
/*
From https://github.com/rust-lang/rust/issues/23596
128-bit support
More usize & isize conversions
Lossless conversion between usize & isize <-> integers
Inlined functions
Removed self-casts and primitives with From<T> implementations
Note: usize & isize conversions valid on 32-bit & 64-bit word sizes.
*/
pub trait PointerCast<T> {
fn pointer_cast(self) -> T;
}
pub trait SaturatingCast<T> {
fn saturating_cast(self) -> T;
}
// Pointer casts that are lossless
macro_rules! cast {
($src:ty as $($dst:ty),+) => {
$(impl PointerCast<$dst> for $src {
#[inline]
fn pointer_cast(self) -> $dst {
self as $dst
}
})+
}
}
cast!(i8 as isize);
cast!(u8 as isize, usize);
cast!(i16 as isize);
cast!(u16 as isize, usize);
cast!(i32 as isize);
#[cfg(target_word_size = "64")]
cast!(u32 as isize);
cast!(u32 as usize);
#[cfg(target_word_size = "64")]
cast!(i64 as isize);
#[cfg(target_word_size = "64")]
cast!(u64 as usize);
#[cfg(target_word_size = "32")]
cast!(isize as i32);
cast!(isize as i64, i128);
#[cfg(target_word_size = "32")]
cast!(usize as u32, i64);
cast!(usize as u64, i128, u128);
// Truncation of signed types to unsigned types of larger range
macro_rules! trunc_s2u_up {
($src:ty as $($dst:ty),+) => {
$(impl SaturatingCast<$dst> for $src {
#[inline]
fn saturating_cast(self) -> $dst {
if self >= 0 {
self as $dst
} else {
0
}
}
})+
}
}
trunc_s2u_up!(i8 as u8, u16, u32, u64, u128, usize);
trunc_s2u_up!(i16 as u16, u32, u64, u128, usize);
trunc_s2u_up!(i32 as u32, u64, u128, usize);
trunc_s2u_up!(i64 as u64, u128);
#[cfg(target_word_size = "64")]
trunc_s2u_up!(i64 as usize);
trunc_s2u_up!(i128 as u128);
#[cfg(target_word_size = "32")]
trunc_s2u_up!(isize as u32);
trunc_s2u_up!(isize as u64, u128, usize);
// Truncation of signed types to types of smaller range
macro_rules! trunc_s_down {
($src:ty as $($dst:ident),+) => {
$(impl SaturatingCast<$dst> for $src {
#[inline]
fn saturating_cast(self) -> $dst {
if self > std::$dst::MAX as $src {
std::$dst::MAX
} else if self < std::$dst::MIN as $src {
std::$dst::MIN
} else {
self as $dst
}
}
})+
}
}
trunc_s_down!(i16 as i8, u8);
trunc_s_down!(i32 as i8, u8, i16, u16);
trunc_s_down!(i64 as i8, u8, i16, u16, i32, u32);
#[cfg(target_word_size = "32")]
trunc_s_down!(i64 as isize, usize);
trunc_s_down!(i128 as i8, u8, i16, u16, i32, u32, i64, u64, isize, usize);
trunc_s_down!(isize as i8, u8, i16, u16);
#[cfg(target_word_size = "64")]
trunc_s_down!(isize as i32, u32);
// Truncation of unsigned types to types of smaller range
macro_rules! trunc_u_down {
($src:ty as $($dst:ident),+) => {
$(impl SaturatingCast<$dst> for $src {
#[inline]
fn saturating_cast(self) -> $dst {
if self > std::$dst::MAX as $src {
std::$dst::MAX
} else {
self as $dst
}
}
})+
}
}
trunc_u_down!(u8 as i8);
trunc_u_down!(u16 as i8, u8, i16);
trunc_u_down!(u32 as i8, u8, i16, u16, i32);
#[cfg(target_word_size = "32")]
trunc_u_down!(u32 as isize);
trunc_u_down!(u64 as i8, u8, i16, u16, i32, u32, i64, isize);
#[cfg(target_word_size = "32")]
trunc_u_down!(u64 as usize);
trunc_u_down!(u128 as i8, u8, i16, u16, i32, u32, i64, u64, i128, isize, usize);
trunc_u_down!(usize as i8, u8, i16, u16, i32, isize);
#[cfg(target_word_size = "64")]
trunc_u_down!(usize as u32, i64);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment