1 // Copyright 2013 The Servo Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9 
10 use std;
11 use std::fmt;
12 use std::marker::PhantomData;
13 use std::mem;
14 use std::mem::ManuallyDrop;
15 use std::ops::{Deref, DerefMut};
16 use std::os::raw::c_void;
17 
18 pub use core_foundation_sys::base::*;
19 
20 use string::CFString;
21 use ConcreteCFType;
22 
23 pub trait CFIndexConvertible {
24     /// Always use this method to construct a `CFIndex` value. It performs bounds checking to
25     /// ensure the value is in range.
to_CFIndex(self) -> CFIndex26     fn to_CFIndex(self) -> CFIndex;
27 }
28 
29 impl CFIndexConvertible for usize {
30     #[inline]
to_CFIndex(self) -> CFIndex31     fn to_CFIndex(self) -> CFIndex {
32         let max_CFIndex = CFIndex::max_value();
33         if self > (max_CFIndex as usize) {
34             panic!("value out of range")
35         }
36         self as CFIndex
37     }
38 }
39 
40 declare_TCFType!{
41     /// Superclass of all Core Foundation objects.
42     CFType, CFTypeRef
43 }
44 
45 impl CFType {
46     /// Try to downcast the `CFType` to a subclass. Checking if the instance is the
47     /// correct subclass happens at runtime and `None` is returned if it is not the correct type.
48     /// Works similar to [`Box::downcast`] and [`CFPropertyList::downcast`].
49     ///
50     /// # Examples
51     ///
52     /// ```
53     /// # use core_foundation::string::CFString;
54     /// # use core_foundation::boolean::CFBoolean;
55     /// # use core_foundation::base::{CFType, TCFType};
56     /// #
57     /// // Create a string.
58     /// let string: CFString = CFString::from_static_string("FooBar");
59     /// // Cast it up to a CFType.
60     /// let cf_type: CFType = string.as_CFType();
61     /// // Cast it down again.
62     /// assert_eq!(cf_type.downcast::<CFString>().unwrap().to_string(), "FooBar");
63     /// // Casting it to some other type will yield `None`
64     /// assert!(cf_type.downcast::<CFBoolean>().is_none());
65     /// ```
66     ///
67     /// ```compile_fail
68     /// # use core_foundation::array::CFArray;
69     /// # use core_foundation::base::TCFType;
70     /// # use core_foundation::boolean::CFBoolean;
71     /// # use core_foundation::string::CFString;
72     /// #
73     /// let boolean_array = CFArray::from_CFTypes(&[CFBoolean::true_value()]).into_CFType();
74     ///
75     /// // This downcast is not allowed and causes compiler error, since it would cause undefined
76     /// // behavior to access the elements of the array as a CFString:
77     /// let invalid_string_array = boolean_array
78     ///     .downcast_into::<CFArray<CFString>>()
79     ///     .unwrap();
80     /// ```
81     ///
82     /// [`Box::downcast`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast
83     /// [`CFPropertyList::downcast`]: ../propertylist/struct.CFPropertyList.html#method.downcast
84     #[inline]
downcast<T: ConcreteCFType>(&self) -> Option<T>85     pub fn downcast<T: ConcreteCFType>(&self) -> Option<T> {
86         if self.instance_of::<T>() {
87             unsafe {
88                 let reference = T::Ref::from_void_ptr(self.0);
89                 Some(T::wrap_under_get_rule(reference))
90             }
91         } else {
92             None
93         }
94     }
95 
96     /// Similar to [`downcast`], but consumes self and can thus avoid touching the retain count.
97     ///
98     /// [`downcast`]: #method.downcast
99     #[inline]
downcast_into<T: ConcreteCFType>(self) -> Option<T>100     pub fn downcast_into<T: ConcreteCFType>(self) -> Option<T> {
101         if self.instance_of::<T>() {
102             unsafe {
103                 let reference = T::Ref::from_void_ptr(self.0);
104                 mem::forget(self);
105                 Some(T::wrap_under_create_rule(reference))
106             }
107         } else {
108             None
109         }
110     }
111 }
112 
113 impl fmt::Debug for CFType {
114    /// Formats the value using [`CFCopyDescription`].
115    ///
116    /// [`CFCopyDescription`]: https://developer.apple.com/documentation/corefoundation/1521252-cfcopydescription?language=objc
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result117     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118         let desc = unsafe {
119             CFString::wrap_under_create_rule(CFCopyDescription(self.0))
120         };
121         desc.fmt(f)
122     }
123 }
124 
125 impl Clone for CFType {
126     #[inline]
clone(&self) -> CFType127     fn clone(&self) -> CFType {
128         unsafe {
129             TCFType::wrap_under_get_rule(self.0)
130         }
131     }
132 }
133 
134 impl PartialEq for CFType {
135     #[inline]
eq(&self, other: &CFType) -> bool136     fn eq(&self, other: &CFType) -> bool {
137         unsafe {
138             CFEqual(self.as_CFTypeRef(), other.as_CFTypeRef()) != 0
139         }
140     }
141 }
142 
143 declare_TCFType!(CFAllocator, CFAllocatorRef);
144 impl_TCFType!(CFAllocator, CFAllocatorRef, CFAllocatorGetTypeID);
145 
146 impl CFAllocator {
147     #[inline]
new(mut context: CFAllocatorContext) -> CFAllocator148     pub fn new(mut context: CFAllocatorContext) -> CFAllocator {
149         unsafe {
150             let allocator_ref = CFAllocatorCreate(kCFAllocatorDefault, &mut context);
151             TCFType::wrap_under_create_rule(allocator_ref)
152         }
153     }
154 }
155 
156 
157 /// All Core Foundation types implement this trait. The associated type `Ref` specifies the
158 /// associated Core Foundation type: e.g. for `CFType` this is `CFTypeRef`; for `CFArray` this is
159 /// `CFArrayRef`.
160 ///
161 /// Most structs that implement this trait will do so via the [`impl_TCFType`] macro.
162 ///
163 /// [`impl_TCFType`]: ../macro.impl_TCFType.html
164 pub trait TCFType {
165     /// The reference type wrapped inside this type.
166     type Ref: TCFTypeRef;
167 
168     /// Returns the object as its concrete TypeRef.
as_concrete_TypeRef(&self) -> Self::Ref169     fn as_concrete_TypeRef(&self) -> Self::Ref;
170 
171     /// Returns an instance of the object, wrapping the underlying `CFTypeRef` subclass. Use this
172     /// when following Core Foundation's "Create Rule". The reference count is *not* bumped.
wrap_under_create_rule(obj: Self::Ref) -> Self173     unsafe fn wrap_under_create_rule(obj: Self::Ref) -> Self;
174 
175     /// Returns the type ID for this class.
type_id() -> CFTypeID176     fn type_id() -> CFTypeID;
177 
178     /// Returns the object as a wrapped `CFType`. The reference count is incremented by one.
179     #[inline]
as_CFType(&self) -> CFType180     fn as_CFType(&self) -> CFType {
181         unsafe {
182             TCFType::wrap_under_get_rule(self.as_CFTypeRef())
183         }
184     }
185 
186     /// Returns the object as a wrapped `CFType`. Consumes self and avoids changing the reference
187     /// count.
188     #[inline]
into_CFType(self) -> CFType where Self: Sized,189     fn into_CFType(self) -> CFType
190     where
191         Self: Sized,
192     {
193         let reference = self.as_CFTypeRef();
194         mem::forget(self);
195         unsafe { TCFType::wrap_under_create_rule(reference) }
196     }
197 
198     /// Returns the object as a raw `CFTypeRef`. The reference count is not adjusted.
as_CFTypeRef(&self) -> CFTypeRef199     fn as_CFTypeRef(&self) -> CFTypeRef;
200 
201     /// Returns an instance of the object, wrapping the underlying `CFTypeRef` subclass. Use this
202     /// when following Core Foundation's "Get Rule". The reference count *is* bumped.
wrap_under_get_rule(reference: Self::Ref) -> Self203     unsafe fn wrap_under_get_rule(reference: Self::Ref) -> Self;
204 
205     /// Returns the reference count of the object. It is unwise to do anything other than test
206     /// whether the return value of this method is greater than zero.
207     #[inline]
retain_count(&self) -> CFIndex208     fn retain_count(&self) -> CFIndex {
209         unsafe {
210             CFGetRetainCount(self.as_CFTypeRef())
211         }
212     }
213 
214     /// Returns the type ID of this object.
215     #[inline]
type_of(&self) -> CFTypeID216     fn type_of(&self) -> CFTypeID {
217         unsafe {
218             CFGetTypeID(self.as_CFTypeRef())
219         }
220     }
221 
222     /// Writes a debugging version of this object on standard error.
show(&self)223     fn show(&self) {
224         unsafe {
225             CFShow(self.as_CFTypeRef())
226         }
227     }
228 
229     /// Returns true if this value is an instance of another type.
230     #[inline]
instance_of<OtherCFType: TCFType>(&self) -> bool231     fn instance_of<OtherCFType: TCFType>(&self) -> bool {
232         self.type_of() == OtherCFType::type_id()
233     }
234 }
235 
236 impl TCFType for CFType {
237     type Ref = CFTypeRef;
238 
239     #[inline]
as_concrete_TypeRef(&self) -> CFTypeRef240     fn as_concrete_TypeRef(&self) -> CFTypeRef {
241         self.0
242     }
243 
244     #[inline]
wrap_under_get_rule(reference: CFTypeRef) -> CFType245     unsafe fn wrap_under_get_rule(reference: CFTypeRef) -> CFType {
246         assert!(!reference.is_null(), "Attempted to create a NULL object.");
247         let reference: CFTypeRef = CFRetain(reference);
248         TCFType::wrap_under_create_rule(reference)
249     }
250 
251     #[inline]
as_CFTypeRef(&self) -> CFTypeRef252     fn as_CFTypeRef(&self) -> CFTypeRef {
253         self.as_concrete_TypeRef()
254     }
255 
256     #[inline]
wrap_under_create_rule(obj: CFTypeRef) -> CFType257     unsafe fn wrap_under_create_rule(obj: CFTypeRef) -> CFType {
258         assert!(!obj.is_null(), "Attempted to create a NULL object.");
259         CFType(obj)
260     }
261 
262     #[inline]
type_id() -> CFTypeID263     fn type_id() -> CFTypeID {
264         // FIXME(pcwalton): Is this right?
265         0
266     }
267 }
268 
269 /// A reference to an element inside a container
270 pub struct ItemRef<'a, T: 'a>(ManuallyDrop<T>, PhantomData<&'a T>);
271 
272 impl<'a, T> Deref for ItemRef<'a, T> {
273     type Target = T;
274 
deref(&self) -> &T275     fn deref(&self) -> &T {
276         &self.0
277     }
278 }
279 
280 impl<'a, T: fmt::Debug> fmt::Debug for ItemRef<'a, T> {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>281     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
282         self.0.fmt(f)
283     }
284 }
285 
286 impl<'a, T: PartialEq> PartialEq for ItemRef<'a, T> {
eq(&self, other: &Self) -> bool287     fn eq(&self, other: &Self) -> bool {
288         self.0.eq(&other.0)
289     }
290 }
291 
292 /// A reference to a mutable element inside a container
293 pub struct ItemMutRef<'a, T: 'a>(ManuallyDrop<T>, PhantomData<&'a T>);
294 
295 impl<'a, T> Deref for ItemMutRef<'a, T> {
296     type Target = T;
297 
deref(&self) -> &T298     fn deref(&self) -> &T {
299         &self.0
300     }
301 }
302 
303 impl<'a, T> DerefMut for ItemMutRef<'a, T> {
deref_mut(&mut self) -> &mut T304     fn deref_mut(&mut self) -> &mut T {
305         &mut self.0
306     }
307 }
308 
309 impl<'a, T: fmt::Debug> fmt::Debug for ItemMutRef<'a, T> {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>310     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
311         self.0.fmt(f)
312     }
313 }
314 
315 impl<'a, T: PartialEq> PartialEq for ItemMutRef<'a, T> {
eq(&self, other: &Self) -> bool316     fn eq(&self, other: &Self) -> bool {
317         self.0.eq(&other.0)
318     }
319 }
320 
321 /// A trait describing how to convert from the stored *mut c_void to the desired T
322 pub unsafe trait FromMutVoid {
from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> where Self: std::marker::Sized323     unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> where Self: std::marker::Sized;
324 }
325 
326 unsafe impl FromMutVoid for u32 {
from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self>327     unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> {
328         ItemMutRef(ManuallyDrop::new(x as u32), PhantomData)
329     }
330 }
331 
332 unsafe impl FromMutVoid for *const c_void {
from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self>333     unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> {
334         ItemMutRef(ManuallyDrop::new(x), PhantomData)
335     }
336 }
337 
338 unsafe impl<T: TCFType> FromMutVoid for T {
from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self>339     unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> {
340         ItemMutRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData)
341     }
342 }
343 
344 /// A trait describing how to convert from the stored *const c_void to the desired T
345 pub unsafe trait FromVoid {
from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> where Self: std::marker::Sized346     unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> where Self: std::marker::Sized;
347 }
348 
349 unsafe impl FromVoid for u32 {
from_void<'a>(x: *const c_void) -> ItemRef<'a, Self>350     unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> {
351         // Functions like CGFontCopyTableTags treat the void*'s as u32's
352         // so we convert by casting directly
353         ItemRef(ManuallyDrop::new(x as u32), PhantomData)
354     }
355 }
356 
357 unsafe impl FromVoid for *const c_void {
from_void<'a>(x: *const c_void) -> ItemRef<'a, Self>358     unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> {
359         ItemRef(ManuallyDrop::new(x), PhantomData)
360     }
361 }
362 
363 unsafe impl<T: TCFType> FromVoid for T {
from_void<'a>(x: *const c_void) -> ItemRef<'a, Self>364     unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> {
365         ItemRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData)
366     }
367 }
368 
369 /// A trait describing how to convert from the stored *const c_void to the desired T
370 pub unsafe trait ToVoid<T> {
to_void(&self) -> *const c_void371     fn to_void(&self) -> *const c_void;
372 }
373 
374 unsafe impl ToVoid<*const c_void> for *const c_void {
to_void(&self) -> *const c_void375     fn to_void(&self) -> *const c_void {
376         *self
377     }
378 }
379 
380 unsafe impl<'a> ToVoid<CFType> for &'a CFType {
to_void(&self) -> *const ::std::os::raw::c_void381     fn to_void(&self) -> *const ::std::os::raw::c_void {
382         self.as_concrete_TypeRef().as_void_ptr()
383     }
384 }
385 
386 unsafe impl ToVoid<CFType> for CFType {
to_void(&self) -> *const ::std::os::raw::c_void387     fn to_void(&self) -> *const ::std::os::raw::c_void {
388         self.as_concrete_TypeRef().as_void_ptr()
389     }
390 }
391 
392 unsafe impl ToVoid<CFType> for CFTypeRef {
to_void(&self) -> *const ::std::os::raw::c_void393     fn to_void(&self) -> *const ::std::os::raw::c_void {
394         self.as_void_ptr()
395     }
396 }
397 
398 
399 #[cfg(test)]
400 mod tests {
401     use super::*;
402     use std::mem;
403     use boolean::CFBoolean;
404 
405     #[test]
cftype_instance_of()406     fn cftype_instance_of() {
407         let string = CFString::from_static_string("foo");
408         let cftype = string.as_CFType();
409 
410         assert!(cftype.instance_of::<CFString>());
411         assert!(!cftype.instance_of::<CFBoolean>());
412     }
413 
414     #[test]
as_cftype_retain_count()415     fn as_cftype_retain_count() {
416         let string = CFString::from_static_string("bar");
417         assert_eq!(string.retain_count(), 1);
418         let cftype = string.as_CFType();
419         assert_eq!(cftype.retain_count(), 2);
420         mem::drop(string);
421         assert_eq!(cftype.retain_count(), 1);
422     }
423 
424     #[test]
into_cftype_retain_count()425     fn into_cftype_retain_count() {
426         let string = CFString::from_static_string("bar");
427         assert_eq!(string.retain_count(), 1);
428         let cftype = string.into_CFType();
429         assert_eq!(cftype.retain_count(), 1);
430     }
431 
432     #[test]
as_cftype_and_downcast()433     fn as_cftype_and_downcast() {
434         let string = CFString::from_static_string("bar");
435         let cftype = string.as_CFType();
436         let string2 = cftype.downcast::<CFString>().unwrap();
437         assert_eq!(string2.to_string(), "bar");
438 
439         assert_eq!(string.retain_count(), 3);
440         assert_eq!(cftype.retain_count(), 3);
441         assert_eq!(string2.retain_count(), 3);
442     }
443 
444     #[test]
into_cftype_and_downcast_into()445     fn into_cftype_and_downcast_into() {
446         let string = CFString::from_static_string("bar");
447         let cftype = string.into_CFType();
448         let string2 = cftype.downcast_into::<CFString>().unwrap();
449         assert_eq!(string2.to_string(), "bar");
450         assert_eq!(string2.retain_count(), 1);
451     }
452 }
453