Skip to main content

mtl_foundation/
number.rs

1//! Value and Number types for Foundation.
2//!
3//! Corresponds to `Foundation/NSNumber.hpp`.
4//!
5//! # C++ Equivalent
6//!
7//! ```cpp
8//! namespace NS {
9//! class Value : public Copying<Value> {
10//! public:
11//!     static Value* value(const void* pValue, const char* pType);
12//!     static Value* value(const void* pPointer);
13//!     static Value* alloc();
14//!     Value*        init(const void* pValue, const char* pType);
15//!     Value*        init(const class Coder* pCoder);
16//!     void          getValue(void* pValue, UInteger size) const;
17//!     const char*   objCType() const;
18//!     bool          isEqualToValue(Value* pValue) const;
19//!     void*         pointerValue() const;
20//! };
21//!
22//! class Number : public Copying<Number, Value> {
23//! public:
24//!     // Many factory methods and accessors for all numeric types
25//! };
26//! }
27//! ```
28
29use std::ffi::{c_char, c_void};
30use std::ptr::NonNull;
31
32use mtl_sys::{class, msg_send_0, msg_send_1, msg_send_2, sel};
33
34use crate::objc_runtime::ComparisonResult;
35use crate::object::{Copying, Referencing};
36use crate::string::String;
37use crate::types::{Integer, UInteger};
38
39/// An Objective-C value object.
40///
41/// C++ equivalent: `NS::Value`
42#[repr(transparent)]
43#[derive(Clone)]
44pub struct Value(NonNull<c_void>);
45
46impl Value {
47    /// Create a value from bytes and type encoding.
48    ///
49    /// C++ equivalent: `static Value* value(const void* pValue, const char* pType)`
50    #[inline]
51    pub fn value(value: *const c_void, obj_c_type: *const c_char) -> Option<Self> {
52        unsafe {
53            let ptr: *mut c_void = msg_send_2(
54                class!(NSValue).as_ptr(),
55                sel!(valueWithBytes:objCType:),
56                value,
57                obj_c_type,
58            );
59            Self::from_ptr(ptr)
60        }
61    }
62
63    /// Create a value from a pointer.
64    ///
65    /// C++ equivalent: `static Value* value(const void* pPointer)`
66    #[inline]
67    pub fn value_with_pointer(pointer: *const c_void) -> Option<Self> {
68        unsafe {
69            let ptr: *mut c_void =
70                msg_send_1(class!(NSValue).as_ptr(), sel!(valueWithPointer:), pointer);
71            Self::from_ptr(ptr)
72        }
73    }
74
75    /// Allocate a new value.
76    ///
77    /// C++ equivalent: `static Value* alloc()`
78    #[inline]
79    pub fn alloc() -> Option<Self> {
80        unsafe {
81            let ptr: *mut c_void = msg_send_0(class!(NSValue).as_ptr(), sel!(alloc));
82            Self::from_ptr(ptr)
83        }
84    }
85
86    /// Initialize with bytes and type encoding.
87    ///
88    /// C++ equivalent: `Value* init(const void* pValue, const char* pType)`
89    #[inline]
90    pub fn init_with_bytes(&self, value: *const c_void, obj_c_type: *const c_char) -> Option<Self> {
91        unsafe {
92            let ptr: *mut c_void = msg_send_2(
93                self.as_ptr(),
94                sel!(initWithBytes:objCType:),
95                value,
96                obj_c_type,
97            );
98            Self::from_ptr(ptr)
99        }
100    }
101
102    /// Initialize with a coder.
103    ///
104    /// C++ equivalent: `Value* init(const class Coder* pCoder)`
105    #[inline]
106    pub fn init_with_coder(&self, coder: *const c_void) -> Option<Self> {
107        unsafe {
108            let ptr: *mut c_void = msg_send_1(self.as_ptr(), sel!(initWithCoder:), coder);
109            Self::from_ptr(ptr)
110        }
111    }
112
113    /// Get the value bytes.
114    ///
115    /// C++ equivalent: `void getValue(void* pValue, UInteger size) const`
116    #[inline]
117    pub fn get_value(&self, value: *mut c_void, size: UInteger) {
118        unsafe {
119            let _: () = msg_send_2(self.as_ptr(), sel!(getValue:size:), value, size);
120        }
121    }
122
123    /// Get the Objective-C type encoding.
124    ///
125    /// C++ equivalent: `const char* objCType() const`
126    #[inline]
127    pub fn objc_type(&self) -> *const c_char {
128        unsafe { msg_send_0(self.as_ptr(), sel!(objCType)) }
129    }
130
131    /// Check if equal to another value.
132    ///
133    /// C++ equivalent: `bool isEqualToValue(Value* pValue) const`
134    #[inline]
135    pub fn is_equal_to_value(&self, value: &Value) -> bool {
136        unsafe { msg_send_1(self.as_ptr(), sel!(isEqualToValue:), value.as_ptr()) }
137    }
138
139    /// Get the pointer value.
140    ///
141    /// C++ equivalent: `void* pointerValue() const`
142    #[inline]
143    pub fn pointer_value(&self) -> *mut c_void {
144        unsafe { msg_send_0(self.as_ptr(), sel!(pointerValue)) }
145    }
146
147    /// Create a Value from a raw pointer.
148    ///
149    /// # Safety
150    ///
151    /// The pointer must be a valid Objective-C NSValue object.
152    #[inline]
153    pub unsafe fn from_ptr(ptr: *mut c_void) -> Option<Self> {
154        NonNull::new(ptr).map(Self)
155    }
156}
157
158impl Referencing for Value {
159    #[inline]
160    fn as_ptr(&self) -> *const c_void {
161        self.0.as_ptr()
162    }
163}
164
165impl Copying for Value {
166    #[inline]
167    fn copy(&self) -> Option<Self> {
168        unsafe {
169            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
170            Self::from_ptr(ptr)
171        }
172    }
173}
174
175unsafe impl Send for Value {}
176unsafe impl Sync for Value {}
177
178/// An Objective-C number object.
179///
180/// C++ equivalent: `NS::Number`
181#[repr(transparent)]
182#[derive(Clone)]
183pub struct Number(NonNull<c_void>);
184
185impl Number {
186    // Static factory methods
187
188    /// Create a number from a char.
189    #[inline]
190    pub fn number_with_char(value: i8) -> Option<Self> {
191        unsafe {
192            let ptr: *mut c_void =
193                msg_send_1(class!(NSNumber).as_ptr(), sel!(numberWithChar:), value);
194            Self::from_ptr(ptr)
195        }
196    }
197
198    /// Create a number from an unsigned char.
199    #[inline]
200    pub fn number_with_unsigned_char(value: u8) -> Option<Self> {
201        unsafe {
202            let ptr: *mut c_void = msg_send_1(
203                class!(NSNumber).as_ptr(),
204                sel!(numberWithUnsignedChar:),
205                value,
206            );
207            Self::from_ptr(ptr)
208        }
209    }
210
211    /// Create a number from a short.
212    #[inline]
213    pub fn number_with_short(value: i16) -> Option<Self> {
214        unsafe {
215            let ptr: *mut c_void =
216                msg_send_1(class!(NSNumber).as_ptr(), sel!(numberWithShort:), value);
217            Self::from_ptr(ptr)
218        }
219    }
220
221    /// Create a number from an unsigned short.
222    #[inline]
223    pub fn number_with_unsigned_short(value: u16) -> Option<Self> {
224        unsafe {
225            let ptr: *mut c_void = msg_send_1(
226                class!(NSNumber).as_ptr(),
227                sel!(numberWithUnsignedShort:),
228                value,
229            );
230            Self::from_ptr(ptr)
231        }
232    }
233
234    /// Create a number from an int.
235    #[inline]
236    pub fn number_with_int(value: i32) -> Option<Self> {
237        unsafe {
238            let ptr: *mut c_void =
239                msg_send_1(class!(NSNumber).as_ptr(), sel!(numberWithInt:), value);
240            Self::from_ptr(ptr)
241        }
242    }
243
244    /// Create a number from an unsigned int.
245    #[inline]
246    pub fn number_with_unsigned_int(value: u32) -> Option<Self> {
247        unsafe {
248            let ptr: *mut c_void = msg_send_1(
249                class!(NSNumber).as_ptr(),
250                sel!(numberWithUnsignedInt:),
251                value,
252            );
253            Self::from_ptr(ptr)
254        }
255    }
256
257    /// Create a number from a long.
258    #[inline]
259    pub fn number_with_long(value: std::ffi::c_long) -> Option<Self> {
260        unsafe {
261            let ptr: *mut c_void =
262                msg_send_1(class!(NSNumber).as_ptr(), sel!(numberWithLong:), value);
263            Self::from_ptr(ptr)
264        }
265    }
266
267    /// Create a number from an unsigned long.
268    #[inline]
269    pub fn number_with_unsigned_long(value: std::ffi::c_ulong) -> Option<Self> {
270        unsafe {
271            let ptr: *mut c_void = msg_send_1(
272                class!(NSNumber).as_ptr(),
273                sel!(numberWithUnsignedLong:),
274                value,
275            );
276            Self::from_ptr(ptr)
277        }
278    }
279
280    /// Create a number from a long long.
281    #[inline]
282    pub fn number_with_long_long(value: i64) -> Option<Self> {
283        unsafe {
284            let ptr: *mut c_void =
285                msg_send_1(class!(NSNumber).as_ptr(), sel!(numberWithLongLong:), value);
286            Self::from_ptr(ptr)
287        }
288    }
289
290    /// Create a number from an unsigned long long.
291    #[inline]
292    pub fn number_with_unsigned_long_long(value: u64) -> Option<Self> {
293        unsafe {
294            let ptr: *mut c_void = msg_send_1(
295                class!(NSNumber).as_ptr(),
296                sel!(numberWithUnsignedLongLong:),
297                value,
298            );
299            Self::from_ptr(ptr)
300        }
301    }
302
303    /// Create a number from a float.
304    #[inline]
305    pub fn number_with_float(value: f32) -> Option<Self> {
306        unsafe {
307            let ptr: *mut c_void =
308                msg_send_1(class!(NSNumber).as_ptr(), sel!(numberWithFloat:), value);
309            Self::from_ptr(ptr)
310        }
311    }
312
313    /// Create a number from a double.
314    #[inline]
315    pub fn number_with_double(value: f64) -> Option<Self> {
316        unsafe {
317            let ptr: *mut c_void =
318                msg_send_1(class!(NSNumber).as_ptr(), sel!(numberWithDouble:), value);
319            Self::from_ptr(ptr)
320        }
321    }
322
323    /// Create a number from a bool.
324    #[inline]
325    pub fn number_with_bool(value: bool) -> Option<Self> {
326        unsafe {
327            let ptr: *mut c_void =
328                msg_send_1(class!(NSNumber).as_ptr(), sel!(numberWithBool:), value);
329            Self::from_ptr(ptr)
330        }
331    }
332
333    /// Allocate a new number.
334    #[inline]
335    pub fn alloc() -> Option<Self> {
336        unsafe {
337            let ptr: *mut c_void = msg_send_0(class!(NSNumber).as_ptr(), sel!(alloc));
338            Self::from_ptr(ptr)
339        }
340    }
341
342    // Init methods
343
344    /// Initialize with a coder.
345    #[inline]
346    pub fn init_with_coder(&self, coder: *const c_void) -> Option<Self> {
347        unsafe {
348            let ptr: *mut c_void = msg_send_1(self.as_ptr(), sel!(initWithCoder:), coder);
349            Self::from_ptr(ptr)
350        }
351    }
352
353    /// Initialize with a char.
354    #[inline]
355    pub fn init_with_char(&self, value: i8) -> Option<Self> {
356        unsafe {
357            let ptr: *mut c_void = msg_send_1(self.as_ptr(), sel!(initWithChar:), value);
358            Self::from_ptr(ptr)
359        }
360    }
361
362    /// Initialize with an unsigned char.
363    #[inline]
364    pub fn init_with_unsigned_char(&self, value: u8) -> Option<Self> {
365        unsafe {
366            let ptr: *mut c_void = msg_send_1(self.as_ptr(), sel!(initWithUnsignedChar:), value);
367            Self::from_ptr(ptr)
368        }
369    }
370
371    /// Initialize with a short.
372    #[inline]
373    pub fn init_with_short(&self, value: i16) -> Option<Self> {
374        unsafe {
375            let ptr: *mut c_void = msg_send_1(self.as_ptr(), sel!(initWithShort:), value);
376            Self::from_ptr(ptr)
377        }
378    }
379
380    /// Initialize with an unsigned short.
381    #[inline]
382    pub fn init_with_unsigned_short(&self, value: u16) -> Option<Self> {
383        unsafe {
384            let ptr: *mut c_void = msg_send_1(self.as_ptr(), sel!(initWithUnsignedShort:), value);
385            Self::from_ptr(ptr)
386        }
387    }
388
389    /// Initialize with an int.
390    #[inline]
391    pub fn init_with_int(&self, value: i32) -> Option<Self> {
392        unsafe {
393            let ptr: *mut c_void = msg_send_1(self.as_ptr(), sel!(initWithInt:), value);
394            Self::from_ptr(ptr)
395        }
396    }
397
398    /// Initialize with an unsigned int.
399    #[inline]
400    pub fn init_with_unsigned_int(&self, value: u32) -> Option<Self> {
401        unsafe {
402            let ptr: *mut c_void = msg_send_1(self.as_ptr(), sel!(initWithUnsignedInt:), value);
403            Self::from_ptr(ptr)
404        }
405    }
406
407    /// Initialize with a long.
408    #[inline]
409    pub fn init_with_long(&self, value: std::ffi::c_long) -> Option<Self> {
410        unsafe {
411            let ptr: *mut c_void = msg_send_1(self.as_ptr(), sel!(initWithLong:), value);
412            Self::from_ptr(ptr)
413        }
414    }
415
416    /// Initialize with an unsigned long.
417    #[inline]
418    pub fn init_with_unsigned_long(&self, value: std::ffi::c_ulong) -> Option<Self> {
419        unsafe {
420            let ptr: *mut c_void = msg_send_1(self.as_ptr(), sel!(initWithUnsignedLong:), value);
421            Self::from_ptr(ptr)
422        }
423    }
424
425    /// Initialize with a long long.
426    #[inline]
427    pub fn init_with_long_long(&self, value: i64) -> Option<Self> {
428        unsafe {
429            let ptr: *mut c_void = msg_send_1(self.as_ptr(), sel!(initWithLongLong:), value);
430            Self::from_ptr(ptr)
431        }
432    }
433
434    /// Initialize with an unsigned long long.
435    #[inline]
436    pub fn init_with_unsigned_long_long(&self, value: u64) -> Option<Self> {
437        unsafe {
438            let ptr: *mut c_void =
439                msg_send_1(self.as_ptr(), sel!(initWithUnsignedLongLong:), value);
440            Self::from_ptr(ptr)
441        }
442    }
443
444    /// Initialize with a float.
445    #[inline]
446    pub fn init_with_float(&self, value: f32) -> Option<Self> {
447        unsafe {
448            let ptr: *mut c_void = msg_send_1(self.as_ptr(), sel!(initWithFloat:), value);
449            Self::from_ptr(ptr)
450        }
451    }
452
453    /// Initialize with a double.
454    #[inline]
455    pub fn init_with_double(&self, value: f64) -> Option<Self> {
456        unsafe {
457            let ptr: *mut c_void = msg_send_1(self.as_ptr(), sel!(initWithDouble:), value);
458            Self::from_ptr(ptr)
459        }
460    }
461
462    /// Initialize with a bool.
463    #[inline]
464    pub fn init_with_bool(&self, value: bool) -> Option<Self> {
465        unsafe {
466            let ptr: *mut c_void = msg_send_1(self.as_ptr(), sel!(initWithBool:), value);
467            Self::from_ptr(ptr)
468        }
469    }
470
471    // Value accessors
472
473    /// Get the char value.
474    #[inline]
475    pub fn char_value(&self) -> i8 {
476        unsafe { msg_send_0(self.as_ptr(), sel!(charValue)) }
477    }
478
479    /// Get the unsigned char value.
480    #[inline]
481    pub fn unsigned_char_value(&self) -> u8 {
482        unsafe { msg_send_0(self.as_ptr(), sel!(unsignedCharValue)) }
483    }
484
485    /// Get the short value.
486    #[inline]
487    pub fn short_value(&self) -> i16 {
488        unsafe { msg_send_0(self.as_ptr(), sel!(shortValue)) }
489    }
490
491    /// Get the unsigned short value.
492    #[inline]
493    pub fn unsigned_short_value(&self) -> u16 {
494        unsafe { msg_send_0(self.as_ptr(), sel!(unsignedShortValue)) }
495    }
496
497    /// Get the int value.
498    #[inline]
499    pub fn int_value(&self) -> i32 {
500        unsafe { msg_send_0(self.as_ptr(), sel!(intValue)) }
501    }
502
503    /// Get the unsigned int value.
504    #[inline]
505    pub fn unsigned_int_value(&self) -> u32 {
506        unsafe { msg_send_0(self.as_ptr(), sel!(unsignedIntValue)) }
507    }
508
509    /// Get the long value.
510    #[inline]
511    pub fn long_value(&self) -> std::ffi::c_long {
512        unsafe { msg_send_0(self.as_ptr(), sel!(longValue)) }
513    }
514
515    /// Get the unsigned long value.
516    #[inline]
517    pub fn unsigned_long_value(&self) -> std::ffi::c_ulong {
518        unsafe { msg_send_0(self.as_ptr(), sel!(unsignedLongValue)) }
519    }
520
521    /// Get the long long value.
522    #[inline]
523    pub fn long_long_value(&self) -> i64 {
524        unsafe { msg_send_0(self.as_ptr(), sel!(longLongValue)) }
525    }
526
527    /// Get the unsigned long long value.
528    #[inline]
529    pub fn unsigned_long_long_value(&self) -> u64 {
530        unsafe { msg_send_0(self.as_ptr(), sel!(unsignedLongLongValue)) }
531    }
532
533    /// Get the float value.
534    #[inline]
535    pub fn float_value(&self) -> f32 {
536        unsafe { msg_send_0(self.as_ptr(), sel!(floatValue)) }
537    }
538
539    /// Get the double value.
540    #[inline]
541    pub fn double_value(&self) -> f64 {
542        unsafe { msg_send_0(self.as_ptr(), sel!(doubleValue)) }
543    }
544
545    /// Get the bool value.
546    #[inline]
547    pub fn bool_value(&self) -> bool {
548        unsafe { msg_send_0(self.as_ptr(), sel!(boolValue)) }
549    }
550
551    /// Get the integer value.
552    #[inline]
553    pub fn integer_value(&self) -> Integer {
554        unsafe { msg_send_0(self.as_ptr(), sel!(integerValue)) }
555    }
556
557    /// Get the unsigned integer value.
558    #[inline]
559    pub fn unsigned_integer_value(&self) -> UInteger {
560        unsafe { msg_send_0(self.as_ptr(), sel!(unsignedIntegerValue)) }
561    }
562
563    /// Get the string value.
564    #[inline]
565    pub fn string_value(&self) -> *mut String {
566        unsafe { msg_send_0(self.as_ptr(), sel!(stringValue)) }
567    }
568
569    /// Compare with another number.
570    #[inline]
571    pub fn compare(&self, other: &Number) -> ComparisonResult {
572        unsafe { msg_send_1(self.as_ptr(), sel!(compare:), other.as_ptr()) }
573    }
574
575    /// Check if equal to another number.
576    #[inline]
577    pub fn is_equal_to_number(&self, number: &Number) -> bool {
578        unsafe { msg_send_1(self.as_ptr(), sel!(isEqualToNumber:), number.as_ptr()) }
579    }
580
581    /// Get description with locale.
582    #[inline]
583    pub fn description_with_locale(&self, locale: *const c_void) -> *mut String {
584        unsafe { msg_send_1(self.as_ptr(), sel!(descriptionWithLocale:), locale) }
585    }
586
587    /// Create a Number from a raw pointer.
588    ///
589    /// # Safety
590    ///
591    /// The pointer must be a valid Objective-C NSNumber object.
592    #[inline]
593    pub unsafe fn from_ptr(ptr: *mut c_void) -> Option<Self> {
594        NonNull::new(ptr).map(Self)
595    }
596}
597
598impl Referencing for Number {
599    #[inline]
600    fn as_ptr(&self) -> *const c_void {
601        self.0.as_ptr()
602    }
603}
604
605impl Copying for Number {
606    #[inline]
607    fn copy(&self) -> Option<Self> {
608        unsafe {
609            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
610            Self::from_ptr(ptr)
611        }
612    }
613}
614
615unsafe impl Send for Number {}
616unsafe impl Sync for Number {}
617
618impl std::fmt::Debug for Number {
619    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
620        f.debug_struct("Number").field("ptr", &self.0).finish()
621    }
622}
623
624#[cfg(test)]
625mod tests {
626    use super::*;
627
628    #[test]
629    fn test_number_size() {
630        assert_eq!(
631            std::mem::size_of::<Number>(),
632            std::mem::size_of::<*mut c_void>()
633        );
634    }
635
636    #[test]
637    fn test_value_size() {
638        assert_eq!(
639            std::mem::size_of::<Value>(),
640            std::mem::size_of::<*mut c_void>()
641        );
642    }
643}