Skip to content

Remove implicit panics in NotNan<T> x T operators #167

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 38 additions & 51 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1227,10 +1227,7 @@ impl<T: FloatCore + Num> Num for OrderedFloat<T> {
/// ```
/// use ordered_float::NotNan;
///
/// let mut v = [
/// NotNan::new(2.0).unwrap(),
/// NotNan::new(1.0).unwrap(),
/// ];
/// let mut v = [NotNan::new(2.0).unwrap(), NotNan::new(1.0).unwrap()];
/// v.sort();
/// assert_eq!(v, [1.0, 2.0]);
/// ```
Expand Down Expand Up @@ -1270,7 +1267,6 @@ impl<T: FloatCore + Num> Num for OrderedFloat<T> {
/// [transmute](core::mem::transmute) or pointer casts to convert between any type `T` and
/// `NotNan<T>`, as long as this does not create a NaN value.
/// However, consider using [`bytemuck`] as a safe alternative if possible.
///
#[cfg_attr(
not(feature = "bytemuck"),
doc = "[`bytemuck`]: https://docs.rs/bytemuck/1/"
Expand Down Expand Up @@ -1384,9 +1380,10 @@ impl NotNan<f64> {
/// Note: For the reverse conversion (from `NotNan<f32>` to `NotNan<f64>`), you can use
/// `.into()`.
pub fn as_f32(self) -> NotNan<f32> {
// This is not destroying invariants, as it is a pure rounding operation. The only two special
// cases are where f32 would be overflowing, then the operation yields Infinity, or where
// the input is already NaN, in which case the invariant is already broken elsewhere.
// This is not destroying invariants, as it is a pure rounding operation. The only two
// special cases are where f32 would be overflowing, then the operation yields
// Infinity, or where the input is already NaN, in which case the invariant is
// already broken elsewhere.
NotNan(self.0 as f32)
}
}
Expand Down Expand Up @@ -1472,13 +1469,13 @@ impl<T: FloatCore> PartialEq<T> for NotNan<T> {

/// Adds a float directly.
///
/// Panics if the provided value is NaN or the computation results in NaN
/// This returns a `T` and not a `NotNan<T>` because if the added value is NaN, this will be NaN
impl<T: FloatCore> Add<T> for NotNan<T> {
type Output = Self;
type Output = T;

#[inline]
fn add(self, other: T) -> Self {
NotNan::new(self.0 + other).expect("Addition resulted in NaN")
fn add(self, other: T) -> Self::Output {
self.0 + other
}
}

Expand All @@ -1500,25 +1497,27 @@ impl<'a, T: FloatCore + Sum + 'a> Sum<&'a NotNan<T>> for NotNan<T> {

/// Subtracts a float directly.
///
/// Panics if the provided value is NaN or the computation results in NaN
/// This returns a `T` and not a `NotNan<T>` because if the substracted value is NaN, this will be
/// NaN
impl<T: FloatCore> Sub<T> for NotNan<T> {
type Output = Self;
type Output = T;

#[inline]
fn sub(self, other: T) -> Self {
NotNan::new(self.0 - other).expect("Subtraction resulted in NaN")
fn sub(self, other: T) -> Self::Output {
self.0 - other
}
}

/// Multiplies a float directly.
///
/// Panics if the provided value is NaN or the computation results in NaN
/// This returns a `T` and not a `NotNan<T>` because if the multiplied value is NaN, this will be
/// NaN
impl<T: FloatCore> Mul<T> for NotNan<T> {
type Output = Self;
type Output = T;

#[inline]
fn mul(self, other: T) -> Self {
NotNan::new(self.0 * other).expect("Multiplication resulted in NaN")
fn mul(self, other: T) -> Self::Output {
self.0 * other
}
}

Expand All @@ -1537,25 +1536,26 @@ impl<'a, T: FloatCore + Product + 'a> Product<&'a NotNan<T>> for NotNan<T> {

/// Divides a float directly.
///
/// Panics if the provided value is NaN or the computation results in NaN
/// This returns a `T` and not a `NotNan<T>` because if the divided-by value is NaN, this will be
/// NaN
impl<T: FloatCore> Div<T> for NotNan<T> {
type Output = Self;
type Output = T;

#[inline]
fn div(self, other: T) -> Self {
NotNan::new(self.0 / other).expect("Division resulted in NaN")
fn div(self, other: T) -> Self::Output {
self.0 / other
}
}

/// Calculates `%` with a float directly.
///
/// Panics if the provided value is NaN or the computation results in NaN
/// This returns a `T` and not a `NotNan<T>` because if the RHS is NaN, this will be NaN
impl<T: FloatCore> Rem<T> for NotNan<T> {
type Output = Self;
type Output = T;

#[inline]
fn rem(self, other: T) -> Self {
NotNan::new(self.0 % other).expect("Rem resulted in NaN")
fn rem(self, other: T) -> Self::Output {
self.0 % other
}
}

Expand All @@ -1566,12 +1566,13 @@ macro_rules! impl_not_nan_binop {

#[inline]
fn $method(self, other: Self) -> Self {
self.$method(other.0)
NotNan::new(self.0.$method(other.0))
.expect("Operation on two NotNan resulted in NaN")
}
}

impl<T: FloatCore> $imp<&T> for NotNan<T> {
type Output = NotNan<T>;
type Output = T;

#[inline]
fn $method(self, other: &T) -> Self::Output {
Expand All @@ -1584,7 +1585,7 @@ macro_rules! impl_not_nan_binop {

#[inline]
fn $method(self, other: &Self) -> Self::Output {
self.$method(other.0)
self.$method(*other)
}
}

Expand All @@ -1593,7 +1594,7 @@ macro_rules! impl_not_nan_binop {

#[inline]
fn $method(self, other: Self) -> Self::Output {
(*self).$method(other.0)
(*self).$method(*other)
}
}

Expand All @@ -1602,12 +1603,12 @@ macro_rules! impl_not_nan_binop {

#[inline]
fn $method(self, other: NotNan<T>) -> Self::Output {
(*self).$method(other.0)
(*self).$method(other)
}
}

impl<T: FloatCore> $imp<T> for &NotNan<T> {
type Output = NotNan<T>;
type Output = T;

#[inline]
fn $method(self, other: T) -> Self::Output {
Expand All @@ -1616,39 +1617,25 @@ macro_rules! impl_not_nan_binop {
}

impl<T: FloatCore> $imp<&T> for &NotNan<T> {
type Output = NotNan<T>;
type Output = T;

#[inline]
fn $method(self, other: &T) -> Self::Output {
(*self).$method(*other)
}
}

impl<T: FloatCore + $assign_imp> $assign_imp<T> for NotNan<T> {
#[inline]
fn $assign_method(&mut self, other: T) {
*self = (*self).$method(other);
}
}

impl<T: FloatCore + $assign_imp> $assign_imp<&T> for NotNan<T> {
#[inline]
fn $assign_method(&mut self, other: &T) {
*self = (*self).$method(*other);
}
}

impl<T: FloatCore + $assign_imp> $assign_imp for NotNan<T> {
#[inline]
fn $assign_method(&mut self, other: Self) {
(*self).$assign_method(other.0);
*self = (*self).$method(other);
}
}

impl<T: FloatCore + $assign_imp> $assign_imp<&Self> for NotNan<T> {
#[inline]
fn $assign_method(&mut self, other: &Self) {
(*self).$assign_method(other.0);
*self = (*self).$method(*other);
}
}
};
Expand Down
Loading