Skip to main content

objc2_core_foundation/
number.rs

1use core::cmp::Ordering;
2use core::ptr;
3
4use crate::{kCFBooleanFalse, kCFBooleanTrue, CFBoolean, CFNumber, CFNumberType, CFRetained};
5
6impl CFBoolean {
7    pub fn new(value: bool) -> &'static CFBoolean {
8        if value {
9            unsafe { kCFBooleanTrue }.unwrap()
10        } else {
11            unsafe { kCFBooleanFalse }.unwrap()
12        }
13    }
14
15    pub fn as_bool(&self) -> bool {
16        self.value()
17    }
18}
19
20macro_rules! def_new_fn {
21    {$(
22        $(#[$($m:meta)*])*
23        ($fn_name:ident($fn_inp:ty); $type:ident),
24    )*} => {$(
25        $(#[$($m)*])*
26        #[inline]
27        pub fn $fn_name(val: $fn_inp) -> CFRetained<Self> {
28            let ptr: *const $fn_inp = &val;
29            unsafe { Self::new(None, CFNumberType::$type, ptr.cast()).expect("failed creating CFNumber") }
30        }
31    )*}
32}
33
34impl CFNumber {
35    def_new_fn! {
36        (new_i8(i8); SInt8Type),
37        (new_i16(i16); SInt16Type),
38        (new_i32(i32); SInt32Type),
39        (new_i64(i64); SInt64Type),
40        (new_isize(isize); NSIntegerType),
41
42        (new_f32(f32); Float32Type),
43        (new_f64(f64); Float64Type),
44    }
45
46    #[cfg(feature = "CFCGTypes")]
47    #[inline]
48    pub fn new_cgfloat(val: crate::CGFloat) -> CFRetained<Self> {
49        #[cfg(not(target_pointer_width = "64"))]
50        {
51            Self::new_f32(val)
52        }
53        #[cfg(target_pointer_width = "64")]
54        {
55            Self::new_f64(val)
56        }
57    }
58}
59
60macro_rules! def_get_fn {
61    {$(
62        $(#[$($m:meta)*])*
63        ($fn_name:ident -> $fn_ret:ty; $type:ident),
64    )*} => {$(
65        $(#[$($m)*])*
66        #[inline]
67        pub fn $fn_name(&self) -> Option<$fn_ret> {
68            let mut value: $fn_ret = <$fn_ret>::default();
69            let ptr: *mut $fn_ret = &mut value;
70            let ret = unsafe { self.value(CFNumberType::$type, ptr.cast()) };
71            if ret {
72                Some(value)
73            } else {
74                None
75            }
76        }
77    )*}
78}
79
80impl CFNumber {
81    def_get_fn! {
82        (as_i8 -> i8; SInt8Type),
83        (as_i16 -> i16; SInt16Type),
84        (as_i32 -> i32; SInt32Type),
85        (as_i64 -> i64; SInt64Type),
86        (as_isize -> isize; NSIntegerType),
87
88        (as_f32 -> f32; Float32Type),
89        (as_f64 -> f64; Float64Type),
90    }
91
92    #[cfg(feature = "CFCGTypes")]
93    #[inline]
94    pub fn as_cgfloat(&self) -> Option<crate::CGFloat> {
95        #[cfg(not(target_pointer_width = "64"))]
96        {
97            self.as_f32()
98        }
99        #[cfg(target_pointer_width = "64")]
100        {
101            self.as_f64()
102        }
103    }
104}
105
106impl PartialOrd for CFNumber {
107    #[inline]
108    #[doc(alias = "CFNumberCompare")]
109    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
110        Some(self.cmp(other))
111    }
112}
113
114impl Ord for CFNumber {
115    #[inline]
116    #[doc(alias = "CFNumberCompare")]
117    fn cmp(&self, other: &Self) -> Ordering {
118        // Documented that one should pass NULL here.
119        let context = ptr::null_mut();
120        unsafe { self.compare(Some(other), context) }.into()
121    }
122}
123
124#[cfg(test)]
125mod tests {
126    use super::*;
127
128    #[test]
129    fn to_from_bool() {
130        let cffalse = CFBoolean::new(false);
131        let cftrue = CFBoolean::new(true);
132        assert_ne!(cffalse, cftrue);
133        assert_eq!(cftrue, CFBoolean::new(true));
134        assert_eq!(cffalse, CFBoolean::new(false));
135        assert!(!cffalse.as_bool());
136        assert!(cftrue.as_bool());
137    }
138
139    #[test]
140    fn to_from_number() {
141        let n = CFNumber::new_i32(442);
142        if cfg!(all(target_os = "macos", target_arch = "x86")) {
143            // Seems to return `None` in the old runtime.
144            assert_eq!(n.as_i8(), None);
145        } else {
146            assert_eq!(n.as_i8(), Some(442i32 as i8));
147        }
148        assert_eq!(n.as_i16(), Some(442));
149        assert_eq!(n.as_i32(), Some(442));
150        assert_eq!(n.as_i64(), Some(442));
151        assert_eq!(n.as_f32(), Some(442.0));
152        assert_eq!(n.as_f64(), Some(442.0));
153    }
154
155    #[test]
156    fn cmp_number() {
157        assert!(CFNumber::new_i32(2) < CFNumber::new_i32(3));
158        assert!(CFNumber::new_i32(3) == CFNumber::new_i32(3));
159        assert!(CFNumber::new_i32(4) > CFNumber::new_i32(3));
160    }
161}