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