From 00a86c6633f7391b3a59ec0232863cb14c018e6d Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 7 Sep 2023 10:41:05 +0200 Subject: [PATCH] Implement Eq and Ord for NSNumber --- crates/icrate/CHANGELOG.md | 2 ++ .../icrate/src/additions/Foundation/number.rs | 22 ++++++++++++++++++- crates/icrate/tests/number.rs | 22 +++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/crates/icrate/CHANGELOG.md b/crates/icrate/CHANGELOG.md index 89d0d898a..a2ef383b4 100644 --- a/crates/icrate/CHANGELOG.md +++ b/crates/icrate/CHANGELOG.md @@ -16,6 +16,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ones Swift marks as `@Sendable`). * Made some common methods in `AppKit` safe. * Added missing `NSCopying` and `NSMutableCopying` zone methods. +* Added `Eq` and `Ord` implementations for `NSNumber`, since its + handling of floating point values allows it. ### Changed * Moved the `ns_string!` macro to `icrate::Foundation::ns_string`. The old diff --git a/crates/icrate/src/additions/Foundation/number.rs b/crates/icrate/src/additions/Foundation/number.rs index 8a997e5ea..decc59fff 100644 --- a/crates/icrate/src/additions/Foundation/number.rs +++ b/crates/icrate/src/additions/Foundation/number.rs @@ -217,13 +217,33 @@ impl PartialEq for NSNumber { } } +/// Beware: This uses the Objective-C method "isEqualToNumber:", which has +/// different floating point NaN semantics than Rust! +// +// This is valid since the following pass (i.e. Objective-C says that two NaNs +// are equal): +// ``` +// let nan = NSNumber::from_f32(f32::NAN); +// assert_eq!(nan, nan); +// ``` +impl Eq for NSNumber {} + /// Beware: This uses the Objective-C method "compare:", which has different /// floating point NaN semantics than Rust! impl PartialOrd for NSNumber { #[doc(alias = "compare:")] fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +/// Beware: This uses the Objective-C method "compare:", which has different +/// floating point NaN semantics than Rust! +impl Ord for NSNumber { + #[doc(alias = "compare:")] + fn cmp(&self, other: &Self) -> Ordering { // Use Objective-C semantics for comparison - Some(self.compare(other).into()) + self.compare(other).into() } } diff --git a/crates/icrate/tests/number.rs b/crates/icrate/tests/number.rs index 05ed98710..c1d8dc247 100644 --- a/crates/icrate/tests/number.rs +++ b/crates/icrate/tests/number.rs @@ -88,6 +88,28 @@ fn equality() { assert_ne!(val1, val4); } +#[test] +#[cfg_attr(feature = "gnustep-1-7", ignore = "GNUStep handles NaNs differently")] +fn nan_equality() { + let nan = NSNumber::new_f32(f32::NAN); + let nan2 = NSNumber::new_f32(f32::NAN); + let neg_nan = NSNumber::new_f32(-f32::NAN); + assert_eq!(nan, nan); + assert_eq!(nan, nan2); + assert_eq!(neg_nan, neg_nan); + assert_eq!(nan, neg_nan); +} + +// Ensure that comparisons are made on the number, and not the bits of the floating point value +#[test] +fn float_int_equality() { + let val1 = NSNumber::new_f32(1.0); + let val2 = NSNumber::new_u32(1); + let val3 = NSNumber::new_u32(1.0f32.to_bits()); + assert_eq!(val1, val2); + assert_ne!(val1, val3); +} + #[test] #[cfg(feature = "Foundation_NSString")] fn display_debug() {