pub trait FloatConvert<Int>: Sized {
#[must_use = "this returns the result of the operation, without modifying the original"]
fn checked_floor(self) -> Option<Int>;
#[must_use = "this returns the result of the operation, without modifying the original"]
fn checked_ceil(self) -> Option<Int>;
#[must_use = "this returns the result of the operation, without modifying the original"]
fn checked_round(self) -> Option<Int>;
#[must_use = "this returns the result of the operation, without modifying the original"]
fn saturated_floor(self) -> Int;
#[must_use = "this returns the result of the operation, without modifying the original"]
fn saturated_ceil(self) -> Int;
#[must_use = "this returns the result of the operation, without modifying the original"]
fn saturated_round(self) -> Int;
}
macro_rules! checked_impl {
($val:ident.$fn:ident(), $int:ty) => {{
if $val.is_nan() || $val.is_infinite() {
return None;
}
let converted = $val.$fn();
if <$int>::MIN as Self <= converted && converted <= <$int>::MAX as Self {
Some(converted as $int)
} else {
None
}
}};
}
macro_rules! saturated_impl {
($val:ident.$fn:ident(), $int:ty) => {{
$val.$fn() as $int
}};
}
macro_rules! impl_float_convert {
($float:ty, $($int:ty),+) => {
$(impl FloatConvert<$int> for $float {
fn checked_floor(self) -> Option<$int> {
checked_impl!(self.floor(), $int)
}
fn checked_ceil(self) -> Option<$int> {
checked_impl!(self.ceil(), $int)
}
fn checked_round(self) -> Option<$int> {
checked_impl!(self.round(), $int)
}
fn saturated_floor(self) -> $int {
saturated_impl!(self.floor(), $int)
}
fn saturated_ceil(self) -> $int {
saturated_impl!(self.ceil(), $int)
}
fn saturated_round(self) -> $int {
saturated_impl!(self.round(), $int)
}
})+
};
}
impl_float_convert!(f32, u8, u16, u32, u64, u128);
impl_float_convert!(f32, i8, i16, i32, i64, i128);
impl_float_convert!(f32, usize, isize);
impl_float_convert!(f64, u8, u16, u32, u64, u128);
impl_float_convert!(f64, i8, i16, i32, i64, i128);
impl_float_convert!(f64, usize, isize);