use std;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut};
use std::os::raw::c_void;
pub use core_foundation_sys::base::*;
use string::CFString;
use ConcreteCFType;
pub trait CFIndexConvertible {
fn to_CFIndex(self) -> CFIndex;
}
impl CFIndexConvertible for usize {
#[inline]
fn to_CFIndex(self) -> CFIndex {
let max_CFIndex = CFIndex::max_value();
if self > (max_CFIndex as usize) {
panic!("value out of range")
}
self as CFIndex
}
}
declare_TCFType!{
CFType, CFTypeRef
}
impl CFType {
#[inline]
pub fn downcast<T: ConcreteCFType>(&self) -> Option<T> {
if self.instance_of::<T>() {
unsafe {
let reference = T::Ref::from_void_ptr(self.0);
Some(T::wrap_under_get_rule(reference))
}
} else {
None
}
}
#[inline]
pub fn downcast_into<T: ConcreteCFType>(self) -> Option<T> {
if self.instance_of::<T>() {
unsafe {
let reference = T::Ref::from_void_ptr(self.0);
mem::forget(self);
Some(T::wrap_under_create_rule(reference))
}
} else {
None
}
}
}
impl fmt::Debug for CFType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let desc = unsafe {
CFString::wrap_under_create_rule(CFCopyDescription(self.0))
};
desc.fmt(f)
}
}
impl Clone for CFType {
#[inline]
fn clone(&self) -> CFType {
unsafe {
TCFType::wrap_under_get_rule(self.0)
}
}
}
impl PartialEq for CFType {
#[inline]
fn eq(&self, other: &CFType) -> bool {
unsafe {
CFEqual(self.as_CFTypeRef(), other.as_CFTypeRef()) != 0
}
}
}
declare_TCFType!(CFAllocator, CFAllocatorRef);
impl_TCFType!(CFAllocator, CFAllocatorRef, CFAllocatorGetTypeID);
impl CFAllocator {
#[inline]
pub fn new(mut context: CFAllocatorContext) -> CFAllocator {
unsafe {
let allocator_ref = CFAllocatorCreate(kCFAllocatorDefault, &mut context);
TCFType::wrap_under_create_rule(allocator_ref)
}
}
}
pub trait TCFType {
type Ref: TCFTypeRef;
fn as_concrete_TypeRef(&self) -> Self::Ref;
unsafe fn wrap_under_create_rule(obj: Self::Ref) -> Self;
fn type_id() -> CFTypeID;
#[inline]
fn as_CFType(&self) -> CFType {
unsafe {
TCFType::wrap_under_get_rule(self.as_CFTypeRef())
}
}
#[inline]
fn into_CFType(self) -> CFType
where
Self: Sized,
{
let reference = self.as_CFTypeRef();
mem::forget(self);
unsafe { TCFType::wrap_under_create_rule(reference) }
}
fn as_CFTypeRef(&self) -> CFTypeRef;
unsafe fn wrap_under_get_rule(reference: Self::Ref) -> Self;
#[inline]
fn retain_count(&self) -> CFIndex {
unsafe {
CFGetRetainCount(self.as_CFTypeRef())
}
}
#[inline]
fn type_of(&self) -> CFTypeID {
unsafe {
CFGetTypeID(self.as_CFTypeRef())
}
}
fn show(&self) {
unsafe {
CFShow(self.as_CFTypeRef())
}
}
#[inline]
fn instance_of<OtherCFType: TCFType>(&self) -> bool {
self.type_of() == OtherCFType::type_id()
}
}
impl TCFType for CFType {
type Ref = CFTypeRef;
#[inline]
fn as_concrete_TypeRef(&self) -> CFTypeRef {
self.0
}
#[inline]
unsafe fn wrap_under_get_rule(reference: CFTypeRef) -> CFType {
let reference: CFTypeRef = CFRetain(reference);
TCFType::wrap_under_create_rule(reference)
}
#[inline]
fn as_CFTypeRef(&self) -> CFTypeRef {
self.as_concrete_TypeRef()
}
#[inline]
unsafe fn wrap_under_create_rule(obj: CFTypeRef) -> CFType {
CFType(obj)
}
#[inline]
fn type_id() -> CFTypeID {
0
}
}
pub struct ItemRef<'a, T: 'a>(ManuallyDrop<T>, PhantomData<&'a T>);
impl<'a, T> Deref for ItemRef<'a, T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<'a, T: fmt::Debug> fmt::Debug for ItemRef<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.0.fmt(f)
}
}
impl<'a, T: PartialEq> PartialEq for ItemRef<'a, T> {
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
pub struct ItemMutRef<'a, T: 'a>(ManuallyDrop<T>, PhantomData<&'a T>);
impl<'a, T> Deref for ItemMutRef<'a, T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<'a, T> DerefMut for ItemMutRef<'a, T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<'a, T: fmt::Debug> fmt::Debug for ItemMutRef<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.0.fmt(f)
}
}
impl<'a, T: PartialEq> PartialEq for ItemMutRef<'a, T> {
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
pub unsafe trait FromMutVoid {
unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> where Self: std::marker::Sized;
}
unsafe impl FromMutVoid for u32 {
unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> {
ItemMutRef(ManuallyDrop::new(x as u32), PhantomData)
}
}
unsafe impl FromMutVoid for *const c_void {
unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> {
ItemMutRef(ManuallyDrop::new(x), PhantomData)
}
}
unsafe impl<T: TCFType> FromMutVoid for T {
unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> {
ItemMutRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData)
}
}
pub unsafe trait FromVoid {
unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> where Self: std::marker::Sized;
}
unsafe impl FromVoid for u32 {
unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> {
ItemRef(ManuallyDrop::new(x as u32), PhantomData)
}
}
unsafe impl FromVoid for *const c_void {
unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> {
ItemRef(ManuallyDrop::new(x), PhantomData)
}
}
unsafe impl<T: TCFType> FromVoid for T {
unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> {
ItemRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData)
}
}
pub unsafe trait ToVoid<T> {
fn to_void(&self) -> *const c_void;
}
unsafe impl ToVoid<*const c_void> for *const c_void {
fn to_void(&self) -> *const c_void {
*self
}
}
unsafe impl<'a> ToVoid<CFType> for &'a CFType {
fn to_void(&self) -> *const ::std::os::raw::c_void {
self.as_concrete_TypeRef().as_void_ptr()
}
}
unsafe impl ToVoid<CFType> for CFType {
fn to_void(&self) -> *const ::std::os::raw::c_void {
self.as_concrete_TypeRef().as_void_ptr()
}
}
unsafe impl ToVoid<CFType> for CFTypeRef {
fn to_void(&self) -> *const ::std::os::raw::c_void {
self.as_void_ptr()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem;
use boolean::CFBoolean;
#[test]
fn cftype_instance_of() {
let string = CFString::from_static_string("foo");
let cftype = string.as_CFType();
assert!(cftype.instance_of::<CFString>());
assert!(!cftype.instance_of::<CFBoolean>());
}
#[test]
fn as_cftype_retain_count() {
let string = CFString::from_static_string("bar");
assert_eq!(string.retain_count(), 1);
let cftype = string.as_CFType();
assert_eq!(cftype.retain_count(), 2);
mem::drop(string);
assert_eq!(cftype.retain_count(), 1);
}
#[test]
fn into_cftype_retain_count() {
let string = CFString::from_static_string("bar");
assert_eq!(string.retain_count(), 1);
let cftype = string.into_CFType();
assert_eq!(cftype.retain_count(), 1);
}
#[test]
fn as_cftype_and_downcast() {
let string = CFString::from_static_string("bar");
let cftype = string.as_CFType();
let string2 = cftype.downcast::<CFString>().unwrap();
assert_eq!(string2.to_string(), "bar");
assert_eq!(string.retain_count(), 3);
assert_eq!(cftype.retain_count(), 3);
assert_eq!(string2.retain_count(), 3);
}
#[test]
fn into_cftype_and_downcast_into() {
let string = CFString::from_static_string("bar");
let cftype = string.into_CFType();
let string2 = cftype.downcast_into::<CFString>().unwrap();
assert_eq!(string2.to_string(), "bar");
assert_eq!(string2.retain_count(), 1);
}
}