pub use core_foundation_sys::array::*;
pub use core_foundation_sys::base::{CFIndex, CFRelease};
use core_foundation_sys::base::{CFTypeRef, kCFAllocatorDefault};
use base::CFType;
use libc::c_void;
use std::mem;
use std::marker::PhantomData;
use base::{CFIndexConvertible, TCFType, CFRange};
pub struct CFArray<T = *const c_void>(CFArrayRef, PhantomData<T>);
pub unsafe trait FromVoid {
unsafe fn from_void(x: *const c_void) -> Self;
}
unsafe impl FromVoid for u32 {
unsafe fn from_void(x: *const c_void) -> u32 {
x as usize as u32
}
}
unsafe impl FromVoid for *const c_void {
unsafe fn from_void(x: *const c_void) -> *const c_void {
x
}
}
unsafe impl FromVoid for CFType {
unsafe fn from_void(x: *const c_void) -> CFType {
TCFType::wrap_under_get_rule(mem::transmute(x))
}
}
impl<T> Drop for CFArray<T> {
fn drop(&mut self) {
unsafe {
CFRelease(self.as_CFTypeRef())
}
}
}
pub struct CFArrayIterator<'a, T: 'a> {
array: &'a CFArray<T>,
index: CFIndex,
}
impl<'a, T: FromVoid> Iterator for CFArrayIterator<'a, T> {
type Item = T;
fn next(&mut self) -> Option<T> {
if self.index >= self.array.len() {
None
} else {
let value = self.array.get(self.index);
self.index += 1;
Some(value)
}
}
}
impl<'a, T: FromVoid> ExactSizeIterator for CFArrayIterator<'a, T> {
fn len(&self) -> usize {
(self.array.len() - self.index) as usize
}
}
impl_TCFTypeGeneric!(CFArray, CFArrayRef, CFArrayGetTypeID);
impl_CFTypeDescriptionGeneric!(CFArray);
impl<T> CFArray<T> {
pub fn from_CFTypes<R>(elems: &[T]) -> CFArray<T> where T: TCFType<R> {
unsafe {
let elems: Vec<CFTypeRef> = elems.iter().map(|elem| elem.as_CFTypeRef()).collect();
let array_ref = CFArrayCreate(kCFAllocatorDefault,
mem::transmute(elems.as_ptr()),
elems.len().to_CFIndex(),
&kCFTypeArrayCallBacks);
TCFType::wrap_under_create_rule(array_ref)
}
}
pub fn to_untyped(self) -> CFArray {
CFArray(self.0, PhantomData)
}
#[inline]
pub fn iter<'a>(&'a self) -> CFArrayIterator<'a, T> {
CFArrayIterator {
array: self,
index: 0
}
}
#[inline]
pub fn len(&self) -> CFIndex {
unsafe {
CFArrayGetCount(self.0)
}
}
#[inline]
pub fn get(&self, index: CFIndex) -> T where T: FromVoid {
assert!(index < self.len());
unsafe { T::from_void(CFArrayGetValueAtIndex(self.0, index)) }
}
pub fn get_values(&self, range: CFRange) -> Vec<*const c_void> {
let mut vec = Vec::with_capacity(range.length as usize);
unsafe {
CFArrayGetValues(self.0, range, vec.as_mut_ptr());
vec.set_len(range.length as usize);
vec
}
}
pub fn get_all_values(&self) -> Vec<*const c_void> {
self.get_values(CFRange {
location: 0,
length: self.len()
})
}
}
impl<'a, T: FromVoid> IntoIterator for &'a CFArray<T> {
type Item = T;
type IntoIter = CFArrayIterator<'a, T>;
fn into_iter(self) -> CFArrayIterator<'a, T> {
self.iter()
}
}
#[test]
fn should_box_and_unbox() {
use number::{CFNumber, number};
let n0 = number(0);
let n1 = number(1);
let n2 = number(2);
let n3 = number(3);
let n4 = number(4);
let n5 = number(5);
let arr = CFArray::from_CFTypes(&[
n0.as_CFType(),
n1.as_CFType(),
n2.as_CFType(),
n3.as_CFType(),
n4.as_CFType(),
n5.as_CFType(),
]);
assert!(arr.get_all_values() == &[n0.as_CFTypeRef(),
n1.as_CFTypeRef(),
n2.as_CFTypeRef(),
n3.as_CFTypeRef(),
n4.as_CFTypeRef(),
n5.as_CFTypeRef()]);
unsafe {
let mut sum = 0;
let mut iter = arr.iter();
assert_eq!(iter.len(), 6);
assert!(iter.next().is_some());
assert_eq!(iter.len(), 5);
for elem in iter {
let number: CFNumber = TCFType::wrap_under_get_rule(mem::transmute(elem));
sum += number.to_i64().unwrap()
}
assert!(sum == 15);
for elem in arr.iter() {
let number: CFNumber = TCFType::wrap_under_get_rule(mem::transmute(elem));
sum += number.to_i64().unwrap()
}
assert!(sum == 30);
}
}