Skip to content

Commit 3661935

Browse files
committed
Implement Eq and Ord for NSNumber
1 parent d5caed7 commit 3661935

File tree

3 files changed

+45
-1
lines changed

3 files changed

+45
-1
lines changed

crates/icrate/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1616
ones Swift marks as `@Sendable`).
1717
* Made some common methods in `AppKit` safe.
1818
* Added missing `NSCopying` and `NSMutableCopying` zone methods.
19+
* Added `Eq` and `Ord` implementations for `NSNumber`, since its
20+
handling of floating point values allows it.
1921

2022
### Changed
2123
* Moved the `ns_string!` macro to `icrate::Foundation::ns_string`. The old

crates/icrate/src/additions/Foundation/number.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,33 @@ impl PartialEq for NSNumber {
217217
}
218218
}
219219

220+
/// Beware: This uses the Objective-C method "isEqualToNumber:", which has
221+
/// different floating point NaN semantics than Rust!
222+
//
223+
// This is valid since the following pass (i.e. Objective-C says that two NaNs
224+
// are equal):
225+
// ```
226+
// let nan = NSNumber::from_f32(f32::NAN);
227+
// assert_eq!(nan, nan);
228+
// ```
229+
impl Eq for NSNumber {}
230+
220231
/// Beware: This uses the Objective-C method "compare:", which has different
221232
/// floating point NaN semantics than Rust!
222233
impl PartialOrd for NSNumber {
223234
#[doc(alias = "compare:")]
224235
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
236+
Some(self.cmp(other))
237+
}
238+
}
239+
240+
/// Beware: This uses the Objective-C method "compare:", which has different
241+
/// floating point NaN semantics than Rust!
242+
impl Ord for NSNumber {
243+
#[doc(alias = "compare:")]
244+
fn cmp(&self, other: &Self) -> Ordering {
225245
// Use Objective-C semantics for comparison
226-
Some(self.compare(other).into())
246+
self.compare(other).into()
227247
}
228248
}
229249

crates/icrate/tests/number.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,28 @@ fn equality() {
8888
assert_ne!(val1, val4);
8989
}
9090

91+
#[test]
92+
#[cfg_attr(feature = "gnustep-1-7", ignore = "GNUStep handles NaNs differently")]
93+
fn nan_equality() {
94+
let nan = NSNumber::new_f32(f32::NAN);
95+
let nan2 = NSNumber::new_f32(f32::NAN);
96+
let neg_nan = NSNumber::new_f32(-f32::NAN);
97+
assert_eq!(nan, nan);
98+
assert_eq!(nan, nan2);
99+
assert_eq!(neg_nan, neg_nan);
100+
assert_eq!(nan, neg_nan);
101+
}
102+
103+
// Ensure that comparisons are made on the number, and not the bits of the floating point value
104+
#[test]
105+
fn float_int_equality() {
106+
let val1 = NSNumber::new_f32(1.0);
107+
let val2 = NSNumber::new_u32(1);
108+
let val3 = NSNumber::new_u32(1.0f32.to_bits());
109+
assert_eq!(val1, val2);
110+
assert_ne!(val1, val3);
111+
}
112+
91113
#[test]
92114
#[cfg(feature = "Foundation_NSString")]
93115
fn display_debug() {

0 commit comments

Comments
 (0)