diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
commit | 10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch) | |
tree | bdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/core-foundation/src/base.rs | |
parent | Releasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff) | |
download | rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip |
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/core-foundation/src/base.rs')
-rw-r--r-- | vendor/core-foundation/src/base.rs | 452 |
1 files changed, 452 insertions, 0 deletions
diff --git a/vendor/core-foundation/src/base.rs b/vendor/core-foundation/src/base.rs new file mode 100644 index 000000000..f08f2b2e8 --- /dev/null +++ b/vendor/core-foundation/src/base.rs @@ -0,0 +1,452 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std; +use std::fmt; +use std::marker::PhantomData; +use std::mem; +use std::mem::ManuallyDrop; +use std::ops::{Deref, DerefMut}; +use std::os::raw::c_void; + +pub use core_foundation_sys::base::*; + +use string::CFString; +use ConcreteCFType; + +pub trait CFIndexConvertible { + /// Always use this method to construct a `CFIndex` value. It performs bounds checking to + /// ensure the value is in range. + fn to_CFIndex(self) -> CFIndex; +} + +impl CFIndexConvertible for usize { + #[inline] + fn to_CFIndex(self) -> CFIndex { + let max_CFIndex = CFIndex::max_value(); + if self > (max_CFIndex as usize) { + panic!("value out of range") + } + self as CFIndex + } +} + +declare_TCFType!{ + /// Superclass of all Core Foundation objects. + CFType, CFTypeRef +} + +impl CFType { + /// Try to downcast the `CFType` to a subclass. Checking if the instance is the + /// correct subclass happens at runtime and `None` is returned if it is not the correct type. + /// Works similar to [`Box::downcast`] and [`CFPropertyList::downcast`]. + /// + /// # Examples + /// + /// ``` + /// # use core_foundation::string::CFString; + /// # use core_foundation::boolean::CFBoolean; + /// # use core_foundation::base::{CFType, TCFType}; + /// # + /// // Create a string. + /// let string: CFString = CFString::from_static_string("FooBar"); + /// // Cast it up to a CFType. + /// let cf_type: CFType = string.as_CFType(); + /// // Cast it down again. + /// assert_eq!(cf_type.downcast::<CFString>().unwrap().to_string(), "FooBar"); + /// // Casting it to some other type will yield `None` + /// assert!(cf_type.downcast::<CFBoolean>().is_none()); + /// ``` + /// + /// ```compile_fail + /// # use core_foundation::array::CFArray; + /// # use core_foundation::base::TCFType; + /// # use core_foundation::boolean::CFBoolean; + /// # use core_foundation::string::CFString; + /// # + /// let boolean_array = CFArray::from_CFTypes(&[CFBoolean::true_value()]).into_CFType(); + /// + /// // This downcast is not allowed and causes compiler error, since it would cause undefined + /// // behavior to access the elements of the array as a CFString: + /// let invalid_string_array = boolean_array + /// .downcast_into::<CFArray<CFString>>() + /// .unwrap(); + /// ``` + /// + /// [`Box::downcast`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast + /// [`CFPropertyList::downcast`]: ../propertylist/struct.CFPropertyList.html#method.downcast + #[inline] + pub fn downcast<T: ConcreteCFType>(&self) -> Option<T> { + if self.instance_of::<T>() { + unsafe { + let reference = T::Ref::from_void_ptr(self.0); + Some(T::wrap_under_get_rule(reference)) + } + } else { + None + } + } + + /// Similar to [`downcast`], but consumes self and can thus avoid touching the retain count. + /// + /// [`downcast`]: #method.downcast + #[inline] + pub fn downcast_into<T: ConcreteCFType>(self) -> Option<T> { + if self.instance_of::<T>() { + unsafe { + let reference = T::Ref::from_void_ptr(self.0); + mem::forget(self); + Some(T::wrap_under_create_rule(reference)) + } + } else { + None + } + } +} + +impl fmt::Debug for CFType { + /// Formats the value using [`CFCopyDescription`]. + /// + /// [`CFCopyDescription`]: https://developer.apple.com/documentation/corefoundation/1521252-cfcopydescription?language=objc + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let desc = unsafe { + CFString::wrap_under_create_rule(CFCopyDescription(self.0)) + }; + desc.fmt(f) + } +} + +impl Clone for CFType { + #[inline] + fn clone(&self) -> CFType { + unsafe { + TCFType::wrap_under_get_rule(self.0) + } + } +} + +impl PartialEq for CFType { + #[inline] + fn eq(&self, other: &CFType) -> bool { + unsafe { + CFEqual(self.as_CFTypeRef(), other.as_CFTypeRef()) != 0 + } + } +} + +declare_TCFType!(CFAllocator, CFAllocatorRef); +impl_TCFType!(CFAllocator, CFAllocatorRef, CFAllocatorGetTypeID); + +impl CFAllocator { + #[inline] + pub fn new(mut context: CFAllocatorContext) -> CFAllocator { + unsafe { + let allocator_ref = CFAllocatorCreate(kCFAllocatorDefault, &mut context); + TCFType::wrap_under_create_rule(allocator_ref) + } + } +} + + +/// All Core Foundation types implement this trait. The associated type `Ref` specifies the +/// associated Core Foundation type: e.g. for `CFType` this is `CFTypeRef`; for `CFArray` this is +/// `CFArrayRef`. +/// +/// Most structs that implement this trait will do so via the [`impl_TCFType`] macro. +/// +/// [`impl_TCFType`]: ../macro.impl_TCFType.html +pub trait TCFType { + /// The reference type wrapped inside this type. + type Ref: TCFTypeRef; + + /// Returns the object as its concrete TypeRef. + fn as_concrete_TypeRef(&self) -> Self::Ref; + + /// Returns an instance of the object, wrapping the underlying `CFTypeRef` subclass. Use this + /// when following Core Foundation's "Create Rule". The reference count is *not* bumped. + unsafe fn wrap_under_create_rule(obj: Self::Ref) -> Self; + + /// Returns the type ID for this class. + fn type_id() -> CFTypeID; + + /// Returns the object as a wrapped `CFType`. The reference count is incremented by one. + #[inline] + fn as_CFType(&self) -> CFType { + unsafe { + TCFType::wrap_under_get_rule(self.as_CFTypeRef()) + } + } + + /// Returns the object as a wrapped `CFType`. Consumes self and avoids changing the reference + /// count. + #[inline] + fn into_CFType(self) -> CFType + where + Self: Sized, + { + let reference = self.as_CFTypeRef(); + mem::forget(self); + unsafe { TCFType::wrap_under_create_rule(reference) } + } + + /// Returns the object as a raw `CFTypeRef`. The reference count is not adjusted. + fn as_CFTypeRef(&self) -> CFTypeRef; + + /// Returns an instance of the object, wrapping the underlying `CFTypeRef` subclass. Use this + /// when following Core Foundation's "Get Rule". The reference count *is* bumped. + unsafe fn wrap_under_get_rule(reference: Self::Ref) -> Self; + + /// Returns the reference count of the object. It is unwise to do anything other than test + /// whether the return value of this method is greater than zero. + #[inline] + fn retain_count(&self) -> CFIndex { + unsafe { + CFGetRetainCount(self.as_CFTypeRef()) + } + } + + /// Returns the type ID of this object. + #[inline] + fn type_of(&self) -> CFTypeID { + unsafe { + CFGetTypeID(self.as_CFTypeRef()) + } + } + + /// Writes a debugging version of this object on standard error. + fn show(&self) { + unsafe { + CFShow(self.as_CFTypeRef()) + } + } + + /// Returns true if this value is an instance of another type. + #[inline] + fn instance_of<OtherCFType: TCFType>(&self) -> bool { + self.type_of() == OtherCFType::type_id() + } +} + +impl TCFType for CFType { + type Ref = CFTypeRef; + + #[inline] + fn as_concrete_TypeRef(&self) -> CFTypeRef { + self.0 + } + + #[inline] + unsafe fn wrap_under_get_rule(reference: CFTypeRef) -> CFType { + assert!(!reference.is_null(), "Attempted to create a NULL object."); + let reference: CFTypeRef = CFRetain(reference); + TCFType::wrap_under_create_rule(reference) + } + + #[inline] + fn as_CFTypeRef(&self) -> CFTypeRef { + self.as_concrete_TypeRef() + } + + #[inline] + unsafe fn wrap_under_create_rule(obj: CFTypeRef) -> CFType { + assert!(!obj.is_null(), "Attempted to create a NULL object."); + CFType(obj) + } + + #[inline] + fn type_id() -> CFTypeID { + // FIXME(pcwalton): Is this right? + 0 + } +} + +/// A reference to an element inside a container +pub struct ItemRef<'a, T: 'a>(ManuallyDrop<T>, PhantomData<&'a T>); + +impl<'a, T> Deref for ItemRef<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +impl<'a, T: fmt::Debug> fmt::Debug for ItemRef<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + self.0.fmt(f) + } +} + +impl<'a, T: PartialEq> PartialEq for ItemRef<'a, T> { + fn eq(&self, other: &Self) -> bool { + self.0.eq(&other.0) + } +} + +/// A reference to a mutable element inside a container +pub struct ItemMutRef<'a, T: 'a>(ManuallyDrop<T>, PhantomData<&'a T>); + +impl<'a, T> Deref for ItemMutRef<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +impl<'a, T> DerefMut for ItemMutRef<'a, T> { + fn deref_mut(&mut self) -> &mut T { + &mut self.0 + } +} + +impl<'a, T: fmt::Debug> fmt::Debug for ItemMutRef<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + self.0.fmt(f) + } +} + +impl<'a, T: PartialEq> PartialEq for ItemMutRef<'a, T> { + fn eq(&self, other: &Self) -> bool { + self.0.eq(&other.0) + } +} + +/// A trait describing how to convert from the stored *mut c_void to the desired T +pub unsafe trait FromMutVoid { + unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> where Self: std::marker::Sized; +} + +unsafe impl FromMutVoid for u32 { + unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> { + ItemMutRef(ManuallyDrop::new(x as u32), PhantomData) + } +} + +unsafe impl FromMutVoid for *const c_void { + unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> { + ItemMutRef(ManuallyDrop::new(x), PhantomData) + } +} + +unsafe impl<T: TCFType> FromMutVoid for T { + unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> { + ItemMutRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData) + } +} + +/// A trait describing how to convert from the stored *const c_void to the desired T +pub unsafe trait FromVoid { + unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> where Self: std::marker::Sized; +} + +unsafe impl FromVoid for u32 { + unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> { + // Functions like CGFontCopyTableTags treat the void*'s as u32's + // so we convert by casting directly + ItemRef(ManuallyDrop::new(x as u32), PhantomData) + } +} + +unsafe impl FromVoid for *const c_void { + unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> { + ItemRef(ManuallyDrop::new(x), PhantomData) + } +} + +unsafe impl<T: TCFType> FromVoid for T { + unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> { + ItemRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData) + } +} + +/// A trait describing how to convert from the stored *const c_void to the desired T +pub unsafe trait ToVoid<T> { + fn to_void(&self) -> *const c_void; +} + +unsafe impl ToVoid<*const c_void> for *const c_void { + fn to_void(&self) -> *const c_void { + *self + } +} + +unsafe impl<'a> ToVoid<CFType> for &'a CFType { + fn to_void(&self) -> *const ::std::os::raw::c_void { + self.as_concrete_TypeRef().as_void_ptr() + } +} + +unsafe impl ToVoid<CFType> for CFType { + fn to_void(&self) -> *const ::std::os::raw::c_void { + self.as_concrete_TypeRef().as_void_ptr() + } +} + +unsafe impl ToVoid<CFType> for CFTypeRef { + fn to_void(&self) -> *const ::std::os::raw::c_void { + self.as_void_ptr() + } +} + + +#[cfg(test)] +mod tests { + use super::*; + use std::mem; + use boolean::CFBoolean; + + #[test] + fn cftype_instance_of() { + let string = CFString::from_static_string("foo"); + let cftype = string.as_CFType(); + + assert!(cftype.instance_of::<CFString>()); + assert!(!cftype.instance_of::<CFBoolean>()); + } + + #[test] + fn as_cftype_retain_count() { + let string = CFString::from_static_string("bar"); + assert_eq!(string.retain_count(), 1); + let cftype = string.as_CFType(); + assert_eq!(cftype.retain_count(), 2); + mem::drop(string); + assert_eq!(cftype.retain_count(), 1); + } + + #[test] + fn into_cftype_retain_count() { + let string = CFString::from_static_string("bar"); + assert_eq!(string.retain_count(), 1); + let cftype = string.into_CFType(); + assert_eq!(cftype.retain_count(), 1); + } + + #[test] + fn as_cftype_and_downcast() { + let string = CFString::from_static_string("bar"); + let cftype = string.as_CFType(); + let string2 = cftype.downcast::<CFString>().unwrap(); + assert_eq!(string2.to_string(), "bar"); + + assert_eq!(string.retain_count(), 3); + assert_eq!(cftype.retain_count(), 3); + assert_eq!(string2.retain_count(), 3); + } + + #[test] + fn into_cftype_and_downcast_into() { + let string = CFString::from_static_string("bar"); + let cftype = string.into_CFType(); + let string2 = cftype.downcast_into::<CFString>().unwrap(); + assert_eq!(string2.to_string(), "bar"); + assert_eq!(string2.retain_count(), 1); + } +} |