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