simplify checked conversions for int and fixed

The actual implementations are now in SealedInt and SealedFixed. Both
macros_from_to.rs and sealed.rs directly defer to those
implementations.
This commit is contained in:
Trevor Spiteri 2019-08-03 01:11:16 +02:00
parent 62457d201d
commit 99668c5a5e
5 changed files with 264 additions and 267 deletions

View File

@ -90,10 +90,7 @@ assert_eq!(Dst::from_fixed(src >> 4), Dst::from_bits(1));
where
F: Fixed,
{
let (wrapped, overflow) = Self::overflowing_from_fixed(val);
debug_assert!(!overflow, "{} overflows", val);
let _ = overflow;
wrapped
SealedFixed::from_fixed(val)
}
);
@ -131,10 +128,7 @@ assert_eq!((src >> 4u32).to_fixed::<Dst>(), Dst::from_bits(1));
where
F: Fixed,
{
let (wrapped, overflow) = <F as SealedFixed>::overflowing_from_fixed(self);
debug_assert!(!overflow, "{} overflows", self);
let _ = overflow;
wrapped
SealedFixed::from_fixed(self)
}
);
@ -187,10 +181,7 @@ assert_eq!(Fix::from_int(",
where
I: Int,
{
let (wrapped, overflow) = Self::overflowing_from_int(val);
debug_assert!(!overflow, "{} overflows", val);
let _ = overflow;
wrapped
SealedInt::to_fixed(val)
}
);
@ -246,10 +237,7 @@ assert_eq!(",
where
I: Int,
{
let (wrapped, overflow) = <I as SealedInt>::overflowing_from_fixed(self);
debug_assert!(!overflow, "{} overflows", self);
let _ = overflow;
wrapped
SealedInt::from_fixed(self)
}
);
@ -383,8 +371,7 @@ assert!(Dst::checked_from_fixed(too_large).is_none());
where
F: Fixed,
{
let (wrapped, overflow) = Self::overflowing_from_fixed(val);
if overflow { None } else { Some(wrapped) }
SealedFixed::checked_from_fixed(val)
}
);
@ -418,10 +405,7 @@ assert!(Src::max_value().checked_to_fixed::<TooFewIntBits>().is_none());
where
F: Fixed,
{
match <F as SealedFixed>::overflowing_from_fixed(self) {
(wrapped, false) => Some(wrapped),
(_, true) => None,
}
SealedFixed::checked_from_fixed(self)
}
);
@ -473,8 +457,7 @@ assert!(Fix::checked_from_int(too_small).is_none());
where
I: Int,
{
let (wrapped, overflow) = Self::overflowing_from_int(val);
if overflow { None } else { Some(wrapped) }
SealedInt::checked_to_fixed(val)
}
);
@ -535,10 +518,7 @@ assert!(AllInt::",
where
I: Int,
{
match <I as SealedInt>::overflowing_from_fixed(self) {
(wrapped, false) => Some(wrapped),
(_, true) => None,
}
SealedInt::checked_from_fixed(self)
}
);
@ -625,35 +605,7 @@ assert_eq!(Dst::saturating_from_fixed(too_small), Dst::min_value());
where
F: Fixed,
{
let (value, _, overflow) = val.to_bits().to_fixed_dir_overflow(
F::FRAC_NBITS as i32,
Self::FRAC_NBITS,
Self::INT_NBITS,
);
if overflow {
return if val.to_bits().is_negative() {
Self::min_value()
} else {
Self::max_value()
};
}
let bits = if_signed_unsigned!(
$Signedness,
match value {
Widest::Unsigned(bits) => {
if (bits as <Self as SealedFixed>::Bits) < 0 {
return Self::max_value();
}
bits as <Self as SealedFixed>::Bits
}
Widest::Negative(bits) => bits as <Self as SealedFixed>::Bits,
},
match value {
Widest::Unsigned(bits) => bits as <Self as SealedFixed>::Bits,
Widest::Negative(_) => return Self::min_value(),
},
);
SealedFixed::from_bits(bits)
SealedFixed::saturating_from_fixed(val)
}
);
@ -685,16 +637,7 @@ assert_eq!(saturated, TooFewIntBits::max_value());
where
F: Fixed,
{
match <F as SealedFixed>::overflowing_from_fixed(self) {
(wrapped, false) => wrapped,
(_, true) => {
if self.to_bits().is_negative() {
F::from_bits(F::Bits::min_value())
} else {
F::from_bits(F::Bits::max_value())
}
}
}
SealedFixed::saturating_from_fixed(self)
}
);
@ -745,35 +688,7 @@ assert_eq!(Fix::saturating_from_int(too_small), Fix::min_value());
where
I: Int,
{
let (value, _, overflow) = val.to_fixed_dir_overflow(
0,
Self::FRAC_NBITS,
Self::INT_NBITS,
);
if overflow {
return if val.is_negative() {
Self::min_value()
} else {
Self::max_value()
};
}
let bits = if_signed_unsigned!(
$Signedness,
match value {
Widest::Unsigned(bits) => {
if (bits as <Self as SealedFixed>::Bits) < 0 {
return Self::max_value();
}
bits as <Self as SealedFixed>::Bits
}
Widest::Negative(bits) => bits as <Self as SealedFixed>::Bits,
},
match value {
Widest::Unsigned(bits) => bits as <Self as SealedFixed>::Bits,
Widest::Negative(_) => return Self::min_value(),
},
);
SealedFixed::from_bits(bits)
SealedInt::saturating_to_fixed(val)
}
);
@ -842,16 +757,7 @@ assert_eq!(",
where
I: Int,
{
match <I as SealedInt>::overflowing_from_fixed(self) {
(wrapped, false) => wrapped,
(_, true) => {
if self.to_bits().is_negative() {
I::min_value()
} else {
I::max_value()
}
}
}
SealedInt::saturating_from_fixed(self)
}
);
@ -965,7 +871,7 @@ assert_eq!(Dst::wrapping_from_fixed(too_large), wrapped);
where
F: Fixed,
{
Self::overflowing_from_fixed(val).0
SealedFixed::wrapping_from_fixed(val)
}
);
@ -998,7 +904,7 @@ assert_eq!(Src::max_value().wrapping_to_fixed::<TooFewIntBits>(), wrapped);
where
F: Fixed,
{
<F as SealedFixed>::overflowing_from_fixed(self).0
SealedFixed::wrapping_from_fixed(self)
}
);
@ -1049,7 +955,7 @@ assert_eq!(Fix::wrapping_from_int(large), wrapped);
where
I: Int,
{
Self::overflowing_from_int(val).0
SealedInt::wrapping_to_fixed(val)
}
);
@ -1118,7 +1024,7 @@ assert_eq!(",
where
I: Int,
{
<I as SealedInt>::overflowing_from_fixed(self).0
SealedInt::wrapping_from_fixed(self)
}
);
@ -1216,31 +1122,7 @@ assert_eq!(Dst::overflowing_from_fixed(too_large), (wrapped, true));
where
F: Fixed,
{
let (value, _, mut overflow) = val.to_bits().to_fixed_dir_overflow(
F::FRAC_NBITS as i32,
Self::FRAC_NBITS,
Self::INT_NBITS,
);
let bits = if_signed_unsigned!(
$Signedness,
match value {
Widest::Unsigned(bits) => {
if (bits as <Self as SealedFixed>::Bits) < 0 {
overflow = true;
}
bits as <Self as SealedFixed>::Bits
}
Widest::Negative(bits) => bits as <Self as SealedFixed>::Bits,
},
match value {
Widest::Unsigned(bits) => bits as <Self as SealedFixed>::Bits,
Widest::Negative(bits) => {
overflow = true;
bits as <Self as SealedFixed>::Bits
}
},
);
(SealedFixed::from_bits(bits), overflow)
SealedFixed::overflowing_from_fixed(val)
}
);
@ -1277,7 +1159,7 @@ assert_eq!(Src::max_value().overflowing_to_fixed::<TooFewIntBits>(), (wrapped, t
where
F: Fixed,
{
<F as SealedFixed>::overflowing_from_fixed(self)
SealedFixed::overflowing_from_fixed(self)
}
);
@ -1332,31 +1214,7 @@ assert_eq!(Fix::overflowing_from_int(large), (wrapped, true));
where
I: Int,
{
let (value, _, mut overflow) = val.to_fixed_dir_overflow(
0,
Self::FRAC_NBITS,
Self::INT_NBITS,
);
let bits = if_signed_unsigned!(
$Signedness,
match value {
Widest::Unsigned(bits) => {
if (bits as <Self as SealedFixed>::Bits) < 0 {
overflow = true;
}
bits as <Self as SealedFixed>::Bits
}
Widest::Negative(bits) => bits as <Self as SealedFixed>::Bits,
},
match value {
Widest::Unsigned(bits) => bits as <Self as SealedFixed>::Bits,
Widest::Negative(bits) => {
overflow = true;
bits as <Self as SealedFixed>::Bits
}
},
);
(SealedFixed::from_bits(bits), overflow)
SealedInt::overflowing_to_fixed(val)
}
);
@ -1424,7 +1282,7 @@ assert_eq!(does_not_fit.overflowing_to_int::<",
where
I: Int,
{
<I as SealedInt>::overflowing_from_fixed(self)
SealedInt::overflowing_from_fixed(self)
}
);

View File

@ -159,51 +159,35 @@ macro_rules! checked_int {
where
F: Fixed,
{
let (wrapped, overflow) = <Self as SealedInt>::overflowing_from_fixed(val);
debug_assert!(!overflow, "{} overflows", val);
let _ = overflow;
wrapped
SealedInt::from_fixed(val)
}
#[inline]
fn checked_from_fixed<F>(val: F) -> Option<Self>
where
F: Fixed,
{
match <Self as SealedInt>::overflowing_from_fixed(val) {
(wrapped, false) => Some(wrapped),
(_, true) => None,
}
SealedInt::checked_from_fixed(val)
}
#[inline]
fn saturating_from_fixed<F>(val: F) -> Self
where
F: Fixed,
{
match <Self as SealedInt>::overflowing_from_fixed(val) {
(wrapped, false) => wrapped,
(_, true) => {
if val.to_bits().is_negative() {
Self::min_value()
} else {
Self::max_value()
}
}
}
SealedInt::saturating_from_fixed(val)
}
#[inline]
fn wrapping_from_fixed<F>(val: F) -> Self
where
F: Fixed,
{
let (wrapped, _) = <Self as SealedInt>::overflowing_from_fixed(val);
wrapped
SealedInt::wrapping_from_fixed(val)
}
#[inline]
fn overflowing_from_fixed<F>(val: F) -> (Self, bool)
where
F: Fixed,
{
<Self as SealedInt>::overflowing_from_fixed(val)
SealedInt::overflowing_from_fixed(val)
}
}
@ -213,51 +197,35 @@ macro_rules! checked_int {
where
F: Fixed,
{
let (wrapped, overflow) = <Self as SealedInt>::overflowing_to_fixed(self);
debug_assert!(!overflow, "{} overflows", self);
let _ = overflow;
wrapped
SealedInt::to_fixed(self)
}
#[inline]
fn checked_to_fixed<F>(self) -> Option<F>
where
F: Fixed,
{
match <Self as SealedInt>::overflowing_to_fixed(self) {
(wrapped, false) => Some(wrapped),
(_, true) => None,
}
SealedInt::checked_to_fixed(self)
}
#[inline]
fn saturating_to_fixed<F>(self) -> F
where
F: Fixed,
{
match <Self as SealedInt>::overflowing_to_fixed(self) {
(wrapped, false) => wrapped,
(_, true) => {
if self.is_negative() {
F::from_bits(<F as SealedFixed>::Bits::min_value())
} else {
F::from_bits(<F as SealedFixed>::Bits::max_value())
}
}
}
SealedInt::saturating_to_fixed(self)
}
#[inline]
fn wrapping_to_fixed<F>(self) -> F
where
F: Fixed,
{
let (wrapped, _) = <Self as SealedInt>::overflowing_to_fixed(self);
wrapped
SealedInt::wrapping_to_fixed(self)
}
#[inline]
fn overflowing_to_fixed<F>(self) -> (F, bool)
where
F: Fixed,
{
<Self as SealedInt>::overflowing_to_fixed(self)
SealedInt::overflowing_to_fixed(self)
}
}
};
@ -322,57 +290,35 @@ macro_rules! checked_float {
where
F: Fixed,
{
let (wrapped, overflow) = <Self as SealedFloat>::overflowing_to_fixed(self);
debug_assert!(!overflow, "{} overflows", self);
let _ = overflow;
wrapped
SealedFloat::to_fixed(self)
}
#[inline]
fn checked_to_fixed<F>(self) -> Option<F>
where
F: Fixed,
{
if !self.is_finite() {
return None;
}
match <Self as SealedFloat>::overflowing_to_fixed(self) {
(wrapped, false) => Some(wrapped),
(_, true) => None,
}
SealedFloat::checked_to_fixed(self)
}
#[inline]
fn saturating_to_fixed<F>(self) -> F
where
F: Fixed,
{
assert!(!self.is_nan(), "NaN");
let saturated = if self.is_sign_negative() {
F::from_bits(<F as SealedFixed>::Bits::min_value())
} else {
F::from_bits(<F as SealedFixed>::Bits::max_value())
};
if !self.is_finite() {
return saturated;
}
match <Self as SealedFloat>::overflowing_to_fixed(self) {
(wrapped, false) => wrapped,
(_, true) => saturated,
}
SealedFloat::saturating_to_fixed(self)
}
#[inline]
fn wrapping_to_fixed<F>(self) -> F
where
F: Fixed,
{
let (wrapped, _) = <Self as SealedFloat>::overflowing_to_fixed(self);
wrapped
SealedFloat::wrapping_to_fixed(self)
}
#[inline]
fn overflowing_to_fixed<F>(self) -> (F, bool)
where
F: Fixed,
{
<Self as SealedFloat>::overflowing_to_fixed(self)
SealedFloat::overflowing_to_fixed(self)
}
}
};
@ -394,44 +340,35 @@ macro_rules! checked_fixed {
where
F: Fixed,
{
let (wrapped, overflow) = <Self as SealedFixed>::overflowing_from_fixed(val);
debug_assert!(!overflow, "{} overflows", val);
let _ = overflow;
wrapped
SealedFixed::from_fixed(val)
}
#[inline]
fn checked_from_fixed<F>(val: F) -> Option<Self>
where
F: Fixed,
{
let (wrapped, overflow) = <Self as SealedFixed>::overflowing_from_fixed(val);
if overflow {
None
} else {
Some(wrapped)
}
SealedFixed::checked_from_fixed(val)
}
#[inline]
fn saturating_from_fixed<F>(val: F) -> Self
where
F: Fixed,
{
<Self as SealedFixed>::saturating_from_fixed(val)
SealedFixed::saturating_from_fixed(val)
}
#[inline]
fn wrapping_from_fixed<F>(val: F) -> Self
where
F: Fixed,
{
let (wrapped, _) = <Self as SealedFixed>::overflowing_from_fixed(val);
wrapped
SealedFixed::wrapping_from_fixed(val)
}
#[inline]
fn overflowing_from_fixed<F>(val: F) -> (Self, bool)
where
F: Fixed,
{
<Self as SealedFixed>::overflowing_from_fixed(val)
SealedFixed::overflowing_from_fixed(val)
}
}
@ -444,42 +381,35 @@ macro_rules! checked_fixed {
where
F: Fixed,
{
let (wrapped, overflow) = <F as SealedFixed>::overflowing_from_fixed(self);
debug_assert!(!overflow, "{} overflows", self);
let _ = overflow;
wrapped
SealedFixed::from_fixed(self)
}
#[inline]
fn checked_to_fixed<F>(self) -> Option<F>
where
F: Fixed,
{
match <F as SealedFixed>::overflowing_from_fixed(self) {
(wrapped, false) => Some(wrapped),
(_, true) => None,
}
SealedFixed::checked_from_fixed(self)
}
#[inline]
fn saturating_to_fixed<F>(self) -> F
where
F: Fixed,
{
<F as SealedFixed>::saturating_from_fixed(self)
SealedFixed::saturating_from_fixed(self)
}
#[inline]
fn wrapping_to_fixed<F>(self) -> F
where
F: Fixed,
{
let (wrapped, _) = <F as SealedFixed>::overflowing_from_fixed(self);
wrapped
SealedFixed::wrapping_from_fixed(self)
}
#[inline]
fn overflowing_to_fixed<F>(self) -> (F, bool)
where
F: Fixed,
{
<F as SealedFixed>::overflowing_from_fixed(self)
SealedFixed::overflowing_from_fixed(self)
}
}
};

View File

@ -49,9 +49,37 @@ pub trait SealedFixed: Copy + Debug + Default + Display + Eq + Hash + Ord {
// 0 for no int bits
const INT_LSB: u128 = Self::INT_MASK ^ (Self::INT_MASK << 1);
#[inline]
fn from_fixed<F>(val: F) -> Self
where
F: Fixed,
{
let (wrapped, overflow) = SealedFixed::overflowing_from_fixed(val);
debug_assert!(!overflow, "{} overflows", val);
let _ = overflow;
wrapped
}
#[inline]
fn checked_from_fixed<F>(val: F) -> Option<Self>
where
F: Fixed,
{
match SealedFixed::overflowing_from_fixed(val) {
(_, true) => None,
(wrapped, false) => Some(wrapped),
}
}
fn saturating_from_fixed<F>(fixed: F) -> Self
where
F: Fixed;
#[inline]
fn wrapping_from_fixed<F>(val: F) -> Self
where
F: Fixed,
{
let (wrapped, _) = SealedFixed::overflowing_from_fixed(val);
wrapped
}
fn overflowing_from_fixed<F>(fixed: F) -> (Self, bool)
where
F: Fixed;
@ -109,19 +137,73 @@ macro_rules! sealed_fixed {
type Bits = $Bits;
#[inline]
fn saturating_from_fixed<F>(fixed: F) -> Self
fn saturating_from_fixed<F>(val: F) -> Self
where
F: Fixed,
{
$Fixed::saturating_from_fixed(fixed)
let (value, _, overflow) = val.to_bits().to_fixed_dir_overflow(
F::FRAC_NBITS as i32,
Self::FRAC_NBITS,
Self::INT_NBITS,
);
if overflow {
return if val.to_bits().is_negative() {
Self::from_bits(Self::Bits::min_value())
} else {
Self::from_bits(Self::Bits::max_value())
};
}
let bits = if_signed_unsigned!(
$Signedness,
match value {
Widest::Unsigned(bits) => {
if (bits as Self::Bits) < 0 {
return Self::from_bits(Self::Bits::max_value());
}
bits as Self::Bits
}
Widest::Negative(bits) => bits as Self::Bits,
},
match value {
Widest::Unsigned(bits) => bits as Self::Bits,
Widest::Negative(_) => {
return Self::from_bits(Self::Bits::min_value());
}
},
);
SealedFixed::from_bits(bits)
}
#[inline]
fn overflowing_from_fixed<F>(fixed: F) -> (Self, bool)
fn overflowing_from_fixed<F>(val: F) -> (Self, bool)
where
F: Fixed,
{
$Fixed::overflowing_from_fixed(fixed)
let (value, _, mut overflow) = val.to_bits().to_fixed_dir_overflow(
F::FRAC_NBITS as i32,
Self::FRAC_NBITS,
Self::INT_NBITS,
);
let bits = if_signed_unsigned!(
$Signedness,
match value {
Widest::Unsigned(bits) => {
if (bits as Self::Bits) < 0 {
overflow = true;
}
bits as Self::Bits
}
Widest::Negative(bits) => bits as Self::Bits,
},
match value {
Widest::Unsigned(bits) => bits as Self::Bits,
Widest::Negative(bits) => {
overflow = true;
bits as Self::Bits
}
},
);
(SealedFixed::from_bits(bits), overflow)
}
#[inline]

View File

@ -16,7 +16,7 @@
#[cfg(feature = "f16")]
use half::f16;
use {
crate::sealed::{Fixed, SealedInt, Widest},
crate::sealed::{Fixed, SealedFixed, SealedInt, Widest},
core::{
cmp::Ordering,
fmt::{Debug, Display},
@ -45,6 +45,56 @@ pub trait SealedFloat: Copy + Debug + Display {
fn parts(self) -> (bool, i32, Self::Bits);
fn from_parts(sign: bool, exp: i32, mant: Self::Bits) -> Self;
#[inline]
fn to_fixed<F>(self) -> F
where
F: Fixed,
{
let (wrapped, overflow) = Self::overflowing_to_fixed(self);
debug_assert!(!overflow, "{} overflows", self);
let _ = overflow;
wrapped
}
#[inline]
fn checked_to_fixed<F>(self) -> Option<F>
where
F: Fixed,
{
if !self.is_finite() {
return None;
}
match Self::overflowing_to_fixed(self) {
(wrapped, false) => Some(wrapped),
(_, true) => None,
}
}
#[inline]
fn saturating_to_fixed<F>(self) -> F
where
F: Fixed,
{
assert!(!self.is_nan(), "NaN");
let saturated = if self.is_sign_negative() {
F::from_bits(<F as SealedFixed>::Bits::min_value())
} else {
F::from_bits(<F as SealedFixed>::Bits::max_value())
};
if !self.is_finite() {
return saturated;
}
match Self::overflowing_to_fixed(self) {
(wrapped, false) => wrapped,
(_, true) => saturated,
}
}
#[inline]
fn wrapping_to_fixed<F>(self) -> F
where
F: Fixed,
{
let (wrapped, _) = Self::overflowing_to_fixed(self);
wrapped
}
fn overflowing_to_fixed<F>(self) -> (F, bool)
where
F: Fixed;

View File

@ -36,9 +36,72 @@ pub trait SealedInt: Copy + Ord + Debug + Display {
const IS_SIGNED: bool = Self::IsSigned::BOOL;
const MSB: Self;
fn overflowing_from_fixed<F>(fixed: F) -> (Self, bool)
#[inline]
fn from_fixed<F>(val: F) -> Self
where
F: Fixed,
{
let (wrapped, overflow) = Self::overflowing_from_fixed(val);
debug_assert!(!overflow, "{} overflows", val);
let _ = overflow;
wrapped
}
#[inline]
fn checked_from_fixed<F>(val: F) -> Option<Self>
where
F: Fixed,
{
match Self::overflowing_from_fixed(val) {
(_, true) => None,
(wrapped, false) => Some(wrapped),
}
}
fn saturating_from_fixed<F>(val: F) -> Self
where
F: Fixed;
#[inline]
fn wrapping_from_fixed<F>(val: F) -> Self
where
F: Fixed,
{
let (wrapped, _) = Self::overflowing_from_fixed(val);
wrapped
}
fn overflowing_from_fixed<F>(val: F) -> (Self, bool)
where
F: Fixed;
#[inline]
fn to_fixed<F>(self) -> F
where
F: Fixed,
{
let (wrapped, overflow) = Self::overflowing_to_fixed(self);
debug_assert!(!overflow, "{} overflows", self);
let _ = overflow;
wrapped
}
#[inline]
fn checked_to_fixed<F>(self) -> Option<F>
where
F: Fixed,
{
match Self::overflowing_to_fixed(self) {
(_, true) => None,
(wrapped, false) => Some(wrapped),
}
}
fn saturating_to_fixed<F>(self) -> F
where
F: Fixed;
#[inline]
fn wrapping_to_fixed<F>(self) -> F
where
F: Fixed,
{
let (wrapped, _) = Self::overflowing_to_fixed(self);
wrapped
}
fn overflowing_to_fixed<F>(self) -> (F, bool)
where
F: Fixed;
@ -85,21 +148,35 @@ macro_rules! sealed_int {
}
#[inline]
fn overflowing_from_fixed<F>(fixed: F) -> (Self, bool)
fn saturating_from_fixed<F>(val: F) -> Self
where
F: Fixed,
{
let (wrapped, overflow) = Self::ReprFixed::overflowing_from_fixed(fixed);
let saturated = Self::ReprFixed::saturating_from_fixed(val);
IntRepr::from_int_repr(saturated.to_bits())
}
#[inline]
fn overflowing_from_fixed<F>(val: F) -> (Self, bool)
where
F: Fixed,
{
let (wrapped, overflow) = Self::ReprFixed::overflowing_from_fixed(val);
(IntRepr::from_int_repr(wrapped.to_bits()), overflow)
}
#[inline]
fn saturating_to_fixed<F>(self) -> F
where
F: Fixed,
{
SealedFixed::saturating_from_fixed(self.to_repr_fixed())
}
#[inline]
fn overflowing_to_fixed<F>(self) -> (F, bool)
where
F: Fixed
{
let from_bits = Self::ReprFixed::from_bits(self.int_repr());
<F as SealedFixed>::overflowing_from_fixed(from_bits)
SealedFixed::overflowing_from_fixed(self.to_repr_fixed())
}
#[inline]