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 let reference: CFTypeRef = CFRetain(reference); 247 TCFType::wrap_under_create_rule(reference) 248 } 249 250 #[inline] as_CFTypeRef(&self) -> CFTypeRef251 fn as_CFTypeRef(&self) -> CFTypeRef { 252 self.as_concrete_TypeRef() 253 } 254 255 #[inline] wrap_under_create_rule(obj: CFTypeRef) -> CFType256 unsafe fn wrap_under_create_rule(obj: CFTypeRef) -> CFType { 257 CFType(obj) 258 } 259 260 #[inline] type_id() -> CFTypeID261 fn type_id() -> CFTypeID { 262 // FIXME(pcwalton): Is this right? 263 0 264 } 265 } 266 267 /// A reference to an element inside a container 268 pub struct ItemRef<'a, T: 'a>(ManuallyDrop<T>, PhantomData<&'a T>); 269 270 impl<'a, T> Deref for ItemRef<'a, T> { 271 type Target = T; 272 deref(&self) -> &T273 fn deref(&self) -> &T { 274 &self.0 275 } 276 } 277 278 impl<'a, T: fmt::Debug> fmt::Debug for ItemRef<'a, T> { fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>279 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 280 self.0.fmt(f) 281 } 282 } 283 284 impl<'a, T: PartialEq> PartialEq for ItemRef<'a, T> { eq(&self, other: &Self) -> bool285 fn eq(&self, other: &Self) -> bool { 286 self.0.eq(&other.0) 287 } 288 } 289 290 /// A reference to a mutable element inside a container 291 pub struct ItemMutRef<'a, T: 'a>(ManuallyDrop<T>, PhantomData<&'a T>); 292 293 impl<'a, T> Deref for ItemMutRef<'a, T> { 294 type Target = T; 295 deref(&self) -> &T296 fn deref(&self) -> &T { 297 &self.0 298 } 299 } 300 301 impl<'a, T> DerefMut for ItemMutRef<'a, T> { deref_mut(&mut self) -> &mut T302 fn deref_mut(&mut self) -> &mut T { 303 &mut self.0 304 } 305 } 306 307 impl<'a, T: fmt::Debug> fmt::Debug for ItemMutRef<'a, T> { fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>308 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 309 self.0.fmt(f) 310 } 311 } 312 313 impl<'a, T: PartialEq> PartialEq for ItemMutRef<'a, T> { eq(&self, other: &Self) -> bool314 fn eq(&self, other: &Self) -> bool { 315 self.0.eq(&other.0) 316 } 317 } 318 319 /// A trait describing how to convert from the stored *mut c_void to the desired T 320 pub unsafe trait FromMutVoid { from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> where Self: std::marker::Sized321 unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> where Self: std::marker::Sized; 322 } 323 324 unsafe impl FromMutVoid for u32 { from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self>325 unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> { 326 ItemMutRef(ManuallyDrop::new(x as u32), PhantomData) 327 } 328 } 329 330 unsafe impl FromMutVoid for *const c_void { from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self>331 unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> { 332 ItemMutRef(ManuallyDrop::new(x), PhantomData) 333 } 334 } 335 336 unsafe impl<T: TCFType> FromMutVoid for T { from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self>337 unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> { 338 ItemMutRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData) 339 } 340 } 341 342 /// A trait describing how to convert from the stored *const c_void to the desired T 343 pub unsafe trait FromVoid { from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> where Self: std::marker::Sized344 unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> where Self: std::marker::Sized; 345 } 346 347 unsafe impl FromVoid for u32 { from_void<'a>(x: *const c_void) -> ItemRef<'a, Self>348 unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> { 349 // Functions like CGFontCopyTableTags treat the void*'s as u32's 350 // so we convert by casting directly 351 ItemRef(ManuallyDrop::new(x as u32), PhantomData) 352 } 353 } 354 355 unsafe impl FromVoid for *const c_void { from_void<'a>(x: *const c_void) -> ItemRef<'a, Self>356 unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> { 357 ItemRef(ManuallyDrop::new(x), PhantomData) 358 } 359 } 360 361 unsafe impl<T: TCFType> FromVoid for T { from_void<'a>(x: *const c_void) -> ItemRef<'a, Self>362 unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> { 363 ItemRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData) 364 } 365 } 366 367 /// A trait describing how to convert from the stored *const c_void to the desired T 368 pub unsafe trait ToVoid<T> { to_void(&self) -> *const c_void369 fn to_void(&self) -> *const c_void; 370 } 371 372 unsafe impl ToVoid<*const c_void> for *const c_void { to_void(&self) -> *const c_void373 fn to_void(&self) -> *const c_void { 374 *self 375 } 376 } 377 378 unsafe impl<'a> ToVoid<CFType> for &'a CFType { to_void(&self) -> *const ::std::os::raw::c_void379 fn to_void(&self) -> *const ::std::os::raw::c_void { 380 self.as_concrete_TypeRef().as_void_ptr() 381 } 382 } 383 384 unsafe impl ToVoid<CFType> for CFType { to_void(&self) -> *const ::std::os::raw::c_void385 fn to_void(&self) -> *const ::std::os::raw::c_void { 386 self.as_concrete_TypeRef().as_void_ptr() 387 } 388 } 389 390 unsafe impl ToVoid<CFType> for CFTypeRef { to_void(&self) -> *const ::std::os::raw::c_void391 fn to_void(&self) -> *const ::std::os::raw::c_void { 392 self.as_void_ptr() 393 } 394 } 395 396 397 #[cfg(test)] 398 mod tests { 399 use super::*; 400 use std::mem; 401 use boolean::CFBoolean; 402 403 #[test] cftype_instance_of()404 fn cftype_instance_of() { 405 let string = CFString::from_static_string("foo"); 406 let cftype = string.as_CFType(); 407 408 assert!(cftype.instance_of::<CFString>()); 409 assert!(!cftype.instance_of::<CFBoolean>()); 410 } 411 412 #[test] as_cftype_retain_count()413 fn as_cftype_retain_count() { 414 let string = CFString::from_static_string("bar"); 415 assert_eq!(string.retain_count(), 1); 416 let cftype = string.as_CFType(); 417 assert_eq!(cftype.retain_count(), 2); 418 mem::drop(string); 419 assert_eq!(cftype.retain_count(), 1); 420 } 421 422 #[test] into_cftype_retain_count()423 fn into_cftype_retain_count() { 424 let string = CFString::from_static_string("bar"); 425 assert_eq!(string.retain_count(), 1); 426 let cftype = string.into_CFType(); 427 assert_eq!(cftype.retain_count(), 1); 428 } 429 430 #[test] as_cftype_and_downcast()431 fn as_cftype_and_downcast() { 432 let string = CFString::from_static_string("bar"); 433 let cftype = string.as_CFType(); 434 let string2 = cftype.downcast::<CFString>().unwrap(); 435 assert_eq!(string2.to_string(), "bar"); 436 437 assert_eq!(string.retain_count(), 3); 438 assert_eq!(cftype.retain_count(), 3); 439 assert_eq!(string2.retain_count(), 3); 440 } 441 442 #[test] into_cftype_and_downcast_into()443 fn into_cftype_and_downcast_into() { 444 let string = CFString::from_static_string("bar"); 445 let cftype = string.into_CFType(); 446 let string2 = cftype.downcast_into::<CFString>().unwrap(); 447 assert_eq!(string2.to_string(), "bar"); 448 assert_eq!(string2.retain_count(), 1); 449 } 450 } 451