1use std;
11use std::fmt;
12use std::marker::PhantomData;
13use std::mem;
14use std::mem::ManuallyDrop;
15use std::ops::{Deref, DerefMut};
16use std::os::raw::c_void;
17
18pub use core_foundation_sys::base::*;
19
20use crate::string::CFString;
21use crate::ConcreteCFType;
22
23pub trait CFIndexConvertible {
24 fn to_CFIndex(self) -> CFIndex;
27}
28
29impl CFIndexConvertible for usize {
30 #[inline]
31 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
40declare_TCFType! {
41 CFType, CFTypeRef
43}
44
45impl CFType {
46 #[inline]
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 #[inline]
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
113impl fmt::Debug for CFType {
114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118 let desc = unsafe { CFString::wrap_under_create_rule(CFCopyDescription(self.0)) };
119 desc.fmt(f)
120 }
121}
122
123impl Clone for CFType {
124 #[inline]
125 fn clone(&self) -> CFType {
126 unsafe { TCFType::wrap_under_get_rule(self.0) }
127 }
128}
129
130impl PartialEq for CFType {
131 #[inline]
132 fn eq(&self, other: &CFType) -> bool {
133 unsafe { CFEqual(self.as_CFTypeRef(), other.as_CFTypeRef()) != 0 }
134 }
135}
136
137declare_TCFType!(CFAllocator, CFAllocatorRef);
138impl_TCFType!(CFAllocator, CFAllocatorRef, CFAllocatorGetTypeID);
139
140impl CFAllocator {
141 #[inline]
142 pub fn new(mut context: CFAllocatorContext) -> CFAllocator {
143 unsafe {
144 let allocator_ref = CFAllocatorCreate(kCFAllocatorDefault, &mut context);
145 TCFType::wrap_under_create_rule(allocator_ref)
146 }
147 }
148}
149
150pub trait TCFType {
158 type Ref: TCFTypeRef;
160
161 fn as_concrete_TypeRef(&self) -> Self::Ref;
163
164 unsafe fn wrap_under_create_rule(obj: Self::Ref) -> Self;
167
168 fn type_id() -> CFTypeID;
170
171 #[inline]
173 fn as_CFType(&self) -> CFType {
174 unsafe { TCFType::wrap_under_get_rule(self.as_CFTypeRef()) }
175 }
176
177 #[inline]
180 fn into_CFType(self) -> CFType
181 where
182 Self: Sized,
183 {
184 let reference = self.as_CFTypeRef();
185 mem::forget(self);
186 unsafe { TCFType::wrap_under_create_rule(reference) }
187 }
188
189 fn as_CFTypeRef(&self) -> CFTypeRef;
191
192 unsafe fn wrap_under_get_rule(reference: Self::Ref) -> Self;
195
196 #[inline]
199 fn retain_count(&self) -> CFIndex {
200 unsafe { CFGetRetainCount(self.as_CFTypeRef()) }
201 }
202
203 #[inline]
205 fn type_of(&self) -> CFTypeID {
206 unsafe { CFGetTypeID(self.as_CFTypeRef()) }
207 }
208
209 fn show(&self) {
211 unsafe { CFShow(self.as_CFTypeRef()) }
212 }
213
214 #[inline]
216 fn instance_of<OtherCFType: TCFType>(&self) -> bool {
217 self.type_of() == OtherCFType::type_id()
218 }
219}
220
221impl TCFType for CFType {
222 type Ref = CFTypeRef;
223
224 #[inline]
225 fn as_concrete_TypeRef(&self) -> CFTypeRef {
226 self.0
227 }
228
229 #[inline]
230 unsafe fn wrap_under_get_rule(reference: CFTypeRef) -> CFType {
231 assert!(!reference.is_null(), "Attempted to create a NULL object.");
232 let reference: CFTypeRef = CFRetain(reference);
233 TCFType::wrap_under_create_rule(reference)
234 }
235
236 #[inline]
237 fn as_CFTypeRef(&self) -> CFTypeRef {
238 self.as_concrete_TypeRef()
239 }
240
241 #[inline]
242 unsafe fn wrap_under_create_rule(obj: CFTypeRef) -> CFType {
243 assert!(!obj.is_null(), "Attempted to create a NULL object.");
244 CFType(obj)
245 }
246
247 #[inline]
248 fn type_id() -> CFTypeID {
249 0
251 }
252}
253
254pub struct ItemRef<'a, T: 'a>(ManuallyDrop<T>, PhantomData<&'a T>);
256
257impl<'a, T> Deref for ItemRef<'a, T> {
258 type Target = T;
259
260 fn deref(&self) -> &T {
261 &self.0
262 }
263}
264
265impl<'a, T: fmt::Debug> fmt::Debug for ItemRef<'a, T> {
266 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
267 self.0.fmt(f)
268 }
269}
270
271impl<'a, T: PartialEq> PartialEq for ItemRef<'a, T> {
272 fn eq(&self, other: &Self) -> bool {
273 self.0.eq(&other.0)
274 }
275}
276
277pub struct ItemMutRef<'a, T: 'a>(ManuallyDrop<T>, PhantomData<&'a T>);
279
280impl<'a, T> Deref for ItemMutRef<'a, T> {
281 type Target = T;
282
283 fn deref(&self) -> &T {
284 &self.0
285 }
286}
287
288impl<'a, T> DerefMut for ItemMutRef<'a, T> {
289 fn deref_mut(&mut self) -> &mut T {
290 &mut self.0
291 }
292}
293
294impl<'a, T: fmt::Debug> fmt::Debug for ItemMutRef<'a, T> {
295 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
296 self.0.fmt(f)
297 }
298}
299
300impl<'a, T: PartialEq> PartialEq for ItemMutRef<'a, T> {
301 fn eq(&self, other: &Self) -> bool {
302 self.0.eq(&other.0)
303 }
304}
305
306pub unsafe trait FromMutVoid {
308 unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self>
309 where
310 Self: std::marker::Sized;
311}
312
313unsafe impl FromMutVoid for u32 {
314 unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> {
315 ItemMutRef(ManuallyDrop::new(x as u32), PhantomData)
316 }
317}
318
319unsafe impl FromMutVoid for *const c_void {
320 unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> {
321 ItemMutRef(ManuallyDrop::new(x), PhantomData)
322 }
323}
324
325unsafe impl<T: TCFType> FromMutVoid for T {
326 unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> {
327 ItemMutRef(
328 ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))),
329 PhantomData,
330 )
331 }
332}
333
334pub unsafe trait FromVoid {
336 unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self>
337 where
338 Self: std::marker::Sized;
339}
340
341unsafe impl FromVoid for u32 {
342 unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> {
343 ItemRef(ManuallyDrop::new(x as u32), PhantomData)
346 }
347}
348
349unsafe impl FromVoid for *const c_void {
350 unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> {
351 ItemRef(ManuallyDrop::new(x), PhantomData)
352 }
353}
354
355unsafe impl<T: TCFType> FromVoid for T {
356 unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> {
357 ItemRef(
358 ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))),
359 PhantomData,
360 )
361 }
362}
363
364pub unsafe trait ToVoid<T> {
366 fn to_void(&self) -> *const c_void;
367}
368
369unsafe impl ToVoid<*const c_void> for *const c_void {
370 fn to_void(&self) -> *const c_void {
371 *self
372 }
373}
374
375unsafe impl<'a> ToVoid<CFType> for &'a CFType {
376 fn to_void(&self) -> *const ::std::os::raw::c_void {
377 self.as_concrete_TypeRef().as_void_ptr()
378 }
379}
380
381unsafe impl ToVoid<CFType> for CFType {
382 fn to_void(&self) -> *const ::std::os::raw::c_void {
383 self.as_concrete_TypeRef().as_void_ptr()
384 }
385}
386
387unsafe impl ToVoid<CFType> for CFTypeRef {
388 fn to_void(&self) -> *const ::std::os::raw::c_void {
389 self.as_void_ptr()
390 }
391}
392
393#[cfg(test)]
394mod tests {
395 use super::*;
396 use crate::boolean::CFBoolean;
397 use std::mem;
398
399 #[test]
400 fn cftype_instance_of() {
401 let string = CFString::from_static_string("foo");
402 let cftype = string.as_CFType();
403
404 assert!(cftype.instance_of::<CFString>());
405 assert!(!cftype.instance_of::<CFBoolean>());
406 }
407
408 #[test]
409 fn as_cftype_retain_count() {
410 let string = CFString::from_static_string("alongerstring");
411 assert_eq!(string.retain_count(), 1);
412 let cftype = string.as_CFType();
413 assert_eq!(cftype.retain_count(), 2);
414 mem::drop(string);
415 assert_eq!(cftype.retain_count(), 1);
416 }
417
418 #[test]
419 fn into_cftype_retain_count() {
420 let string = CFString::from_static_string("alongerstring");
421 assert_eq!(string.retain_count(), 1);
422 let cftype = string.into_CFType();
423 assert_eq!(cftype.retain_count(), 1);
424 }
425
426 #[test]
427 fn as_cftype_and_downcast() {
428 let string = CFString::from_static_string("alongerstring");
429 let cftype = string.as_CFType();
430 let string2 = cftype.downcast::<CFString>().unwrap();
431 assert_eq!(string2.to_string(), "alongerstring");
432
433 assert_eq!(string.retain_count(), 3);
434 assert_eq!(cftype.retain_count(), 3);
435 assert_eq!(string2.retain_count(), 3);
436 }
437
438 #[test]
439 fn into_cftype_and_downcast_into() {
440 let string = CFString::from_static_string("alongerstring");
441 let cftype = string.into_CFType();
442 let string2 = cftype.downcast_into::<CFString>().unwrap();
443 assert_eq!(string2.to_string(), "alongerstring");
444 assert_eq!(string2.retain_count(), 1);
445 }
446}