Auto merge of #132 - faern:tcftype-ref-as-associated, r=jdm

Reference type as associated value instead of generic

Each `CFFoo` has exactly one `CFFooRef` and which one is defined by `CFFoo`, not by its user. Thus the type of reference can be an associated type instead of a generic.

As you can see this greatly simplifies things such as calling `instance_of` and `from_CFType_pairs` as well as using `CFPropertyListSubClass`. It basically removes one generic parameter from any method dealing with `TCFType`s in some way.

This is a breaking change, so it would probably mean a `0.5.0` release if accepted. I don't know what your stance on breaking changes or version bumps is, so I don't know if you want this or not. But it would simplify the API, both here, but first and foremost in higher level crates using this.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/core-foundation-rs/132)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo
2018-01-24 11:30:17 -06:00
committed by GitHub
11 changed files with 184 additions and 157 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ name = "core-foundation-sys"
description = "Bindings to Core Foundation for OS X"
homepage = "https://github.com/servo/core-foundation-rs"
repository = "https://github.com/servo/core-foundation-rs"
version = "0.4.6"
version = "0.5.0"
authors = ["The Servo Project Developers"]
license = "MIT / Apache-2.0"
build = "build.rs"
+17
View File
@@ -80,6 +80,23 @@ pub struct CFAllocatorContext {
pub preferredSize: CFAllocatorPreferredSizeCallBack
}
/// Trait for all types which are Core Foundation reference types.
pub trait TCFTypeRef {
fn as_void_ptr(&self) -> *const c_void;
unsafe fn from_void_ptr(ptr: *const c_void) -> Self;
}
impl<T> TCFTypeRef for *const T {
fn as_void_ptr(&self) -> *const c_void {
(*self) as *const c_void
}
unsafe fn from_void_ptr(ptr: *const c_void) -> Self {
ptr as *const T
}
}
extern {
/*
* CFBase.h
+1 -1
View File
@@ -15,7 +15,7 @@ use string::CFStringRef;
#[repr(C)]
pub struct __CFError(c_void);
pub type CFErrorRef = *mut __CFError;
pub type CFErrorRef = *const __CFError;
extern "C" {
pub fn CFErrorGetTypeID() -> CFTypeID;
+2 -2
View File
@@ -3,13 +3,13 @@ name = "core-foundation"
description = "Bindings to Core Foundation for OS X"
homepage = "https://github.com/servo/core-foundation-rs"
repository = "https://github.com/servo/core-foundation-rs"
version = "0.4.6"
version = "0.5.0"
authors = ["The Servo Project Developers"]
license = "MIT / Apache-2.0"
[dependencies.core-foundation-sys]
path = "../core-foundation-sys"
version = "0.4.6"
version = "0.5.0"
[dependencies]
libc = "0.2"
+25 -16
View File
@@ -81,7 +81,7 @@ impl_CFTypeDescriptionGeneric!(CFArray);
impl<T> CFArray<T> {
/// Creates a new `CFArray` with the given elements, which must be `CFType` objects.
pub fn from_CFTypes<R>(elems: &[T]) -> CFArray<T> where T: TCFType<R> {
pub fn from_CFTypes(elems: &[T]) -> CFArray<T> where T: TCFType {
unsafe {
let elems: Vec<CFTypeRef> = elems.iter().map(|elem| elem.as_CFTypeRef()).collect();
let array_ref = CFArrayCreate(kCFAllocatorDefault,
@@ -92,13 +92,18 @@ impl<T> CFArray<T> {
}
}
#[deprecated(note = "please use `as_untyped` instead")]
pub fn to_untyped(self) -> CFArray {
#[inline]
pub fn to_untyped(&self) -> CFArray {
unsafe { CFArray::wrap_under_get_rule(self.0) }
}
pub fn as_untyped(&self) -> CFArray {
unsafe { CFArray::wrap_under_get_rule(self.0) }
/// Returns the same array, but with the type reset to void pointers.
/// Equal to `to_untyped`, but is faster since it does not increment the retain count.
#[inline]
pub fn into_untyped(self) -> CFArray {
let reference = self.0;
mem::forget(self);
unsafe { CFArray::wrap_under_create_rule(reference) }
}
/// Iterates over the elements of this `CFArray`.
@@ -164,15 +169,6 @@ mod tests {
assert_eq!(array.retain_count(), 1);
let untyped_array = array.to_untyped();
assert_eq!(untyped_array.retain_count(), 1);
}
#[test]
fn as_untyped_correct_retain_count() {
let array = CFArray::<CFType>::from_CFTypes(&[]);
assert_eq!(array.retain_count(), 1);
let untyped_array = array.as_untyped();
assert_eq!(array.retain_count(), 2);
assert_eq!(untyped_array.retain_count(), 2);
@@ -180,6 +176,19 @@ mod tests {
assert_eq!(untyped_array.retain_count(), 1);
}
#[test]
fn into_untyped() {
let array = CFArray::<CFType>::from_CFTypes(&[]);
let array2 = array.to_untyped();
assert_eq!(array.retain_count(), 2);
let untyped_array = array.into_untyped();
assert_eq!(untyped_array.retain_count(), 2);
mem::drop(array2);
assert_eq!(untyped_array.retain_count(), 1);
}
#[test]
fn should_box_and_unbox() {
use number::CFNumber;
@@ -215,14 +224,14 @@ mod tests {
assert_eq!(iter.len(), 5);
for elem in iter {
let number: CFNumber = elem.downcast::<_, CFNumber>().unwrap();
let number: CFNumber = elem.downcast::<CFNumber>().unwrap();
sum += number.to_i64().unwrap()
}
assert!(sum == 15);
for elem in arr.iter() {
let number: CFNumber = elem.downcast::<_, CFNumber>().unwrap();
let number: CFNumber = elem.downcast::<CFNumber>().unwrap();
sum += number.to_i64().unwrap()
}
+33 -23
View File
@@ -53,18 +53,19 @@ impl CFType {
/// // Cast it up to a CFType.
/// let cf_type: CFType = string.as_CFType();
/// // Cast it down again.
/// assert!(cf_type.downcast::<_, CFString>().unwrap().to_string() == "FooBar");
/// assert!(cf_type.downcast::<CFString>().unwrap().to_string() == "FooBar");
/// // Casting it to some other type will yield `None`
/// assert!(cf_type.downcast::<_, CFBoolean>().is_none());
/// assert!(cf_type.downcast::<CFBoolean>().is_none());
/// ```
///
/// [`Box::downcast`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast
/// [`CFPropertyList::downcast`]: ../propertylist/struct.CFPropertyList.html#method.downcast
#[inline]
pub fn downcast<Raw, T: TCFType<*const Raw>>(&self) -> Option<T> {
if self.instance_of::<_, T>() {
pub fn downcast<T: TCFType>(&self) -> Option<T> {
if self.instance_of::<T>() {
unsafe {
Some(T::wrap_under_get_rule(self.0 as *const Raw))
let reference = T::Ref::from_void_ptr(self.0);
Some(T::wrap_under_get_rule(reference))
}
} else {
None
@@ -75,11 +76,13 @@ impl CFType {
///
/// [`downcast`]: #method.downcast
#[inline]
pub fn downcast_into<Raw, T: TCFType<*const Raw>>(self) -> Option<T> {
if self.instance_of::<_, T>() {
let reference = self.0 as *const Raw;
mem::forget(self);
unsafe { Some(T::wrap_under_create_rule(reference)) }
pub fn downcast_into<T: TCFType>(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
}
@@ -126,16 +129,20 @@ impl CFAllocator {
}
}
/// All Core Foundation types implement this trait. The type parameter `TypeRef` specifies the
/// All Core Foundation types implement this trait. The associated type `Ref` specifies the
/// associated Core Foundation type: e.g. for `CFType` this is `CFTypeRef`; for `CFArray` this is
/// `CFArrayRef`.
pub trait TCFType<ConcreteTypeRef> {
pub trait TCFType {
/// The reference type wrapped inside this type.
type Ref: TCFTypeRef;
/// Returns the object as its concrete TypeRef.
fn as_concrete_TypeRef(&self) -> ConcreteTypeRef;
fn as_concrete_TypeRef(&self) -> Self::Ref;
/// Returns an instance of the object, wrapping the underlying `CFTypeRef` subclass. Use this
/// when following Core Foundation's "Create Rule". The reference count is *not* bumped.
unsafe fn wrap_under_create_rule(obj: ConcreteTypeRef) -> Self;
unsafe fn wrap_under_create_rule(obj: Self::Ref) -> Self;
/// Returns the type ID for this class.
fn type_id() -> CFTypeID;
@@ -152,7 +159,8 @@ pub trait TCFType<ConcreteTypeRef> {
/// count.
#[inline]
fn into_CFType(self) -> CFType
where Self: Sized
where
Self: Sized,
{
let reference = self.as_CFTypeRef();
mem::forget(self);
@@ -164,7 +172,7 @@ pub trait TCFType<ConcreteTypeRef> {
/// Returns an instance of the object, wrapping the underlying `CFTypeRef` subclass. Use this
/// when following Core Foundation's "Get Rule". The reference count *is* bumped.
unsafe fn wrap_under_get_rule(reference: ConcreteTypeRef) -> Self;
unsafe fn wrap_under_get_rule(reference: Self::Ref) -> Self;
/// Returns the reference count of the object. It is unwise to do anything other than test
/// whether the return value of this method is greater than zero.
@@ -192,12 +200,14 @@ pub trait TCFType<ConcreteTypeRef> {
/// Returns true if this value is an instance of another type.
#[inline]
fn instance_of<OtherConcreteTypeRef,OtherCFType:TCFType<OtherConcreteTypeRef>>(&self) -> bool {
self.type_of() == <OtherCFType as TCFType<_>>::type_id()
fn instance_of<OtherCFType: TCFType>(&self) -> bool {
self.type_of() == OtherCFType::type_id()
}
}
impl TCFType<CFTypeRef> for CFType {
impl TCFType for CFType {
type Ref = CFTypeRef;
#[inline]
fn as_concrete_TypeRef(&self) -> CFTypeRef {
self.0
@@ -238,8 +248,8 @@ mod tests {
let string = CFString::from_static_string("foo");
let cftype = string.as_CFType();
assert!(cftype.instance_of::<_, CFString>());
assert!(!cftype.instance_of::<_, CFBoolean>());
assert!(cftype.instance_of::<CFString>());
assert!(!cftype.instance_of::<CFBoolean>());
}
#[test]
@@ -264,7 +274,7 @@ mod tests {
fn as_cftype_and_downcast() {
let string = CFString::from_static_string("bar");
let cftype = string.as_CFType();
let string2 = cftype.downcast::<_, CFString>().unwrap();
let string2 = cftype.downcast::<CFString>().unwrap();
assert_eq!(string2.to_string(), "bar");
assert_eq!(string.retain_count(), 3);
@@ -276,7 +286,7 @@ mod tests {
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();
let string2 = cftype.downcast_into::<CFString>().unwrap();
assert_eq!(string2.to_string(), "bar");
assert_eq!(string2.retain_count(), 1);
}
+52 -39
View File
@@ -16,7 +16,7 @@ use libc::c_void;
use std::mem;
use std::ptr;
use base::{CFType, CFIndexConvertible, TCFType};
use base::{CFType, CFIndexConvertible, TCFType, TCFTypeRef};
declare_TCFType!{
@@ -27,10 +27,9 @@ impl_TCFType!(CFDictionary, CFDictionaryRef, CFDictionaryGetTypeID);
impl_CFTypeDescription!(CFDictionary);
impl CFDictionary {
pub fn from_CFType_pairs<R1, R2, K, V>(pairs: &[(K, V)]) -> CFDictionary
where K: TCFType<R1>, V: TCFType<R2> {
let (keys, values): (Vec<CFTypeRef>,Vec<CFTypeRef>) =
pairs.iter()
pub fn from_CFType_pairs<K: TCFType, V: TCFType>(pairs: &[(K, V)]) -> CFDictionary {
let (keys, values): (Vec<CFTypeRef>, Vec<CFTypeRef>) = pairs
.iter()
.map(|&(ref key, ref value)| (key.as_CFTypeRef(), value.as_CFTypeRef()))
.unzip();
@@ -59,16 +58,14 @@ impl CFDictionary {
#[inline]
pub fn contains_key(&self, key: *const c_void) -> bool {
unsafe {
CFDictionaryContainsKey(self.0, key) != 0
}
unsafe { CFDictionaryContainsKey(self.0, key) != 0 }
}
/// Similar to `contains_key` but acts on a higher level, automatically converting from any
/// `TCFType` to the raw pointer of its concrete TypeRef.
#[inline]
pub fn contains_key2<X, K: TCFType<*const X>>(&self, key: &K) -> bool {
self.contains_key(key.as_concrete_TypeRef() as *const c_void)
pub fn contains_key2<K: TCFType>(&self, key: &K) -> bool {
self.contains_key(key.as_concrete_TypeRef().as_void_ptr())
}
#[inline]
@@ -86,8 +83,8 @@ impl CFDictionary {
/// Similar to `find` but acts on a higher level, automatically converting from any `TCFType`
/// to the raw pointer of its concrete TypeRef.
#[inline]
pub fn find2<X, K: TCFType<*const X>>(&self, key: &K) -> Option<*const c_void> {
self.find(key.as_concrete_TypeRef() as *const c_void)
pub fn find2<K: TCFType>(&self, key: &K) -> Option<*const c_void> {
self.find(key.as_concrete_TypeRef().as_void_ptr())
}
/// # Panics
@@ -151,8 +148,7 @@ impl CFMutableDictionary {
}
}
pub fn from_CFType_pairs<R1, R2, K, V>(pairs: &[(K, V)]) -> CFMutableDictionary
where K: TCFType<R1>, V: TCFType<R2> {
pub fn from_CFType_pairs<K: TCFType, V: TCFType>(pairs: &[(K, V)]) -> CFMutableDictionary {
let result = Self::with_capacity(pairs.len() as _);
unsafe {
for &(ref key, ref value) in pairs {
@@ -186,8 +182,8 @@ impl CFMutableDictionary {
/// Similar to `contains_key` but acts on a higher level, automatically converting from any
/// `TCFType` to the raw pointer of its concrete TypeRef.
#[inline]
pub fn contains_key2<X, K: TCFType<*const X>>(&self, key: &K) -> bool {
self.contains_key(key.as_concrete_TypeRef() as *const c_void)
pub fn contains_key2<K: TCFType>(&self, key: &K) -> bool {
self.contains_key(key.as_concrete_TypeRef().as_void_ptr())
}
#[inline]
@@ -205,8 +201,8 @@ impl CFMutableDictionary {
/// Similar to `find` but acts on a higher level, automatically converting from any `TCFType`
/// to the raw pointer of its concrete TypeRef.
#[inline]
pub fn find2<X, K: TCFType<*const X>>(&self, key: &K) -> Option<*const c_void> {
self.find(key.as_concrete_TypeRef() as *const c_void)
pub fn find2<K: TCFType>(&self, key: &K) -> Option<*const c_void> {
self.find(key.as_concrete_TypeRef().as_void_ptr())
}
/// # Panics
@@ -250,12 +246,12 @@ impl CFMutableDictionary {
/// Similar to `add` but acts on a higher level, automatically converting from any `TCFType`
/// to the raw pointer of its concrete TypeRef.
#[inline]
pub fn add2<RK, RV, K, V>(&self, key: &K, value: &V)
where K: TCFType<*const RK>,
V: TCFType<*const RV> {
pub fn add2<K: TCFType, V: TCFType>(&self, key: &K, value: &V) {
unsafe {
self.add(key.as_concrete_TypeRef() as *const _,
value.as_concrete_TypeRef() as *const _)
self.add(
key.as_concrete_TypeRef().as_void_ptr(),
value.as_concrete_TypeRef().as_void_ptr(),
)
}
}
@@ -268,12 +264,12 @@ impl CFMutableDictionary {
/// Similar to `set` but acts on a higher level, automatically converting from any `TCFType`
/// to the raw pointer of its concrete TypeRef.
#[inline]
pub fn set2<RK, RV, K, V>(&self, key: &K, value: &V)
where K: TCFType<*const RK>,
V: TCFType<*const RV> {
pub fn set2<K: TCFType, V: TCFType>(&self, key: &K, value: &V) {
unsafe {
self.set(key.as_concrete_TypeRef() as *const c_void,
value.as_concrete_TypeRef() as *const c_void)
self.set(
key.as_concrete_TypeRef().as_void_ptr(),
value.as_concrete_TypeRef().as_void_ptr(),
)
}
}
@@ -286,12 +282,12 @@ impl CFMutableDictionary {
/// Similar to `replace` but acts on a higher level, automatically converting from any `TCFType`
/// to the raw pointer of its concrete TypeRef.
#[inline]
pub fn replace2<RK, RV, K, V>(&self, key: &K, value: &V)
where K: TCFType<*const RK>,
V: TCFType<*const RV> {
pub fn replace2<K: TCFType, V: TCFType>(&self, key: &K, value: &V) {
unsafe {
self.replace(key.as_concrete_TypeRef() as *const c_void,
value.as_concrete_TypeRef() as *const c_void)
self.replace(
key.as_concrete_TypeRef().as_void_ptr(),
value.as_concrete_TypeRef().as_void_ptr(),
)
}
}
@@ -304,11 +300,8 @@ impl CFMutableDictionary {
/// Similar to `remove` but acts on a higher level, automatically converting from any `TCFType`
/// to the raw pointer of its concrete TypeRef.
#[inline]
pub fn remove2<RK, K>(&self, key: &K)
where K: TCFType<*const RK> {
unsafe {
self.remove(key.as_concrete_TypeRef() as *const c_void)
}
pub fn remove2<K: TCFType>(&self, key: &K) {
unsafe { self.remove(key.as_concrete_TypeRef().as_void_ptr()) }
}
#[inline]
@@ -322,10 +315,11 @@ impl CFMutableDictionary {
pub mod test {
use super::*;
use base::TCFType;
use boolean::CFBoolean;
use boolean::{CFBoolean, CFBooleanRef};
use number::CFNumber;
use string::CFString;
#[test]
fn dictionary() {
let bar = CFString::from_static_string("Bar");
@@ -375,4 +369,23 @@ pub mod test {
d.remove_all();
assert_eq!(d.len(), 0)
}
#[test]
fn dict_find2_and_contains_key2() {
let dict = CFDictionary::from_CFType_pairs(&[
(
CFString::from_static_string("hello"),
CFBoolean::true_value(),
),
]);
let key = CFString::from_static_string("hello");
let invalid_key = CFString::from_static_string("foobar");
assert!(dict.contains_key2(&key));
assert!(!dict.contains_key2(&invalid_key));
let value = unsafe { CFBoolean::wrap_under_get_rule(dict.find2(&key).unwrap() as CFBooleanRef) };
assert_eq!(value, CFBoolean::true_value());
assert_eq!(dict.find2(&invalid_key), None);
}
}
+15 -11
View File
@@ -33,15 +33,17 @@ macro_rules! declare_TCFType {
#[macro_export]
macro_rules! impl_TCFType {
($ty:ident, $raw:ident, $ty_id:ident) => {
impl $crate::base::TCFType<$raw> for $ty {
($ty:ident, $ty_ref:ident, $ty_id:ident) => {
impl $crate::base::TCFType for $ty {
type Ref = $ty_ref;
#[inline]
fn as_concrete_TypeRef(&self) -> $raw {
fn as_concrete_TypeRef(&self) -> $ty_ref {
self.0
}
#[inline]
unsafe fn wrap_under_get_rule(reference: $raw) -> $ty {
unsafe fn wrap_under_get_rule(reference: $ty_ref) -> $ty {
use std::mem;
let reference = mem::transmute($crate::base::CFRetain(mem::transmute(reference)));
$crate::base::TCFType::wrap_under_create_rule(reference)
@@ -55,8 +57,8 @@ macro_rules! impl_TCFType {
}
#[inline]
unsafe fn wrap_under_create_rule(obj: $raw) -> $ty {
$ty(obj)
unsafe fn wrap_under_create_rule(reference: $ty_ref) -> $ty {
$ty(reference)
}
#[inline]
@@ -91,15 +93,17 @@ macro_rules! impl_TCFType {
// think of a clean way to have them share code
#[macro_export]
macro_rules! impl_TCFTypeGeneric {
($ty:ident, $raw:ident, $ty_id:ident) => {
impl<T> $crate::base::TCFType<$raw> for $ty<T> {
($ty:ident, $ty_ref:ident, $ty_id:ident) => {
impl<T> $crate::base::TCFType for $ty<T> {
type Ref = $ty_ref;
#[inline]
fn as_concrete_TypeRef(&self) -> $raw {
fn as_concrete_TypeRef(&self) -> $ty_ref {
self.0
}
#[inline]
unsafe fn wrap_under_get_rule(reference: $raw) -> $ty<T> {
unsafe fn wrap_under_get_rule(reference: $ty_ref) -> $ty<T> {
use std::mem;
let reference = mem::transmute($crate::base::CFRetain(mem::transmute(reference)));
$crate::base::TCFType::wrap_under_create_rule(reference)
@@ -113,7 +117,7 @@ macro_rules! impl_TCFTypeGeneric {
}
#[inline]
unsafe fn wrap_under_create_rule(obj: $raw) -> $ty<T> {
unsafe fn wrap_under_create_rule(obj: $ty_ref) -> $ty<T> {
$ty(obj, PhantomData)
}
-30
View File
@@ -51,30 +51,6 @@ impl CFNumber {
if ok { Some(value) } else { None }
}
}
#[deprecated(note = "please use `CFNumber::from` instead")]
#[inline]
pub fn from_i32(value: i32) -> CFNumber {
CFNumber::from(value)
}
#[deprecated(note = "please use `CFNumber::from` instead")]
#[inline]
pub fn from_i64(value: i64) -> CFNumber {
Self::from(value)
}
#[deprecated(note = "please use `CFNumber::from` instead")]
#[inline]
pub fn from_f32(value: f32) -> CFNumber {
Self::from(value)
}
#[deprecated(note = "please use `CFNumber::from` instead")]
#[inline]
pub fn from_f64(value: f64) -> CFNumber {
Self::from(value)
}
}
impl From<i32> for CFNumber {
@@ -132,9 +108,3 @@ impl From<f64> for CFNumber {
}
}
}
/// A convenience function to create CFNumbers.
#[deprecated(note = "please use `CFNumber::from` instead")]
pub fn number(value: i64) -> CFNumber {
CFNumber::from(value)
}
+37 -33
View File
@@ -16,7 +16,7 @@ use libc::c_void;
use error::CFError;
use data::CFData;
use base::{CFType, TCFType};
use base::{CFType, TCFType, TCFTypeRef};
pub use core_foundation_sys::propertylist::*;
use core_foundation_sys::error::CFErrorRef;
@@ -62,13 +62,13 @@ pub fn create_data(property_list: *const c_void, format: CFPropertyListFormat) -
/// Trait for all subclasses of [`CFPropertyList`].
///
/// [`CFPropertyList`]: struct.CFPropertyList.html
pub trait CFPropertyListSubClass<Raw>: TCFType<*const Raw> {
pub trait CFPropertyListSubClass: TCFType {
/// Create an instance of the superclass type [`CFPropertyList`] for this instance.
///
/// [`CFPropertyList`]: struct.CFPropertyList.html
#[inline]
fn to_CFPropertyList(&self) -> CFPropertyList {
unsafe { CFPropertyList::wrap_under_get_rule(self.as_concrete_TypeRef() as *const c_void) }
unsafe { CFPropertyList::wrap_under_get_rule(self.as_concrete_TypeRef().as_void_ptr()) }
}
/// Equal to [`to_CFPropertyList`], but consumes self and avoids changing the reference count.
@@ -76,21 +76,22 @@ pub trait CFPropertyListSubClass<Raw>: TCFType<*const Raw> {
/// [`to_CFPropertyList`]: #method.to_CFPropertyList
#[inline]
fn into_CFPropertyList(self) -> CFPropertyList
where Self: Sized
where
Self: Sized,
{
let reference = self.as_concrete_TypeRef() as *const c_void;
let reference = self.as_concrete_TypeRef().as_void_ptr();
mem::forget(self);
unsafe { CFPropertyList::wrap_under_create_rule(reference) }
}
}
impl CFPropertyListSubClass<::data::__CFData> for ::data::CFData {}
impl CFPropertyListSubClass<::string::__CFString> for ::string::CFString {}
impl CFPropertyListSubClass<::array::__CFArray> for ::array::CFArray {}
impl CFPropertyListSubClass<::dictionary::__CFDictionary> for ::dictionary::CFDictionary {}
impl CFPropertyListSubClass<::date::__CFDate> for ::date::CFDate {}
impl CFPropertyListSubClass<::number::__CFBoolean> for ::boolean::CFBoolean {}
impl CFPropertyListSubClass<::number::__CFNumber> for ::number::CFNumber {}
impl CFPropertyListSubClass for ::data::CFData {}
impl CFPropertyListSubClass for ::string::CFString {}
impl CFPropertyListSubClass for ::array::CFArray {}
impl CFPropertyListSubClass for ::dictionary::CFDictionary {}
impl CFPropertyListSubClass for ::date::CFDate {}
impl CFPropertyListSubClass for ::boolean::CFBoolean {}
impl CFPropertyListSubClass for ::number::CFNumber {}
declare_TCFType!{
@@ -132,7 +133,8 @@ impl CFPropertyList {
#[inline]
pub fn into_CFType(self) -> CFType
where Self: Sized
where
Self: Sized,
{
let reference = self.as_CFTypeRef();
mem::forget(self);
@@ -170,10 +172,8 @@ impl CFPropertyList {
/// Returns true if this value is an instance of another type.
#[inline]
pub fn instance_of<OtherConcreteTypeRef, OtherCFType: TCFType<OtherConcreteTypeRef>>(
&self,
) -> bool {
self.type_of() == <OtherCFType as TCFType<_>>::type_id()
pub fn instance_of<OtherCFType: TCFType>(&self) -> bool {
self.type_of() == OtherCFType::type_id()
}
}
@@ -209,15 +209,17 @@ impl CFPropertyList {
/// // Cast it up to a property list.
/// let propertylist: CFPropertyList = string.to_CFPropertyList();
/// // Cast it down again.
/// assert!(propertylist.downcast::<_, CFString>().unwrap().to_string() == "FooBar");
/// assert!(propertylist.downcast::<CFString>().unwrap().to_string() == "FooBar");
/// ```
///
/// [`CFPropertyList`]: struct.CFPropertyList.html
/// [`Box::downcast`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast
/// [`CFType::downcast`]: ../base/struct.CFType.html#method.downcast
pub fn downcast<Raw, T: CFPropertyListSubClass<Raw>>(&self) -> Option<T> {
if self.instance_of::<_, T>() {
Some(unsafe { T::wrap_under_get_rule(self.0 as *const Raw) })
pub fn downcast<T: CFPropertyListSubClass>(&self) -> Option<T> {
if self.instance_of::<T>() {
unsafe {
let subclass_ref = T::Ref::from_void_ptr(self.0);
Some(T::wrap_under_get_rule(subclass_ref))
}
} else {
None
}
@@ -226,11 +228,13 @@ impl CFPropertyList {
/// Similar to [`downcast`], but consumes self and can thus avoid touching the retain count.
///
/// [`downcast`]: #method.downcast
pub fn downcast_into<Raw, T: CFPropertyListSubClass<Raw>>(self) -> Option<T> {
if self.instance_of::<_, T>() {
let reference = self.0 as *const Raw;
mem::forget(self);
unsafe { Some(T::wrap_under_create_rule(reference)) }
pub fn downcast_into<T: CFPropertyListSubClass>(self) -> Option<T> {
if self.instance_of::<T>() {
unsafe {
let subclass_ref = T::Ref::from_void_ptr(self.0);
mem::forget(self);
Some(T::wrap_under_create_rule(subclass_ref))
}
} else {
None
}
@@ -288,15 +292,15 @@ pub mod test {
#[test]
fn downcast_string() {
let propertylist = CFString::from_static_string("Bar").to_CFPropertyList();
assert!(propertylist.downcast::<_, CFString>().unwrap().to_string() == "Bar");
assert!(propertylist.downcast::<_, CFBoolean>().is_none());
assert!(propertylist.downcast::<CFString>().unwrap().to_string() == "Bar");
assert!(propertylist.downcast::<CFBoolean>().is_none());
}
#[test]
fn downcast_boolean() {
let propertylist = CFBoolean::true_value().to_CFPropertyList();
assert!(propertylist.downcast::<_, CFBoolean>().is_some());
assert!(propertylist.downcast::<_, CFString>().is_none());
assert!(propertylist.downcast::<CFBoolean>().is_some());
assert!(propertylist.downcast::<CFString>().is_none());
}
#[test]
@@ -305,7 +309,7 @@ pub mod test {
let propertylist = string.to_CFPropertyList();
assert_eq!(string.retain_count(), 2);
assert!(propertylist.downcast_into::<_, CFBoolean>().is_none());
assert!(propertylist.downcast_into::<CFBoolean>().is_none());
assert_eq!(string.retain_count(), 1);
}
@@ -315,7 +319,7 @@ pub mod test {
let propertylist = string.to_CFPropertyList();
assert_eq!(string.retain_count(), 2);
let string2 = propertylist.downcast_into::<_, CFString>().unwrap();
let string2 = propertylist.downcast_into::<CFString>().unwrap();
assert!(string2.to_string() == "Bar");
assert_eq!(string2.retain_count(), 2);
}
+1 -1
View File
@@ -26,7 +26,7 @@ impl_CFTypeDescription!(CFSet);
impl CFSet {
/// Creates a new set from a list of `CFType` instances.
pub fn from_slice<R, T>(elems: &[T]) -> CFSet where T: TCFType<R> {
pub fn from_slice<T>(elems: &[T]) -> CFSet where T: TCFType {
unsafe {
let elems: Vec<CFTypeRef> = elems.iter().map(|elem| elem.as_CFTypeRef()).collect();
let set_ref = CFSetCreate(kCFAllocatorDefault,