use crate::{
core::Arc,
core_foundation::{sys, CFAllocator, CFComparisonResult, CFType},
};
use std::{
cmp::Ordering,
mem::{self, MaybeUninit},
ptr,
};
mod type_;
pub use type_::*;
use super::{CFIndex, CFTypeID};
subclass! {
#[derive(PartialEq, Hash)]
pub class CFNumber: CFType<'static>;
}
#[cfg(feature = "foundation")]
cf_bridge!(CFNumber, crate::foundation::NSNumber);
impl Eq for CFNumber {}
impl PartialOrd for CFNumber {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for CFNumber {
#[inline]
#[doc(alias = "CFNumberCompare")]
fn cmp(&self, other: &Self) -> Ordering {
self.compare(other).into()
}
}
impl From<i8> for Arc<CFNumber> {
#[inline]
fn from(value: i8) -> Self {
unsafe { CFNumber::create(None, CFNumberType::I8, &value) }
}
}
impl From<i16> for Arc<CFNumber> {
#[inline]
fn from(value: i16) -> Self {
unsafe { CFNumber::create(None, CFNumberType::I16, &value) }
}
}
impl From<i32> for Arc<CFNumber> {
#[inline]
fn from(value: i32) -> Self {
unsafe { CFNumber::create(None, CFNumberType::I32, &value) }
}
}
impl From<i64> for Arc<CFNumber> {
#[inline]
fn from(value: i64) -> Self {
unsafe { CFNumber::create(None, CFNumberType::I64, &value) }
}
}
impl From<isize> for Arc<CFNumber> {
#[inline]
fn from(value: isize) -> Self {
if mem::size_of::<isize>() == 4 {
(value as i32).into()
} else {
(value as i64).into()
}
}
}
impl From<f32> for Arc<CFNumber> {
#[inline]
fn from(value: f32) -> Self {
unsafe { CFNumber::create(None, CFNumberType::F32, &value) }
}
}
impl From<f64> for Arc<CFNumber> {
#[inline]
fn from(value: f64) -> Self {
unsafe { CFNumber::create(None, CFNumberType::F64, &value) }
}
}
impl CFNumber {
#[inline]
#[doc(alias = "kCFNumberNaN")]
pub fn nan() -> &'static Self {
extern "C" {
static kCFNumberNaN: &'static CFNumber;
}
unsafe { kCFNumberNaN }
}
#[inline]
#[doc(alias = "kCFNumberPositiveInfinity")]
pub fn infinity() -> &'static Self {
extern "C" {
static kCFNumberPositiveInfinity: &'static CFNumber;
}
unsafe { kCFNumberPositiveInfinity }
}
#[inline]
#[doc(alias = "kCFNumberNegativeInfinity")]
pub fn neg_infinity() -> &'static Self {
extern "C" {
static kCFNumberNegativeInfinity: &'static CFNumber;
}
unsafe { kCFNumberNegativeInfinity }
}
}
impl CFNumber {
#[inline]
#[doc(alias = "CFNumberGetTypeID")]
pub fn type_id() -> CFTypeID {
unsafe { sys::CFNumberGetTypeID() }
}
#[inline]
pub fn new<T>(value: T) -> Arc<Self>
where
T: Into<Arc<Self>>,
{
value.into()
}
#[inline]
#[doc(alias = "CFNumberCreate")]
pub unsafe fn create<T>(
allocator: Option<&CFAllocator>,
number_type: CFNumberType,
value: &T,
) -> Arc<Self> {
Arc::from_raw(sys::CFNumberCreate(
match allocator {
Some(allocator) => allocator,
None => ptr::null(),
},
number_type,
(value as *const T).cast(),
))
}
#[inline]
#[doc(alias = "CFNumberCompare")]
pub fn compare(&self, other: &Self) -> CFComparisonResult {
unsafe { sys::CFNumberCompare(self, other, ptr::null_mut()) }
}
#[inline]
#[doc(alias = "CFNumberGetByteSize")]
pub fn byte_size(&self) -> CFIndex {
unsafe { sys::CFNumberGetByteSize(self) }
}
#[inline]
#[doc(alias = "CFNumberGetType")]
pub fn get_type(&self) -> CFNumberType {
unsafe { sys::CFNumberGetType(self) }
}
#[inline]
#[doc(alias = "CFNumberIsFloatType")]
pub fn is_float_type(&self) -> bool {
unsafe { sys::CFNumberIsFloatType(self) != 0 }
}
}
impl CFNumber {
#[inline]
#[doc(alias = "CFNumberGetValue")]
pub unsafe fn get_value<T>(&self, number_type: CFNumberType) -> Option<T> {
let mut value = MaybeUninit::<T>::uninit();
if sys::CFNumberGetValue(self, number_type, value.as_mut_ptr().cast()) != 0 {
Some(value.assume_init())
} else {
None
}
}
#[inline]
pub fn i8_value(&self) -> Option<i8> {
unsafe { self.get_value(CFNumberType::I8) }
}
#[inline]
pub fn i16_value(&self) -> Option<i16> {
unsafe { self.get_value(CFNumberType::I16) }
}
#[inline]
pub fn i32_value(&self) -> Option<i32> {
unsafe { self.get_value(CFNumberType::I32) }
}
#[inline]
pub fn i64_value(&self) -> Option<i64> {
unsafe { self.get_value(CFNumberType::I64) }
}
#[inline]
pub fn isize_value(&self) -> Option<isize> {
if mem::size_of::<isize>() == 4 {
Some(self.i32_value()? as isize)
} else {
Some(self.i64_value()? as isize)
}
}
#[inline]
pub fn f32_value(&self) -> Option<f32> {
unsafe { self.get_value(CFNumberType::F32) }
}
#[inline]
pub fn f64_value(&self) -> Option<f64> {
unsafe { self.get_value(CFNumberType::F64) }
}
}