fruity__bbqsrc/foundation/
ns_number.rs

1use super::{NSComparisonResult, NSString, NSValue};
2use crate::core::Arc;
3use crate::objc::{ClassType, NSInteger, NSUInteger, ObjCObject, BOOL};
4use std::{
5    cmp::Ordering,
6    fmt,
7    os::raw::{
8        c_char, c_double, c_float, c_int, c_long, c_longlong, c_short, c_uchar, c_uint, c_ulong,
9        c_ulonglong, c_ushort,
10    },
11    ptr,
12};
13
14objc_subclass! {
15    /// An object wrapper for primitive scalar numeric values.
16    ///
17    /// There are [static instances](#static-instances) which make using certain
18    /// numbers much faster.
19    ///
20    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber).
21    pub class NSNumber: NSValue;
22}
23
24impl PartialEq for NSNumber {
25    #[inline]
26    fn eq(&self, other: &Self) -> bool {
27        unsafe { _msg_send_any_cached![self, isEqualToNumber: other => BOOL] }.into()
28    }
29}
30
31impl Eq for NSNumber {}
32
33impl PartialOrd for NSNumber {
34    #[inline]
35    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
36        Some(self.cmp(other))
37    }
38}
39
40impl Ord for NSNumber {
41    #[inline]
42    fn cmp(&self, other: &Self) -> Ordering {
43        self.compare(other).into()
44    }
45}
46
47impl From<bool> for Arc<NSNumber> {
48    #[inline]
49    fn from(value: bool) -> Self {
50        NSNumber::from_bool(value)
51    }
52}
53
54impl From<c_double> for Arc<NSNumber> {
55    #[inline]
56    fn from(value: c_double) -> Self {
57        NSNumber::from_double(value)
58    }
59}
60
61impl From<c_float> for Arc<NSNumber> {
62    #[inline]
63    fn from(value: c_float) -> Self {
64        NSNumber::from_float(value)
65    }
66}
67
68impl From<NSInteger> for Arc<NSNumber> {
69    #[inline]
70    fn from(value: NSInteger) -> Self {
71        NSNumber::from_integer(value)
72    }
73}
74
75impl From<NSUInteger> for Arc<NSNumber> {
76    #[inline]
77    fn from(value: NSUInteger) -> Self {
78        NSNumber::from_unsigned_integer(value)
79    }
80}
81
82impl From<c_char> for Arc<NSNumber> {
83    #[inline]
84    fn from(value: c_char) -> Self {
85        NSNumber::from_char(value)
86    }
87}
88
89impl From<c_uchar> for Arc<NSNumber> {
90    #[inline]
91    fn from(value: c_uchar) -> Self {
92        NSNumber::from_unsigned_char(value)
93    }
94}
95
96impl From<c_int> for Arc<NSNumber> {
97    #[inline]
98    fn from(value: c_int) -> Self {
99        NSNumber::from_int(value)
100    }
101}
102
103impl From<c_uint> for Arc<NSNumber> {
104    #[inline]
105    fn from(value: c_uint) -> Self {
106        NSNumber::from_unsigned_int(value)
107    }
108}
109
110impl From<c_long> for Arc<NSNumber> {
111    #[inline]
112    fn from(value: c_long) -> Self {
113        NSNumber::from_long(value)
114    }
115}
116
117impl From<c_ulong> for Arc<NSNumber> {
118    #[inline]
119    fn from(value: c_ulong) -> Self {
120        NSNumber::from_unsigned_long(value)
121    }
122}
123
124// TODO: Determine if `c_longlong` and `c_ulonglong` differ from `c_long` and
125// `c_ulong` on the targeted platforms. If they do, then conditionally add
126// `From` implementations.
127
128impl From<c_short> for Arc<NSNumber> {
129    #[inline]
130    fn from(value: c_short) -> Self {
131        NSNumber::from_short(value)
132    }
133}
134
135impl From<c_ushort> for Arc<NSNumber> {
136    #[inline]
137    fn from(value: c_ushort) -> Self {
138        NSNumber::from_unsigned_short(value)
139    }
140}
141
142impl From<&NSNumber> for Arc<NSString<'_>> {
143    #[inline]
144    fn from(number: &NSNumber) -> Self {
145        number.string_value()
146    }
147}
148
149impl fmt::Debug for NSNumber {
150    #[inline]
151    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
152        fmt::Display::fmt(self, f)
153    }
154}
155
156impl fmt::Display for NSNumber {
157    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
158        match self._cfboolean_value() {
159            Some(false) => "NO".fmt(f),
160            Some(true) => "YES".fmt(f),
161            None => match self.objc_type_single() as u8 {
162                // https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
163                b'f' => self.float_value().fmt(f),
164                b'd' => self.double_value().fmt(f),
165                b'c' | b'i' | b's' | b'l' | b'q' => self.longlong_value().fmt(f),
166                _ => self.unsigned_longlong_value().fmt(f),
167            },
168        }
169    }
170}
171
172/// Scalar constructors.
173impl NSNumber {
174    // TODO: Add constructors:
175    // - initWithCoder:
176
177    /// Creates a number object containing a boolean.
178    ///
179    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1551475-numberwithbool).
180    #[inline]
181    #[doc(alias = "numberWithBool")]
182    #[doc(alias = "numberWithBool:")]
183    pub fn from_bool(value: bool) -> Arc<Self> {
184        unsafe { _msg_send_any![Self::class(), numberWithBool: BOOL::from(value)] }
185    }
186
187    /// Creates a number object from a C `float`.
188    ///
189    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1551471-numberwithfloat)
190    #[inline]
191    #[doc(alias = "numberWithFloat")]
192    #[doc(alias = "numberWithFloat:")]
193    pub fn from_float(value: c_float) -> Arc<Self> {
194        unsafe { _msg_send_any![Self::class(), numberWithFloat: value] }
195    }
196
197    /// Creates a number object from a C `double`.
198    ///
199    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1551463-numberwithdouble)
200    #[inline]
201    #[doc(alias = "numberWithDouble")]
202    #[doc(alias = "numberWithDouble:")]
203    pub fn from_double(value: c_double) -> Arc<Self> {
204        unsafe { _msg_send_any![Self::class(), numberWithDouble: value] }
205    }
206
207    /// Creates a number object from a C `char`.
208    ///
209    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1551464-numberwithchar)
210    #[inline]
211    #[doc(alias = "numberWithChar")]
212    #[doc(alias = "numberWithChar:")]
213    pub fn from_char(value: c_char) -> Arc<Self> {
214        unsafe { _msg_send_any![Self::class(), numberWithChar: value] }
215    }
216
217    /// Creates a number object from a C `short`.
218    ///
219    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1551476-numberwithshort)
220    #[inline]
221    #[doc(alias = "numberWithShort")]
222    #[doc(alias = "numberWithShort:")]
223    pub fn from_short(value: c_short) -> Arc<Self> {
224        unsafe { _msg_send_any![Self::class(), numberWithShort: value] }
225    }
226
227    /// Creates a number object from a C `int`.
228    ///
229    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1551470-numberwithint)
230    #[inline]
231    #[doc(alias = "numberWithInt")]
232    #[doc(alias = "numberWithInt:")]
233    pub fn from_int(value: c_int) -> Arc<Self> {
234        unsafe { _msg_send_any![Self::class(), numberWithInt: value] }
235    }
236
237    /// Creates a number object from a C `long`.
238    ///
239    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1551474-numberwithlong)
240    #[inline]
241    #[doc(alias = "numberWithLong")]
242    #[doc(alias = "numberWithLong:")]
243    pub fn from_long(value: c_long) -> Arc<Self> {
244        unsafe { _msg_send_any![Self::class(), numberWithLong: value] }
245    }
246
247    /// Creates a number object from a C `long long`.
248    ///
249    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1551462-numberwithlonglong)
250    #[inline]
251    #[doc(alias = "numberWithLongLong")]
252    #[doc(alias = "numberWithLongLong:")]
253    pub fn from_longlong(value: c_longlong) -> Arc<Self> {
254        unsafe { _msg_send_any![Self::class(), numberWithLongLong: value] }
255    }
256
257    /// Creates a number object from an Objective-C integer.
258    ///
259    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1551473-numberwithinteger)
260    #[inline]
261    #[doc(alias = "numberWithInteger")]
262    #[doc(alias = "numberWithInteger:")]
263    pub fn from_integer(value: NSInteger) -> Arc<Self> {
264        unsafe { _msg_send_any![Self::class(), numberWithInteger: value] }
265    }
266
267    /// Creates a number object from a C `unsigned char`.
268    ///
269    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1551468-numberwithunsignedchar)
270    #[inline]
271    #[doc(alias = "numberWithUnsignedChar")]
272    #[doc(alias = "numberWithUnsignedChar:")]
273    pub fn from_unsigned_char(value: c_uchar) -> Arc<Self> {
274        unsafe { _msg_send_any![Self::class(), numberWithUnsignedChar: value] }
275    }
276
277    /// Creates a number object from a C `unsigned short`.
278    ///
279    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1551467-numberwithunsignedshort)
280    #[inline]
281    #[doc(alias = "numberWithUnsignedShort")]
282    #[doc(alias = "numberWithUnsignedShort:")]
283    pub fn from_unsigned_short(value: c_ushort) -> Arc<Self> {
284        unsafe { _msg_send_any![Self::class(), numberWithUnsignedShort: value] }
285    }
286
287    /// Creates a number object from a C `unsigned int`.
288    ///
289    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1551472-numberwithunsignedint)
290    #[inline]
291    #[doc(alias = "numberWithUnsignedInt")]
292    #[doc(alias = "numberWithUnsignedInt:")]
293    pub fn from_unsigned_int(value: c_uint) -> Arc<Self> {
294        unsafe { _msg_send_any![Self::class(), numberWithUnsignedInt: value] }
295    }
296
297    /// Creates a number object from a C `unsigned long`.
298    ///
299    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1551477-numberwithunsignedlong)
300    #[inline]
301    #[doc(alias = "numberWithUnsignedLong")]
302    #[doc(alias = "numberWithUnsignedLong:")]
303    pub fn from_unsigned_long(value: c_ulong) -> Arc<Self> {
304        unsafe { _msg_send_any![Self::class(), numberWithUnsignedLong: value] }
305    }
306
307    /// Creates a number object from a C `unsigned long long`.
308    ///
309    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1551465-numberwithunsignedlonglong)
310    #[inline]
311    #[doc(alias = "numberWithUnsignedLongLong")]
312    #[doc(alias = "numberWithUnsignedLongLong:")]
313    pub fn from_unsigned_longlong(value: c_ulonglong) -> Arc<Self> {
314        unsafe { _msg_send_any![Self::class(), numberWithUnsignedLongLong: value] }
315    }
316
317    /// Creates a number object from a Objective-C unsigned integer.
318    ///
319    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1551469-numberwithunsignedinteger)
320    #[inline]
321    #[doc(alias = "numberWithUnsignedInteger")]
322    #[doc(alias = "numberWithUnsignedInteger:")]
323    pub fn from_unsigned_integer(value: NSUInteger) -> Arc<Self> {
324        unsafe { _msg_send_any![Self::class(), numberWithUnsignedInteger: value] }
325    }
326}
327
328/// <span id="static-instances">Static instances</span>.
329///
330/// Use these number references over corresponding constructors for better
331/// performance.
332impl NSNumber {
333    // SAFETY: NSNumber is toll-free bridged to CFNumber and CFBoolean, the
334    // underlying types of these statics.
335
336    /// Returns a reference to the equivalent of `@NO`.
337    ///
338    /// This internally references
339    /// [`kCFBooleanFalse`](https://developer.apple.com/documentation/corefoundation/kCFBooleanFalse).
340    #[inline]
341    #[doc(alias = "kCFBooleanFalse")]
342    pub fn no() -> &'static NSNumber {
343        extern "C" {
344            static kCFBooleanFalse: &'static NSNumber;
345        }
346        unsafe { kCFBooleanFalse }
347    }
348
349    /// Returns a reference to the equivalent of `@YES`.
350    ///
351    /// This internally references
352    /// [`kCFBooleanTrue`](https://developer.apple.com/documentation/corefoundation/kCFBooleanTrue).
353    #[inline]
354    #[doc(alias = "kCFBooleanTrue")]
355    pub fn yes() -> &'static NSNumber {
356        extern "C" {
357            static kCFBooleanTrue: &'static NSNumber;
358        }
359        unsafe { kCFBooleanTrue }
360    }
361
362    /// Returns a reference to a
363    /// [NaN (Not a Number)](https://en.wikipedia.org/wiki/NaN) value.
364    ///
365    /// This internally references
366    /// [`kCFNumberNaN`](https://developer.apple.com/documentation/corefoundation/kCFNumberNaN).
367    #[inline]
368    #[doc(alias = "kCFNumberNaN")]
369    pub fn nan() -> &'static NSNumber {
370        extern "C" {
371            static kCFNumberNaN: &'static NSNumber;
372        }
373        unsafe { kCFNumberNaN }
374    }
375
376    /// Returns a reference to the infinity (∞) value.
377    ///
378    /// This internally references
379    /// [`kCFNumberPositiveInfinity`](https://developer.apple.com/documentation/corefoundation/kcfnumberpositiveinfinity).
380    #[inline]
381    #[doc(alias = "kCFNumberPositiveInfinity")]
382    pub fn infinity() -> &'static NSNumber {
383        extern "C" {
384            static kCFNumberPositiveInfinity: &'static NSNumber;
385        }
386        unsafe { kCFNumberPositiveInfinity }
387    }
388
389    /// Returns a reference to the negative infinity (−∞) value.
390    ///
391    /// This internally references
392    /// [`kCFNumberNegativeInfinity`](https://developer.apple.com/documentation/corefoundation/kcfnumbernegativeinfinity).
393    #[inline]
394    #[doc(alias = "kCFNumberNegativeInfinity")]
395    pub fn neg_infinity() -> &'static NSNumber {
396        extern "C" {
397            static kCFNumberNegativeInfinity: &'static NSNumber;
398        }
399        unsafe { kCFNumberNegativeInfinity }
400    }
401}
402
403/// Instance operations.
404impl NSNumber {
405    #[inline]
406    pub(crate) fn _cfboolean_value(&self) -> Option<bool> {
407        if ptr::eq(self, Self::no()) {
408            Some(false)
409        } else if ptr::eq(self, Self::yes()) {
410            Some(true)
411        } else {
412            None
413        }
414    }
415
416    /// Returns an `NSComparisonResult` value that indicates whether the number
417    /// object’s value is greater than, equal to, or less than a given number.
418    ///
419    /// This method follows the standard C rules for type conversion. For
420    /// example, if you compare an NSNumber object that has an integer value
421    /// with an NSNumber object that has a floating point value, the integer
422    /// value is converted to a floating-point value for comparison.
423    ///
424    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1413562-compare)
425    #[inline]
426    pub fn compare(&self, other: &NSNumber) -> NSComparisonResult {
427        unsafe { _msg_send_any![self, compare: other] }
428    }
429
430    /// Returns the number object's value expressed as a human-readable string.
431    ///
432    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1415802-stringvalue)
433    #[inline]
434    #[doc(alias = "stringValue")]
435    pub fn string_value(&self) -> Arc<NSString<'static>> {
436        unsafe { _msg_send_any![self, stringValue] }
437    }
438
439    /// Returns a string that represents the contents of the number object for a
440    /// given locale.
441    ///
442    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1409984-descriptionwithlocale)
443    #[inline]
444    #[doc(alias = "descriptionWithLocale")]
445    pub fn description_with_locale<'l, L>(&self, locale: Option<&L>) -> Arc<NSString>
446    where
447        L: AsRef<ObjCObject<'l>>,
448    {
449        let locale: Option<&ObjCObject<'_>> = match &locale {
450            Some(locale) => Some(locale.as_ref()),
451            None => None,
452        };
453        unsafe { _msg_send_any![self, descriptionWithLocale: locale] }
454    }
455}
456
457/// Accessing numeric values.
458impl NSNumber {
459    // TODO: Implement methods:
460    // - decimalValue
461
462    /// Returns the number object's value expressed as boolean, converted as necessary.
463    ///
464    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1410865-boolvalue).
465    #[inline]
466    #[doc(alias = "boolValue")]
467    pub fn bool_value(&self) -> bool {
468        unsafe { _msg_send_any![self, boolValue => BOOL] }.into()
469    }
470
471    /// Returns the number object's value expressed as a C `float`, converted as necessary.
472    ///
473    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1418317-floatvalue).
474    #[inline]
475    #[doc(alias = "floatValue")]
476    pub fn float_value(&self) -> c_float {
477        unsafe { _msg_send_any![self, floatValue] }
478    }
479
480    /// Returns the number object's value expressed as a C `double`, converted as necessary.
481    ///
482    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1414104-doublevalue).
483    #[inline]
484    #[doc(alias = "doubleValue")]
485    pub fn double_value(&self) -> c_double {
486        unsafe { _msg_send_any![self, doubleValue] }
487    }
488
489    /// Returns the number object's value expressed as a C `char`, converted as necessary.
490    ///
491    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1407838-charvalue).
492    #[inline]
493    #[doc(alias = "charValue")]
494    pub fn char_value(&self) -> c_char {
495        unsafe { _msg_send_any![self, charValue] }
496    }
497
498    /// Returns the number object's value expressed as a C `short`, converted as necessary.
499    ///
500    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1407601-shortvalue).
501    #[inline]
502    #[doc(alias = "shortValue")]
503    pub fn short_value(&self) -> c_short {
504        unsafe { _msg_send_any![self, shortValue] }
505    }
506
507    /// Returns the number object's value expressed as a C `int`, converted as necessary.
508    ///
509    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1407153-intvalue).
510    #[inline]
511    #[doc(alias = "intValue")]
512    pub fn int_value(&self) -> c_int {
513        unsafe { _msg_send_any![self, intValue] }
514    }
515
516    /// Returns the number object's value expressed as a C `long`, converted as necessary.
517    ///
518    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1412566-longvalue).
519    #[inline]
520    #[doc(alias = "longValue")]
521    pub fn long_value(&self) -> c_long {
522        unsafe { _msg_send_any![self, longValue] }
523    }
524
525    /// Returns the number object's value expressed as a C `long long`, converted as necessary.
526    ///
527    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1416870-longlongvalue).
528    #[inline]
529    #[doc(alias = "longLongValue")]
530    pub fn longlong_value(&self) -> c_longlong {
531        unsafe { _msg_send_any![self, longLongValue] }
532    }
533
534    /// Returns the number object's value expressed as an Objective-C integer, converted as necessary.
535    ///
536    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1412554-integervalue).
537    #[inline]
538    #[doc(alias = "integerValue")]
539    pub fn integer_value(&self) -> NSInteger {
540        unsafe { _msg_send_any![self, integerValue] }
541    }
542
543    /// Returns the number object's value expressed as a C `unsigned char`, converted as necessary.
544    ///
545    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1409016-unsignedcharvalue).
546    #[inline]
547    #[doc(alias = "unsignedCharValue")]
548    pub fn unsigned_char_value(&self) -> c_uchar {
549        unsafe { _msg_send_any![self, unsignedCharValue] }
550    }
551
552    /// Returns the number object's value expressed as a C `unsigned short`, converted as necessary.
553    ///
554    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1410604-unsignedshortvalue).
555    #[inline]
556    #[doc(alias = "unsignedShortValue")]
557    pub fn unsigned_short_value(&self) -> c_ushort {
558        unsafe { _msg_send_any![self, unsignedShortValue] }
559    }
560
561    /// Returns the number object's value expressed as a C `unsigned int`, converted as necessary.
562    ///
563    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1417875-unsignedintvalue).
564    #[inline]
565    #[doc(alias = "unsignedIntValue")]
566    pub fn unsigned_int_value(&self) -> c_uint {
567        unsafe { _msg_send_any![self, unsignedIntValue] }
568    }
569
570    /// Returns the number object's value expressed as a C `unsigned long`, converted as necessary.
571    ///
572    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1415252-unsignedlongvalue).
573    #[inline]
574    #[doc(alias = "unsignedLongValue")]
575    pub fn unsigned_long_value(&self) -> c_ulong {
576        unsafe { _msg_send_any![self, unsignedLongValue] }
577    }
578
579    /// Returns the number object's value expressed as a C `unsigned long long`, converted as necessary.
580    ///
581    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1414524-unsignedlonglongvalue).
582    #[inline]
583    #[doc(alias = "unsignedLongLongValue")]
584    pub fn unsigned_longlong_value(&self) -> c_ulonglong {
585        unsafe { _msg_send_any![self, unsignedLongLongValue] }
586    }
587
588    /// Returns the number object's value expressed as an Objective-C unsigned integer, converted as necessary.
589    ///
590    /// See [documentation](https://developer.apple.com/documentation/foundation/nsnumber/1413324-unsignedintegervalue).
591    #[inline]
592    #[doc(alias = "unsignedIntegerValue")]
593    pub fn unsigned_integer_value(&self) -> NSUInteger {
594        unsafe { _msg_send_any![self, unsignedIntegerValue] }
595    }
596}