Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

309
vendor/core-foundation/src/array.rs vendored Normal file
View File

@@ -0,0 +1,309 @@
// 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.
//! Heterogeneous immutable arrays.
use crate::ConcreteCFType;
use core::ffi::c_void;
pub use core_foundation_sys::array::*;
pub use core_foundation_sys::base::CFIndex;
use core_foundation_sys::base::{kCFAllocatorDefault, CFRelease, CFTypeRef};
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use crate::base::{CFIndexConvertible, CFRange, TCFType};
use crate::base::{FromVoid, ItemRef};
/// A heterogeneous immutable array.
pub struct CFArray<T = *const c_void>(CFArrayRef, PhantomData<T>);
impl<T> Drop for CFArray<T> {
fn drop(&mut self) {
unsafe { CFRelease(self.as_CFTypeRef()) }
}
}
pub struct CFArrayIterator<'a, T: 'a> {
array: &'a CFArray<T>,
index: CFIndex,
len: CFIndex,
}
impl<'a, T: FromVoid> Iterator for CFArrayIterator<'a, T> {
type Item = ItemRef<'a, T>;
fn next(&mut self) -> Option<ItemRef<'a, T>> {
if self.index >= self.len {
None
} else {
let value = unsafe { self.array.get_unchecked(self.index) };
self.index += 1;
Some(value)
}
}
}
impl<T: FromVoid> ExactSizeIterator for CFArrayIterator<'_, T> {
fn len(&self) -> usize {
(self.array.len() - self.index) as usize
}
}
impl_TCFType!(CFArray<T>, CFArrayRef, CFArrayGetTypeID);
impl_CFTypeDescription!(CFArray<T>);
unsafe impl ConcreteCFType for CFArray<*const c_void> {}
impl<T> CFArray<T> {
/// Creates a new `CFArray` with the given elements, which must implement `Copy`.
pub fn from_copyable(elems: &[T]) -> CFArray<T>
where
T: Copy,
{
unsafe {
let array_ref = CFArrayCreate(
kCFAllocatorDefault,
elems.as_ptr() as *const *const c_void,
elems.len().to_CFIndex(),
ptr::null(),
);
TCFType::wrap_under_create_rule(array_ref)
}
}
/// Creates a new `CFArray` with the given elements, which must be `CFType` objects.
pub fn from_CFTypes(elems: &[T]) -> CFArray<T>
where
T: TCFType,
{
unsafe {
let elems: Vec<CFTypeRef> = elems.iter().map(|elem| elem.as_CFTypeRef()).collect();
let array_ref = CFArrayCreate(
kCFAllocatorDefault,
elems.as_ptr(),
elems.len().to_CFIndex(),
&kCFTypeArrayCallBacks,
);
TCFType::wrap_under_create_rule(array_ref)
}
}
#[inline]
pub fn to_untyped(&self) -> CFArray {
unsafe { CFArray::wrap_under_get_rule(self.0) }
}
/// Returns the same array, but with the type reset to void pointers.
/// Equal to `to_untyped`, but is faster since it does not increment the retain count.
#[inline]
pub fn into_untyped(self) -> CFArray {
let reference = self.0;
mem::forget(self);
unsafe { CFArray::wrap_under_create_rule(reference) }
}
/// Iterates over the elements of this `CFArray`.
///
/// Careful; the loop body must wrap the reference properly. Generally, when array elements are
/// Core Foundation objects (not always true), they need to be wrapped with
/// `TCFType::wrap_under_get_rule()`.
#[inline]
pub fn iter(&self) -> CFArrayIterator<'_, T> {
CFArrayIterator {
array: self,
index: 0,
len: self.len(),
}
}
#[inline]
pub fn len(&self) -> CFIndex {
unsafe { CFArrayGetCount(self.0) }
}
/// Returns `true` if the array contains no elements.
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub unsafe fn get_unchecked(&self, index: CFIndex) -> ItemRef<'_, T>
where
T: FromVoid,
{
T::from_void(CFArrayGetValueAtIndex(self.0, index))
}
#[inline]
pub fn get(&self, index: CFIndex) -> Option<ItemRef<'_, T>>
where
T: FromVoid,
{
if index < self.len() {
Some(unsafe { T::from_void(CFArrayGetValueAtIndex(self.0, index)) })
} else {
None
}
}
pub fn get_values(&self, range: CFRange) -> Vec<*const c_void> {
let mut vec = Vec::with_capacity(range.length as usize);
unsafe {
CFArrayGetValues(self.0, range, vec.as_mut_ptr());
vec.set_len(range.length as usize);
vec
}
}
pub fn get_all_values(&self) -> Vec<*const c_void> {
self.get_values(CFRange {
location: 0,
length: self.len(),
})
}
}
impl<'a, T: FromVoid> IntoIterator for &'a CFArray<T> {
type Item = ItemRef<'a, T>;
type IntoIter = CFArrayIterator<'a, T>;
fn into_iter(self) -> CFArrayIterator<'a, T> {
self.iter()
}
}
#[cfg(test)]
mod tests {
use crate::number::CFNumber;
use super::*;
use crate::base::CFType;
use std::mem;
#[test]
fn to_untyped_correct_retain_count() {
let array = CFArray::<CFType>::from_CFTypes(&[CFNumber::from(4).as_CFType()]);
assert_eq!(array.retain_count(), 1);
let untyped_array = array.to_untyped();
assert_eq!(array.retain_count(), 2);
assert_eq!(untyped_array.retain_count(), 2);
mem::drop(array);
assert_eq!(untyped_array.retain_count(), 1);
}
#[test]
fn into_untyped() {
let array = CFArray::<CFType>::from_CFTypes(&[CFNumber::from(4).as_CFType()]);
let array2 = array.to_untyped();
assert_eq!(array.retain_count(), 2);
let untyped_array = array.into_untyped();
assert_eq!(untyped_array.retain_count(), 2);
mem::drop(array2);
assert_eq!(untyped_array.retain_count(), 1);
}
#[test]
fn borrow() {
use crate::string::CFString;
let string = CFString::from_static_string("alongerstring");
assert_eq!(string.retain_count(), 1);
let x;
{
let arr: CFArray<CFString> = CFArray::from_CFTypes(&[string]);
{
let p = arr.get(0).unwrap();
assert_eq!(p.retain_count(), 1);
}
{
x = arr.get(0).unwrap().clone();
assert_eq!(x.retain_count(), 2);
assert_eq!(x.to_string(), "alongerstring");
}
}
assert_eq!(x.retain_count(), 1);
}
#[test]
fn iter_untyped_array() {
use crate::base::TCFTypeRef;
use crate::string::{CFString, CFStringRef};
let cf_string = CFString::from_static_string("alongerstring");
let array: CFArray = CFArray::from_CFTypes(&[cf_string.clone()]).into_untyped();
let cf_strings = array
.iter()
.map(|ptr| unsafe { CFString::wrap_under_get_rule(CFStringRef::from_void_ptr(*ptr)) })
.collect::<Vec<_>>();
let strings = cf_strings.iter().map(|s| s.to_string()).collect::<Vec<_>>();
assert_eq!(cf_string.retain_count(), 3);
assert_eq!(&strings[..], &["alongerstring"]);
}
#[test]
fn should_box_and_unbox() {
use crate::number::CFNumber;
let n0 = CFNumber::from(0);
let n1 = CFNumber::from(1);
let n2 = CFNumber::from(2);
let n3 = CFNumber::from(3);
let n4 = CFNumber::from(4);
let n5 = CFNumber::from(5);
let arr = CFArray::from_CFTypes(&[
n0.as_CFType(),
n1.as_CFType(),
n2.as_CFType(),
n3.as_CFType(),
n4.as_CFType(),
n5.as_CFType(),
]);
assert_eq!(
arr.get_all_values(),
&[
n0.as_CFTypeRef(),
n1.as_CFTypeRef(),
n2.as_CFTypeRef(),
n3.as_CFTypeRef(),
n4.as_CFTypeRef(),
n5.as_CFTypeRef()
]
);
let mut sum = 0;
let mut iter = arr.iter();
assert_eq!(iter.len(), 6);
assert!(iter.next().is_some());
assert_eq!(iter.len(), 5);
for elem in iter {
let number: CFNumber = elem.downcast::<CFNumber>().unwrap();
sum += number.to_i64().unwrap()
}
assert_eq!(sum, 15);
for elem in arr.iter() {
let number: CFNumber = elem.downcast::<CFNumber>().unwrap();
sum += number.to_i64().unwrap()
}
assert_eq!(sum, 30);
}
}

View File

@@ -0,0 +1,101 @@
// 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.
pub use core_foundation_sys::attributed_string::*;
use crate::base::TCFType;
use crate::string::{CFString, CFStringRef};
use core_foundation_sys::base::{kCFAllocatorDefault, CFIndex, CFRange};
use std::ptr::null;
declare_TCFType! {
CFAttributedString, CFAttributedStringRef
}
impl_TCFType!(
CFAttributedString,
CFAttributedStringRef,
CFAttributedStringGetTypeID
);
impl CFAttributedString {
#[inline]
pub fn new(string: &CFString) -> Self {
unsafe {
let astr_ref =
CFAttributedStringCreate(kCFAllocatorDefault, string.as_concrete_TypeRef(), null());
CFAttributedString::wrap_under_create_rule(astr_ref)
}
}
#[inline]
pub fn char_len(&self) -> CFIndex {
unsafe { CFAttributedStringGetLength(self.0) }
}
}
declare_TCFType! {
CFMutableAttributedString, CFMutableAttributedStringRef
}
impl_TCFType!(
CFMutableAttributedString,
CFMutableAttributedStringRef,
CFAttributedStringGetTypeID
);
impl CFMutableAttributedString {
#[inline]
pub fn new() -> Self {
unsafe {
let astr_ref = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
CFMutableAttributedString::wrap_under_create_rule(astr_ref)
}
}
#[inline]
pub fn char_len(&self) -> CFIndex {
unsafe { CFAttributedStringGetLength(self.0) }
}
#[inline]
pub fn replace_str(&mut self, string: &CFString, range: CFRange) {
unsafe {
CFAttributedStringReplaceString(self.0, range, string.as_concrete_TypeRef());
}
}
#[inline]
pub fn set_attribute<T: TCFType>(&mut self, range: CFRange, name: CFStringRef, value: &T) {
unsafe {
CFAttributedStringSetAttribute(self.0, range, name, value.as_CFTypeRef());
}
}
}
impl Default for CFMutableAttributedString {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn attributed_string_type_id_comparison() {
// CFMutableAttributedString TypeID must be equal to CFAttributedString TypeID.
// Compilation must not fail.
assert_eq!(
<CFAttributedString as TCFType>::type_id(),
<CFMutableAttributedString as TCFType>::type_id()
);
}
}

445
vendor/core-foundation/src/base.rs vendored Normal file
View File

@@ -0,0 +1,445 @@
// 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 core::ffi::c_void;
use std;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut};
pub use core_foundation_sys::base::*;
use crate::string::CFString;
use crate::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 {
if self > (CFIndex::MAX 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<T> Deref for ItemRef<'_, T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T: fmt::Debug> fmt::Debug for ItemRef<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.0.fmt(f)
}
}
impl<T: PartialEq> PartialEq for ItemRef<'_, 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<T> Deref for ItemMutRef<'_, T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> DerefMut for ItemMutRef<'_, T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T: fmt::Debug> fmt::Debug for ItemMutRef<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.0.fmt(f)
}
}
impl<T: PartialEq> PartialEq for ItemMutRef<'_, 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 ToVoid<CFType> for &CFType {
fn to_void(&self) -> *const c_void {
self.as_concrete_TypeRef().as_void_ptr()
}
}
unsafe impl ToVoid<CFType> for CFType {
fn to_void(&self) -> *const c_void {
self.as_concrete_TypeRef().as_void_ptr()
}
}
unsafe impl ToVoid<CFType> for CFTypeRef {
fn to_void(&self) -> *const c_void {
self.as_void_ptr()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::boolean::CFBoolean;
use std::mem;
#[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("alongerstring");
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("alongerstring");
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("alongerstring");
let cftype = string.as_CFType();
let string2 = cftype.downcast::<CFString>().unwrap();
assert_eq!(string2.to_string(), "alongerstring");
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("alongerstring");
let cftype = string.into_CFType();
let string2 = cftype.downcast_into::<CFString>().unwrap();
assert_eq!(string2.to_string(), "alongerstring");
assert_eq!(string2.retain_count(), 1);
}
}

67
vendor/core-foundation/src/boolean.rs vendored Normal file
View File

@@ -0,0 +1,67 @@
// 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.
//! A Boolean type.
pub use core_foundation_sys::number::{
kCFBooleanFalse, kCFBooleanTrue, CFBooleanGetTypeID, CFBooleanRef,
};
use crate::base::TCFType;
declare_TCFType! {
/// A Boolean type.
///
/// FIXME(pcwalton): Should be a newtype struct, but that fails due to a Rust compiler bug.
CFBoolean, CFBooleanRef
}
impl_TCFType!(CFBoolean, CFBooleanRef, CFBooleanGetTypeID);
impl_CFTypeDescription!(CFBoolean);
impl CFBoolean {
pub fn true_value() -> CFBoolean {
unsafe { TCFType::wrap_under_get_rule(kCFBooleanTrue) }
}
pub fn false_value() -> CFBoolean {
unsafe { TCFType::wrap_under_get_rule(kCFBooleanFalse) }
}
}
impl From<bool> for CFBoolean {
fn from(value: bool) -> CFBoolean {
if value {
CFBoolean::true_value()
} else {
CFBoolean::false_value()
}
}
}
impl From<CFBoolean> for bool {
fn from(value: CFBoolean) -> bool {
value.0 == unsafe { kCFBooleanTrue }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn to_and_from_bool() {
let b_false = CFBoolean::from(false);
let b_true = CFBoolean::from(true);
assert_ne!(b_false, b_true);
assert_eq!(b_false, CFBoolean::false_value());
assert_eq!(b_true, CFBoolean::true_value());
assert!(!bool::from(b_false));
assert!(bool::from(b_true));
}
}

199
vendor/core-foundation/src/bundle.rs vendored Normal file
View File

@@ -0,0 +1,199 @@
// 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.
//! Core Foundation Bundle Type
use core::ffi::c_void;
use core_foundation_sys::base::kCFAllocatorDefault;
pub use core_foundation_sys::bundle::*;
use core_foundation_sys::url::kCFURLPOSIXPathStyle;
use std::path::PathBuf;
use crate::base::{CFType, TCFType};
use crate::dictionary::CFDictionary;
use crate::string::CFString;
use crate::url::CFURL;
declare_TCFType! {
/// A Bundle type.
CFBundle, CFBundleRef
}
impl_TCFType!(CFBundle, CFBundleRef, CFBundleGetTypeID);
impl CFBundle {
pub fn new(bundleURL: CFURL) -> Option<CFBundle> {
unsafe {
let bundle_ref = CFBundleCreate(kCFAllocatorDefault, bundleURL.as_concrete_TypeRef());
if bundle_ref.is_null() {
None
} else {
Some(TCFType::wrap_under_create_rule(bundle_ref))
}
}
}
pub fn bundle_with_identifier(identifier: CFString) -> Option<CFBundle> {
unsafe {
let bundle_ref = CFBundleGetBundleWithIdentifier(identifier.as_concrete_TypeRef());
if bundle_ref.is_null() {
None
} else {
Some(TCFType::wrap_under_get_rule(bundle_ref))
}
}
}
pub fn function_pointer_for_name(&self, function_name: CFString) -> *const c_void {
unsafe {
CFBundleGetFunctionPointerForName(
self.as_concrete_TypeRef(),
function_name.as_concrete_TypeRef(),
)
}
}
pub fn main_bundle() -> CFBundle {
unsafe {
let bundle_ref = CFBundleGetMainBundle();
TCFType::wrap_under_get_rule(bundle_ref)
}
}
pub fn info_dictionary(&self) -> CFDictionary<CFString, CFType> {
unsafe {
let info_dictionary = CFBundleGetInfoDictionary(self.0);
TCFType::wrap_under_get_rule(info_dictionary)
}
}
pub fn executable_url(&self) -> Option<CFURL> {
unsafe {
let exe_url = CFBundleCopyExecutableURL(self.0);
if exe_url.is_null() {
None
} else {
Some(TCFType::wrap_under_create_rule(exe_url))
}
}
}
/// Bundle's own location
pub fn bundle_url(&self) -> Option<CFURL> {
unsafe {
let bundle_url = CFBundleCopyBundleURL(self.0);
if bundle_url.is_null() {
None
} else {
Some(TCFType::wrap_under_create_rule(bundle_url))
}
}
}
/// Bundle's own location
pub fn path(&self) -> Option<PathBuf> {
let url = self.bundle_url()?;
Some(PathBuf::from(
url.get_file_system_path(kCFURLPOSIXPathStyle).to_string(),
))
}
/// Bundle's resources location
pub fn bundle_resources_url(&self) -> Option<CFURL> {
unsafe {
let bundle_url = CFBundleCopyResourcesDirectoryURL(self.0);
if bundle_url.is_null() {
None
} else {
Some(TCFType::wrap_under_create_rule(bundle_url))
}
}
}
/// Bundle's resources location
pub fn resources_path(&self) -> Option<PathBuf> {
let url = self.bundle_resources_url()?;
Some(PathBuf::from(
url.get_file_system_path(kCFURLPOSIXPathStyle).to_string(),
))
}
pub fn private_frameworks_url(&self) -> Option<CFURL> {
unsafe {
let fw_url = CFBundleCopyPrivateFrameworksURL(self.0);
if fw_url.is_null() {
None
} else {
Some(TCFType::wrap_under_create_rule(fw_url))
}
}
}
pub fn shared_support_url(&self) -> Option<CFURL> {
unsafe {
let fw_url = CFBundleCopySharedSupportURL(self.0);
if fw_url.is_null() {
None
} else {
Some(TCFType::wrap_under_create_rule(fw_url))
}
}
}
}
#[test]
fn safari_executable_url() {
use crate::string::CFString;
use crate::url::{kCFURLPOSIXPathStyle, CFURL};
let cfstr_path = CFString::from_static_string("/Applications/Safari.app");
let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true);
let cfurl_executable = CFBundle::new(cfurl_path)
.expect("Safari not present")
.executable_url();
assert!(cfurl_executable.is_some());
assert_eq!(
cfurl_executable
.unwrap()
.absolute()
.get_file_system_path(kCFURLPOSIXPathStyle)
.to_string(),
"/Applications/Safari.app/Contents/MacOS/Safari"
);
}
#[test]
fn safari_private_frameworks_url() {
use crate::string::CFString;
use crate::url::{kCFURLPOSIXPathStyle, CFURL};
let cfstr_path = CFString::from_static_string("/Applications/Safari.app");
let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true);
let cfurl_executable = CFBundle::new(cfurl_path)
.expect("Safari not present")
.private_frameworks_url();
assert!(cfurl_executable.is_some());
assert_eq!(
cfurl_executable
.unwrap()
.absolute()
.get_file_system_path(kCFURLPOSIXPathStyle)
.to_string(),
"/Applications/Safari.app/Contents/Frameworks"
);
}
#[test]
fn non_existent_bundle() {
use crate::string::CFString;
use crate::url::{kCFURLPOSIXPathStyle, CFURL};
let cfstr_path = CFString::from_static_string("/usr/local/foo");
let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true);
assert!(CFBundle::new(cfurl_path).is_none());
}

View File

@@ -0,0 +1,19 @@
// Copyright 2019 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.
//! A set of Unicode compliant characters.
pub use core_foundation_sys::characterset::*;
declare_TCFType! {
/// An immutable set of Unicode characters.
CFCharacterSet, CFCharacterSetRef
}
impl_TCFType!(CFCharacterSet, CFCharacterSetRef, CFCharacterSetGetTypeID);
impl_CFTypeDescription!(CFCharacterSet);

160
vendor/core-foundation/src/data.rs vendored Normal file
View File

@@ -0,0 +1,160 @@
// 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.
//! Core Foundation byte buffers.
use core_foundation_sys::base::kCFAllocatorDefault;
use core_foundation_sys::base::CFIndex;
pub use core_foundation_sys::data::*;
use std::ops::Deref;
use std::slice;
use std::sync::Arc;
use crate::base::{CFIndexConvertible, TCFType};
declare_TCFType! {
/// A byte buffer.
CFData, CFDataRef
}
impl_TCFType!(CFData, CFDataRef, CFDataGetTypeID);
impl_CFTypeDescription!(CFData);
impl CFData {
/// Creates a [`CFData`] around a copy `buffer`
pub fn from_buffer(buffer: &[u8]) -> CFData {
unsafe {
let data_ref = CFDataCreate(
kCFAllocatorDefault,
buffer.as_ptr(),
buffer.len().to_CFIndex(),
);
TCFType::wrap_under_create_rule(data_ref)
}
}
/// Creates a [`CFData`] referencing `buffer` without creating a copy
pub fn from_arc<T: AsRef<[u8]> + Sync + Send>(buffer: Arc<T>) -> Self {
use crate::base::{CFAllocator, CFAllocatorContext};
use core::ffi::c_void;
unsafe {
let ptr = (*buffer).as_ref().as_ptr() as *const _;
let len = (*buffer).as_ref().len().to_CFIndex();
let info = Arc::into_raw(buffer) as *mut c_void;
extern "C" fn deallocate<T>(_: *mut c_void, info: *mut c_void) {
unsafe {
drop(Arc::from_raw(info as *mut T));
}
}
// Use a separate allocator for each allocation because
// we need `info` to do the deallocation vs. `ptr`
let allocator = CFAllocator::new(CFAllocatorContext {
info,
version: 0,
retain: None,
reallocate: None,
release: None,
copyDescription: None,
allocate: None,
deallocate: Some(deallocate::<T>),
preferredSize: None,
});
let data_ref = CFDataCreateWithBytesNoCopy(
kCFAllocatorDefault,
ptr,
len,
allocator.as_CFTypeRef(),
);
TCFType::wrap_under_create_rule(data_ref)
}
}
/// Returns a pointer to the underlying bytes in this data. Note that this byte buffer is
/// read-only.
#[inline]
pub fn bytes(&self) -> &[u8] {
unsafe {
let ptr = CFDataGetBytePtr(self.0);
// Rust slice must never have a NULL pointer
if ptr.is_null() {
return &[];
}
slice::from_raw_parts(ptr, self.len() as usize)
}
}
/// Returns the length of this byte buffer.
#[inline]
pub fn len(&self) -> CFIndex {
unsafe { CFDataGetLength(self.0) }
}
/// Returns `true` if this byte buffer is empty.
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl Deref for CFData {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.bytes()
}
}
#[cfg(test)]
mod test {
use super::CFData;
use std::sync::Arc;
#[test]
fn test_data_provider() {
let l = vec![5];
CFData::from_arc(Arc::new(l));
let l = vec![5];
CFData::from_arc(Arc::new(l.into_boxed_slice()));
// Make sure the buffer is actually dropped
use std::sync::atomic::{AtomicBool, Ordering::SeqCst};
struct VecWrapper {
inner: Vec<u8>,
dropped: Arc<AtomicBool>,
}
impl Drop for VecWrapper {
fn drop(&mut self) {
self.dropped.store(true, SeqCst)
}
}
impl std::convert::AsRef<[u8]> for VecWrapper {
fn as_ref(&self) -> &[u8] {
&self.inner
}
}
let dropped = Arc::new(AtomicBool::default());
let l = Arc::new(VecWrapper {
inner: vec![5],
dropped: dropped.clone(),
});
let m = l.clone();
let dp = CFData::from_arc(l);
drop(m);
assert!(!dropped.load(SeqCst));
drop(dp);
assert!(dropped.load(SeqCst))
}
}

65
vendor/core-foundation/src/date.rs vendored Normal file
View File

@@ -0,0 +1,65 @@
// 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.
//! Core Foundation date objects.
use core_foundation_sys::base::kCFAllocatorDefault;
pub use core_foundation_sys::date::*;
use crate::base::TCFType;
declare_TCFType! {
/// A date.
CFDate, CFDateRef
}
impl_TCFType!(CFDate, CFDateRef, CFDateGetTypeID);
impl_CFTypeDescription!(CFDate);
impl_CFComparison!(CFDate, CFDateCompare);
impl CFDate {
#[inline]
pub fn new(time: CFAbsoluteTime) -> CFDate {
unsafe {
let date_ref = CFDateCreate(kCFAllocatorDefault, time);
TCFType::wrap_under_create_rule(date_ref)
}
}
#[inline]
pub fn now() -> CFDate {
CFDate::new(unsafe { CFAbsoluteTimeGetCurrent() })
}
#[inline]
pub fn abs_time(&self) -> CFAbsoluteTime {
unsafe { CFDateGetAbsoluteTime(self.0) }
}
}
#[cfg(test)]
mod test {
use super::CFDate;
use std::cmp::Ordering;
#[test]
fn date_comparison() {
let now = CFDate::now();
let past = CFDate::new(now.abs_time() - 1.0);
assert_eq!(now.cmp(&past), Ordering::Greater);
assert_eq!(now.cmp(&now), Ordering::Equal);
assert_eq!(past.cmp(&now), Ordering::Less);
}
#[test]
fn date_equality() {
let now = CFDate::now();
let same_time = CFDate::new(now.abs_time());
assert_eq!(now, same_time);
}
}

481
vendor/core-foundation/src/dictionary.rs vendored Normal file
View File

@@ -0,0 +1,481 @@
// 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.
//! Dictionaries of key-value pairs.
pub use core_foundation_sys::dictionary::*;
use core::ffi::c_void;
use core_foundation_sys::base::{kCFAllocatorDefault, CFRelease, CFTypeRef};
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use crate::base::{CFIndexConvertible, TCFType};
use crate::base::{FromVoid, ItemRef, ToVoid};
use crate::ConcreteCFType;
// consume the type parameters with `PhantomData`
pub struct CFDictionary<K = *const c_void, V = *const c_void>(
CFDictionaryRef,
PhantomData<K>,
PhantomData<V>,
);
impl<K, V> Drop for CFDictionary<K, V> {
fn drop(&mut self) {
unsafe { CFRelease(self.as_CFTypeRef()) }
}
}
impl_TCFType!(CFDictionary<K, V>, CFDictionaryRef, CFDictionaryGetTypeID);
impl_CFTypeDescription!(CFDictionary<K, V>);
unsafe impl ConcreteCFType for CFDictionary<*const c_void, *const c_void> {}
impl<K, V> CFDictionary<K, V> {
pub fn from_CFType_pairs(pairs: &[(K, V)]) -> CFDictionary<K, V>
where
K: TCFType,
V: TCFType,
{
let (keys, values): (Vec<CFTypeRef>, Vec<CFTypeRef>) = pairs
.iter()
.map(|(key, value)| (key.as_CFTypeRef(), value.as_CFTypeRef()))
.unzip();
unsafe {
let dictionary_ref = CFDictionaryCreate(
kCFAllocatorDefault,
keys.as_ptr(),
values.as_ptr(),
keys.len().to_CFIndex(),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks,
);
TCFType::wrap_under_create_rule(dictionary_ref)
}
}
#[inline]
pub fn to_untyped(&self) -> CFDictionary {
unsafe { CFDictionary::wrap_under_get_rule(self.0) }
}
/// Returns a `CFMutableDictionary` pointing to the same underlying dictionary as this immutable one.
/// This should only be used when the underlying dictionary is mutable.
#[inline]
pub unsafe fn to_mutable(&self) -> CFMutableDictionary<K, V> {
CFMutableDictionary::wrap_under_get_rule(self.0 as CFMutableDictionaryRef)
}
/// Returns the same dictionary, but with the types reset to void pointers.
/// Equal to `to_untyped`, but is faster since it does not increment the retain count.
#[inline]
pub fn into_untyped(self) -> CFDictionary {
let reference = self.0;
mem::forget(self);
unsafe { CFDictionary::wrap_under_create_rule(reference) }
}
#[inline]
pub fn len(&self) -> usize {
unsafe { CFDictionaryGetCount(self.0) as usize }
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn contains_key(&self, key: &K) -> bool
where
K: ToVoid<K>,
{
unsafe { CFDictionaryContainsKey(self.0, key.to_void()) != 0 }
}
#[inline]
pub fn find<T: ToVoid<K>>(&self, key: T) -> Option<ItemRef<'_, V>>
where
V: FromVoid,
K: ToVoid<K>,
{
unsafe {
let mut value: *const c_void = ptr::null();
if CFDictionaryGetValueIfPresent(self.0, key.to_void(), &mut value) != 0 {
Some(V::from_void(value))
} else {
None
}
}
}
/// # Panics
///
/// Panics if the key is not present in the dictionary. Use `find` to get an `Option` instead
/// of panicking.
#[inline]
pub fn get<T: ToVoid<K>>(&self, key: T) -> ItemRef<'_, V>
where
V: FromVoid,
K: ToVoid<K>,
{
let ptr = key.to_void();
self.find(key)
.unwrap_or_else(|| panic!("No entry found for key {:p}", ptr))
}
pub fn get_keys_and_values(&self) -> (Vec<*const c_void>, Vec<*const c_void>) {
let length = self.len();
let mut keys = Vec::with_capacity(length);
let mut values = Vec::with_capacity(length);
unsafe {
CFDictionaryGetKeysAndValues(self.0, keys.as_mut_ptr(), values.as_mut_ptr());
keys.set_len(length);
values.set_len(length);
}
(keys, values)
}
}
// consume the type parameters with `PhantomData`
pub struct CFMutableDictionary<K = *const c_void, V = *const c_void>(
CFMutableDictionaryRef,
PhantomData<K>,
PhantomData<V>,
);
impl<K, V> Drop for CFMutableDictionary<K, V> {
fn drop(&mut self) {
unsafe { CFRelease(self.as_CFTypeRef()) }
}
}
impl_TCFType!(CFMutableDictionary<K, V>, CFMutableDictionaryRef, CFDictionaryGetTypeID);
impl_CFTypeDescription!(CFMutableDictionary);
impl<K, V> CFMutableDictionary<K, V> {
pub fn new() -> Self {
Self::with_capacity(0)
}
pub fn with_capacity(capacity: isize) -> Self {
unsafe {
let dictionary_ref = CFDictionaryCreateMutable(
kCFAllocatorDefault,
capacity as _,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks,
);
TCFType::wrap_under_create_rule(dictionary_ref)
}
}
pub fn copy_with_capacity(&self, capacity: isize) -> Self {
unsafe {
let dictionary_ref =
CFDictionaryCreateMutableCopy(kCFAllocatorDefault, capacity as _, self.0);
TCFType::wrap_under_get_rule(dictionary_ref)
}
}
pub fn from_CFType_pairs(pairs: &[(K, V)]) -> CFMutableDictionary<K, V>
where
K: ToVoid<K>,
V: ToVoid<V>,
{
let mut result = Self::with_capacity(pairs.len() as _);
for (key, value) in pairs {
result.add(key, value);
}
result
}
#[inline]
pub fn to_untyped(&self) -> CFMutableDictionary {
unsafe { CFMutableDictionary::wrap_under_get_rule(self.0) }
}
/// Returns the same dictionary, but with the types reset to void pointers.
/// Equal to `to_untyped`, but is faster since it does not increment the retain count.
#[inline]
pub fn into_untyped(self) -> CFMutableDictionary {
let reference = self.0;
mem::forget(self);
unsafe { CFMutableDictionary::wrap_under_create_rule(reference) }
}
/// Returns a `CFDictionary` pointing to the same underlying dictionary as this mutable one.
#[inline]
pub fn to_immutable(&self) -> CFDictionary<K, V> {
unsafe { CFDictionary::wrap_under_get_rule(self.0) }
}
// Immutable interface
#[inline]
pub fn len(&self) -> usize {
unsafe { CFDictionaryGetCount(self.0) as usize }
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn contains_key(&self, key: *const c_void) -> bool {
unsafe { CFDictionaryContainsKey(self.0, key) != 0 }
}
#[inline]
pub fn find<'a>(&'a self, key: &K) -> Option<ItemRef<'a, V>>
where
V: FromVoid,
K: ToVoid<K>,
{
unsafe {
let mut value: *const c_void = ptr::null();
if CFDictionaryGetValueIfPresent(self.0, key.to_void(), &mut value) != 0 {
Some(V::from_void(value))
} else {
None
}
}
}
/// # Panics
///
/// Panics if the key is not present in the dictionary. Use `find` to get an `Option` instead
/// of panicking.
#[inline]
pub fn get<'a>(&'a self, key: &K) -> ItemRef<'a, V>
where
V: FromVoid,
K: ToVoid<K>,
{
let ptr = key.to_void();
self.find(key)
.unwrap_or_else(|| panic!("No entry found for key {:p}", ptr))
}
pub fn get_keys_and_values(&self) -> (Vec<*const c_void>, Vec<*const c_void>) {
let length = self.len();
let mut keys = Vec::with_capacity(length);
let mut values = Vec::with_capacity(length);
unsafe {
CFDictionaryGetKeysAndValues(self.0, keys.as_mut_ptr(), values.as_mut_ptr());
keys.set_len(length);
values.set_len(length);
}
(keys, values)
}
// Mutable interface
/// Adds the key-value pair to the dictionary if no such key already exist.
#[inline]
pub fn add(&mut self, key: &K, value: &V)
where
K: ToVoid<K>,
V: ToVoid<V>,
{
unsafe { CFDictionaryAddValue(self.0, key.to_void(), value.to_void()) }
}
/// Sets the value of the key in the dictionary.
#[inline]
pub fn set(&mut self, key: K, value: V)
where
K: ToVoid<K>,
V: ToVoid<V>,
{
unsafe { CFDictionarySetValue(self.0, key.to_void(), value.to_void()) }
}
/// Replaces the value of the key in the dictionary.
#[inline]
pub fn replace(&mut self, key: K, value: V)
where
K: ToVoid<K>,
V: ToVoid<V>,
{
unsafe { CFDictionaryReplaceValue(self.0, key.to_void(), value.to_void()) }
}
/// Removes the value of the key from the dictionary.
#[inline]
pub fn remove(&mut self, key: K)
where
K: ToVoid<K>,
{
unsafe { CFDictionaryRemoveValue(self.0, key.to_void()) }
}
#[inline]
pub fn remove_all(&mut self) {
unsafe { CFDictionaryRemoveAllValues(self.0) }
}
}
impl<K, V> Default for CFMutableDictionary<K, V> {
fn default() -> Self {
Self::new()
}
}
impl<'a, K, V> From<&'a CFDictionary<K, V>> for CFMutableDictionary<K, V> {
/// Creates a new mutable dictionary with the key-value pairs from another dictionary.
/// The capacity of the new mutable dictionary is not limited.
fn from(dict: &'a CFDictionary<K, V>) -> Self {
unsafe {
let mut_dict_ref = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict.0);
TCFType::wrap_under_create_rule(mut_dict_ref)
}
}
}
#[cfg(test)]
pub mod test {
use super::*;
use crate::base::{CFType, TCFType};
use crate::boolean::CFBoolean;
use crate::number::CFNumber;
use crate::string::CFString;
#[test]
fn dictionary() {
let bar = CFString::from_static_string("Bar");
let baz = CFString::from_static_string("Baz");
let boo = CFString::from_static_string("Boo");
let foo = CFString::from_static_string("Foo");
let tru = CFBoolean::true_value();
let n42 = CFNumber::from(42);
let d = CFDictionary::from_CFType_pairs(&[
(bar.as_CFType(), boo.as_CFType()),
(baz.as_CFType(), tru.as_CFType()),
(foo.as_CFType(), n42.as_CFType()),
]);
let (v1, v2) = d.get_keys_and_values();
assert_eq!(
v1,
&[bar.as_CFTypeRef(), baz.as_CFTypeRef(), foo.as_CFTypeRef()]
);
assert_eq!(
v2,
&[boo.as_CFTypeRef(), tru.as_CFTypeRef(), n42.as_CFTypeRef()]
);
}
#[test]
fn mutable_dictionary() {
let bar = CFString::from_static_string("Bar");
let baz = CFString::from_static_string("Baz");
let boo = CFString::from_static_string("Boo");
let foo = CFString::from_static_string("Foo");
let tru = CFBoolean::true_value();
let n42 = CFNumber::from(42);
let mut d = CFMutableDictionary::<CFString, CFType>::new();
d.add(&bar, &boo.as_CFType());
d.add(&baz, &tru.as_CFType());
d.add(&foo, &n42.as_CFType());
assert_eq!(d.len(), 3);
let (v1, v2) = d.get_keys_and_values();
assert_eq!(
v1,
&[bar.as_CFTypeRef(), baz.as_CFTypeRef(), foo.as_CFTypeRef()]
);
assert_eq!(
v2,
&[boo.as_CFTypeRef(), tru.as_CFTypeRef(), n42.as_CFTypeRef()]
);
d.remove(baz);
assert_eq!(d.len(), 2);
let (v1, v2) = d.get_keys_and_values();
assert_eq!(v1, &[bar.as_CFTypeRef(), foo.as_CFTypeRef()]);
assert_eq!(v2, &[boo.as_CFTypeRef(), n42.as_CFTypeRef()]);
d.remove_all();
assert_eq!(d.len(), 0)
}
#[test]
fn dict_find_and_contains_key() {
let dict = CFDictionary::from_CFType_pairs(&[(
CFString::from_static_string("hello"),
CFBoolean::true_value(),
)]);
let key = CFString::from_static_string("hello");
let invalid_key = CFString::from_static_string("foobar");
assert!(dict.contains_key(&key));
assert!(!dict.contains_key(&invalid_key));
let value = dict.find(&key).unwrap().clone();
assert_eq!(value, CFBoolean::true_value());
assert_eq!(dict.find(&invalid_key), None);
}
#[test]
fn convert_immutable_to_mutable_dict() {
let dict: CFDictionary<CFString, CFBoolean> = CFDictionary::from_CFType_pairs(&[(
CFString::from_static_string("Foo"),
CFBoolean::true_value(),
)]);
let mut mut_dict = CFMutableDictionary::from(&dict);
assert_eq!(dict.retain_count(), 1);
assert_eq!(mut_dict.retain_count(), 1);
assert_eq!(mut_dict.len(), 1);
assert_eq!(
*mut_dict.get(&CFString::from_static_string("Foo")),
CFBoolean::true_value()
);
mut_dict.add(
&CFString::from_static_string("Bar"),
&CFBoolean::false_value(),
);
assert_eq!(dict.len(), 1);
assert_eq!(mut_dict.len(), 2);
}
#[test]
fn mutable_dictionary_as_immutable() {
let mut mut_dict: CFMutableDictionary<CFString, CFBoolean> = CFMutableDictionary::new();
mut_dict.add(
&CFString::from_static_string("Bar"),
&CFBoolean::false_value(),
);
assert_eq!(mut_dict.retain_count(), 1);
let dict = mut_dict.to_immutable();
assert_eq!(mut_dict.retain_count(), 2);
assert_eq!(dict.retain_count(), 2);
assert_eq!(
*dict.get(CFString::from_static_string("Bar")),
CFBoolean::false_value()
);
mem::drop(dict);
assert_eq!(mut_dict.retain_count(), 1);
}
}

70
vendor/core-foundation/src/error.rs vendored Normal file
View File

@@ -0,0 +1,70 @@
// Copyright 2016 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.
//! Core Foundation errors.
pub use core_foundation_sys::error::*;
use std::error::Error;
use std::fmt;
use crate::base::{CFIndex, TCFType};
use crate::string::CFString;
declare_TCFType! {
/// An error value.
CFError, CFErrorRef
}
impl_TCFType!(CFError, CFErrorRef, CFErrorGetTypeID);
impl fmt::Debug for CFError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("CFError")
.field("domain", &self.domain())
.field("code", &self.code())
.field("description", &self.description())
.finish()
}
}
impl fmt::Display for CFError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", self.description())
}
}
impl Error for CFError {
fn description(&self) -> &str {
"a Core Foundation error"
}
}
impl CFError {
/// Returns a string identifying the domain with which this error is
/// associated.
pub fn domain(&self) -> CFString {
unsafe {
let s = CFErrorGetDomain(self.0);
CFString::wrap_under_get_rule(s)
}
}
/// Returns the code identifying this type of error.
pub fn code(&self) -> CFIndex {
unsafe { CFErrorGetCode(self.0) }
}
/// Returns a human-presentable description of the error.
pub fn description(&self) -> CFString {
unsafe {
let s = CFErrorCopyDescription(self.0);
CFString::wrap_under_create_rule(s)
}
}
}

View File

@@ -0,0 +1,192 @@
// 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.
pub use core_foundation_sys::filedescriptor::*;
use core_foundation_sys::base::{kCFAllocatorDefault, CFOptionFlags};
use core_foundation_sys::base::{Boolean, CFIndex};
use crate::base::TCFType;
use crate::runloop::CFRunLoopSource;
use std::mem::MaybeUninit;
use std::os::unix::io::{AsRawFd, RawFd};
use std::ptr;
declare_TCFType! {
CFFileDescriptor, CFFileDescriptorRef
}
impl_TCFType!(
CFFileDescriptor,
CFFileDescriptorRef,
CFFileDescriptorGetTypeID
);
impl CFFileDescriptor {
pub fn new(
fd: RawFd,
closeOnInvalidate: bool,
callout: CFFileDescriptorCallBack,
context: Option<&CFFileDescriptorContext>,
) -> Option<CFFileDescriptor> {
let context = context.map_or(ptr::null(), |c| c as *const _);
unsafe {
let fd_ref = CFFileDescriptorCreate(
kCFAllocatorDefault,
fd,
closeOnInvalidate as Boolean,
callout,
context,
);
if fd_ref.is_null() {
None
} else {
Some(TCFType::wrap_under_create_rule(fd_ref))
}
}
}
pub fn context(&self) -> CFFileDescriptorContext {
unsafe {
let mut context = MaybeUninit::<CFFileDescriptorContext>::uninit();
CFFileDescriptorGetContext(self.0, context.as_mut_ptr());
context.assume_init()
}
}
pub fn enable_callbacks(&self, callback_types: CFOptionFlags) {
unsafe { CFFileDescriptorEnableCallBacks(self.0, callback_types) }
}
pub fn disable_callbacks(&self, callback_types: CFOptionFlags) {
unsafe { CFFileDescriptorDisableCallBacks(self.0, callback_types) }
}
pub fn valid(&self) -> bool {
unsafe { CFFileDescriptorIsValid(self.0) != 0 }
}
pub fn invalidate(&self) {
unsafe { CFFileDescriptorInvalidate(self.0) }
}
pub fn to_run_loop_source(&self, order: CFIndex) -> Option<CFRunLoopSource> {
unsafe {
let source_ref =
CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, self.0, order);
if source_ref.is_null() {
None
} else {
Some(TCFType::wrap_under_create_rule(source_ref))
}
}
}
}
impl AsRawFd for CFFileDescriptor {
fn as_raw_fd(&self) -> RawFd {
unsafe { CFFileDescriptorGetNativeDescriptor(self.0) }
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::runloop::CFRunLoop;
use core::ffi::c_void;
use core_foundation_sys::base::CFOptionFlags;
use core_foundation_sys::runloop::kCFRunLoopDefaultMode;
use libc::O_RDWR;
use std::ffi::CString;
#[test]
fn test_unconsumed() {
let path = CString::new("/dev/null").unwrap();
let raw_fd = unsafe { libc::open(path.as_ptr(), O_RDWR, 0) };
let cf_fd = CFFileDescriptor::new(raw_fd, false, never_callback, None);
assert!(cf_fd.is_some());
let cf_fd = cf_fd.unwrap();
assert!(cf_fd.valid());
cf_fd.invalidate();
assert!(!cf_fd.valid());
// close() should succeed
assert_eq!(unsafe { libc::close(raw_fd) }, 0);
}
extern "C" fn never_callback(
_f: CFFileDescriptorRef,
_callback_types: CFOptionFlags,
_info_ptr: *mut c_void,
) {
unreachable!();
}
struct TestInfo {
value: CFOptionFlags,
}
#[test]
fn test_callback() {
let mut info = TestInfo { value: 0 };
let context = CFFileDescriptorContext {
version: 0,
info: &mut info as *mut _ as *mut c_void,
retain: None,
release: None,
copyDescription: None,
};
let path = CString::new("/dev/null").unwrap();
let raw_fd = unsafe { libc::open(path.as_ptr(), O_RDWR, 0) };
let cf_fd = CFFileDescriptor::new(raw_fd, true, callback, Some(&context));
assert!(cf_fd.is_some());
let cf_fd = cf_fd.unwrap();
assert!(cf_fd.valid());
let run_loop = CFRunLoop::get_current();
let source = CFRunLoopSource::from_file_descriptor(&cf_fd, 0);
assert!(source.is_some());
unsafe {
run_loop.add_source(&source.unwrap(), kCFRunLoopDefaultMode);
}
info.value = 0;
cf_fd.enable_callbacks(kCFFileDescriptorReadCallBack);
CFRunLoop::run_current();
assert_eq!(info.value, kCFFileDescriptorReadCallBack);
info.value = 0;
cf_fd.enable_callbacks(kCFFileDescriptorWriteCallBack);
CFRunLoop::run_current();
assert_eq!(info.value, kCFFileDescriptorWriteCallBack);
info.value = 0;
cf_fd.disable_callbacks(kCFFileDescriptorReadCallBack | kCFFileDescriptorWriteCallBack);
cf_fd.invalidate();
assert!(!cf_fd.valid());
}
extern "C" fn callback(
_f: CFFileDescriptorRef,
callback_types: CFOptionFlags,
info_ptr: *mut c_void,
) {
assert!(!info_ptr.is_null());
let info: *mut TestInfo = info_ptr as *mut TestInfo;
unsafe { (*info).value = callback_types };
CFRunLoop::get_current().stop();
}
}

259
vendor/core-foundation/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,259 @@
// 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.
#![allow(non_snake_case)]
//! This crate provides wrappers around the underlying CoreFoundation
//! types and functions that are available on Apple's operating systems.
//!
//! It also provides a framework for other crates to use when wrapping
//! other frameworks that use the CoreFoundation framework.
use crate::base::TCFType;
pub unsafe trait ConcreteCFType: TCFType {}
/// Declare a Rust type that wraps an underlying CoreFoundation type.
///
/// This will provide an implementation of `Drop` using [`CFRelease`].
/// The type must have an implementation of the [`TCFType`] trait, usually
/// provided using the [`impl_TCFType`] macro.
///
/// ```
/// use core_foundation::{declare_TCFType, impl_TCFType};
/// // Make sure that the `TCFType` trait is in scope.
/// use core_foundation::base::{CFTypeID, TCFType};
///
/// extern "C" {
/// // We need a function that returns the `CFTypeID`.
/// pub fn ShrubberyGetTypeID() -> CFTypeID;
/// }
///
/// pub struct __Shrubbery {}
/// // The ref type must be a pointer to the underlying struct.
/// pub type ShrubberyRef = *const __Shrubbery;
///
/// declare_TCFType!(Shrubbery, ShrubberyRef);
/// impl_TCFType!(Shrubbery, ShrubberyRef, ShrubberyGetTypeID);
/// # fn main() {}
/// ```
///
/// [`CFRelease`]: https://developer.apple.com/documentation/corefoundation/1521153-cfrelease
/// [`TCFType`]: base/trait.TCFType.html
/// [`impl_TCFType`]: macro.impl_TCFType.html
#[macro_export]
macro_rules! declare_TCFType {
(
$(#[$doc:meta])*
$ty:ident, $raw:ident
) => {
declare_TCFType!($(#[$doc])* $ty<>, $raw);
};
(
$(#[$doc:meta])*
$ty:ident<$($p:ident $(: $bound:path)*),*>, $raw:ident
) => {
$(#[$doc])*
pub struct $ty<$($p $(: $bound)*),*>($raw, $(::std::marker::PhantomData<$p>),*);
#[allow(unused_imports)]
impl<$($p $(: $bound)*),*> Drop for $ty<$($p),*> {
fn drop(&mut self) {
use $crate::base::TCFType;
unsafe { $crate::base::CFRelease(self.as_CFTypeRef()) }
}
}
};
}
/// Provide an implementation of the [`TCFType`] trait for the Rust
/// wrapper type around an underlying CoreFoundation type.
///
/// See [`declare_TCFType`] for details.
///
/// [`declare_TCFType`]: macro.declare_TCFType.html
/// [`TCFType`]: base/trait.TCFType.html
#[macro_export]
macro_rules! impl_TCFType {
($ty:ident, $ty_ref:ident, $ty_id:ident) => {
impl_TCFType!($ty<>, $ty_ref, $ty_id);
unsafe impl $crate::ConcreteCFType for $ty { }
};
($ty:ident<$($p:ident $(: $bound:path)*),*>, $ty_ref:ident, $ty_id:ident) => {
impl<$($p $(: $bound)*),*> $crate::base::TCFType for $ty<$($p),*> {
type Ref = $ty_ref;
#[allow(non_snake_case)]
#[inline]
fn as_concrete_TypeRef(&self) -> $ty_ref {
self.0
}
#[inline]
unsafe fn wrap_under_get_rule(reference: $ty_ref) -> Self {
assert!(!reference.is_null(), "Attempted to create a NULL object.");
let reference = $crate::base::CFRetain(reference as *const ::core::ffi::c_void) as $ty_ref;
$crate::base::TCFType::wrap_under_create_rule(reference)
}
#[allow(non_snake_case)]
#[inline]
fn as_CFTypeRef(&self) -> $crate::base::CFTypeRef {
self.as_concrete_TypeRef() as $crate::base::CFTypeRef
}
#[inline]
unsafe fn wrap_under_create_rule(reference: $ty_ref) -> Self {
assert!(!reference.is_null(), "Attempted to create a NULL object.");
// we need one PhantomData for each type parameter so call ourselves
// again with @Phantom $p to produce that
$ty(reference $(, impl_TCFType!(@Phantom $p))*)
}
#[inline]
fn type_id() -> $crate::base::CFTypeID {
unsafe {
$ty_id()
}
}
}
#[allow(unused_imports)]
impl<$($p $(: $bound)*),*> Clone for $ty<$($p),*> {
#[inline]
fn clone(&self) -> Self {
use $crate::base::TCFType;
unsafe {
$ty::wrap_under_get_rule(self.0)
}
}
}
#[allow(unused_imports)]
impl<$($p $(: $bound)*),*> PartialEq for $ty<$($p),*> {
#[inline]
fn eq(&self, other: &Self) -> bool {
use $crate::base::TCFType;
self.as_CFType().eq(&other.as_CFType())
}
}
impl<$($p $(: $bound)*),*> Eq for $ty<$($p),*> { }
#[allow(unused_imports)]
unsafe impl<'a, $($p $(: $bound)*),*> $crate::base::ToVoid<$ty<$($p),*>> for &'a $ty<$($p),*> {
fn to_void(&self) -> *const ::core::ffi::c_void {
use $crate::base::{TCFType, TCFTypeRef};
self.as_concrete_TypeRef().as_void_ptr()
}
}
#[allow(unused_imports)]
unsafe impl<$($p $(: $bound)*),*> $crate::base::ToVoid<$ty<$($p),*>> for $ty<$($p),*> {
fn to_void(&self) -> *const ::core::ffi::c_void {
use $crate::base::{TCFType, TCFTypeRef};
self.as_concrete_TypeRef().as_void_ptr()
}
}
#[allow(unused_imports)]
unsafe impl<$($p $(: $bound)*),*> $crate::base::ToVoid<$ty<$($p),*>> for $ty_ref {
fn to_void(&self) -> *const ::core::ffi::c_void {
use $crate::base::TCFTypeRef;
self.as_void_ptr()
}
}
};
(@Phantom $x:ident) => { ::std::marker::PhantomData };
}
/// Implement `std::fmt::Debug` for the given type.
///
/// This will invoke the implementation of `Debug` for [`CFType`]
/// which invokes [`CFCopyDescription`].
///
/// The type must have an implementation of the [`TCFType`] trait, usually
/// provided using the [`impl_TCFType`] macro.
///
/// [`CFType`]: base/struct.CFType.html#impl-Debug
/// [`CFCopyDescription`]: https://developer.apple.com/documentation/corefoundation/1521252-cfcopydescription?language=objc
/// [`TCFType`]: base/trait.TCFType.html
/// [`impl_TCFType`]: macro.impl_TCFType.html
#[macro_export]
macro_rules! impl_CFTypeDescription {
($ty:ident) => {
// it's fine to use an empty <> list
impl_CFTypeDescription!($ty<>);
};
($ty:ident<$($p:ident $(: $bound:path)*),*>) => {
#[allow(unused_imports)]
impl<$($p $(: $bound)*),*> ::std::fmt::Debug for $ty<$($p),*> {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
use $crate::base::TCFType;
self.as_CFType().fmt(f)
}
}
}
}
#[macro_export]
macro_rules! impl_CFComparison {
($ty:ident, $compare:ident) => {
impl_CFComparison!($ty<>, $compare);
};
($ty:ident<$($p:ident $(: $bound:path)*),*>, $compare:ident) => {
impl<$($p $(: $bound)*),*> PartialOrd for $ty<$($p),*> {
#[inline]
fn partial_cmp(&self, other: &$ty<$($p),*>) -> Option<::std::cmp::Ordering> {
unsafe {
Some(
$compare(
self.as_concrete_TypeRef(),
other.as_concrete_TypeRef(),
::std::ptr::null_mut(),
)
.into(),
)
}
}
}
impl<$($p $(: $bound)*),*> Ord for $ty<$($p),*> {
#[inline]
fn cmp(&self, other: &$ty<$($p),*>) -> ::std::cmp::Ordering {
self.partial_cmp(other).unwrap()
}
}
};
}
pub mod array;
pub mod attributed_string;
pub mod base;
pub mod boolean;
pub mod bundle;
pub mod characterset;
pub mod data;
pub mod date;
pub mod dictionary;
pub mod error;
pub mod filedescriptor;
pub mod mach_port;
pub mod number;
pub mod propertylist;
pub mod runloop;
pub mod set;
pub mod string;
pub mod timezone;
pub mod url;
pub mod uuid;

25
vendor/core-foundation/src/mach_port.rs vendored Normal file
View File

@@ -0,0 +1,25 @@
use crate::base::TCFType;
use crate::runloop::CFRunLoopSource;
use core_foundation_sys::base::kCFAllocatorDefault;
pub use core_foundation_sys::mach_port::*;
declare_TCFType! {
/// An immutable numeric value.
CFMachPort, CFMachPortRef
}
impl_TCFType!(CFMachPort, CFMachPortRef, CFMachPortGetTypeID);
impl_CFTypeDescription!(CFMachPort);
impl CFMachPort {
pub fn create_runloop_source(&self, order: CFIndex) -> Result<CFRunLoopSource, ()> {
unsafe {
let runloop_source_ref =
CFMachPortCreateRunLoopSource(kCFAllocatorDefault, self.0, order);
if runloop_source_ref.is_null() {
Err(())
} else {
Ok(CFRunLoopSource::wrap_under_create_rule(runloop_source_ref))
}
}
}
}

150
vendor/core-foundation/src/number.rs vendored Normal file
View File

@@ -0,0 +1,150 @@
// 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.
//! Immutable numbers.
use core::ffi::c_void;
use core_foundation_sys::base::kCFAllocatorDefault;
pub use core_foundation_sys::number::*;
use crate::base::TCFType;
declare_TCFType! {
/// An immutable numeric value.
CFNumber, CFNumberRef
}
impl_TCFType!(CFNumber, CFNumberRef, CFNumberGetTypeID);
impl_CFTypeDescription!(CFNumber);
impl_CFComparison!(CFNumber, CFNumberCompare);
impl CFNumber {
#[inline]
pub fn to_i32(&self) -> Option<i32> {
unsafe {
let mut value: i32 = 0;
let ok = CFNumberGetValue(
self.0,
kCFNumberSInt32Type,
&mut value as *mut i32 as *mut c_void,
);
if ok {
Some(value)
} else {
None
}
}
}
#[inline]
pub fn to_i64(&self) -> Option<i64> {
unsafe {
let mut value: i64 = 0;
let ok = CFNumberGetValue(
self.0,
kCFNumberSInt64Type,
&mut value as *mut i64 as *mut c_void,
);
if ok {
Some(value)
} else {
None
}
}
}
#[inline]
pub fn to_f32(&self) -> Option<f32> {
unsafe {
let mut value: f32 = 0.0;
let ok = CFNumberGetValue(
self.0,
kCFNumberFloat32Type,
&mut value as *mut f32 as *mut c_void,
);
if ok {
Some(value)
} else {
None
}
}
}
#[inline]
pub fn to_f64(&self) -> Option<f64> {
unsafe {
let mut value: f64 = 0.0;
let ok = CFNumberGetValue(
self.0,
kCFNumberFloat64Type,
&mut value as *mut f64 as *mut c_void,
);
if ok {
Some(value)
} else {
None
}
}
}
}
impl From<i32> for CFNumber {
#[inline]
fn from(value: i32) -> Self {
unsafe {
let number_ref = CFNumberCreate(
kCFAllocatorDefault,
kCFNumberSInt32Type,
&value as *const i32 as *const c_void,
);
TCFType::wrap_under_create_rule(number_ref)
}
}
}
impl From<i64> for CFNumber {
#[inline]
fn from(value: i64) -> Self {
unsafe {
let number_ref = CFNumberCreate(
kCFAllocatorDefault,
kCFNumberSInt64Type,
&value as *const i64 as *const c_void,
);
TCFType::wrap_under_create_rule(number_ref)
}
}
}
impl From<f32> for CFNumber {
#[inline]
fn from(value: f32) -> Self {
unsafe {
let number_ref = CFNumberCreate(
kCFAllocatorDefault,
kCFNumberFloat32Type,
&value as *const f32 as *const c_void,
);
TCFType::wrap_under_create_rule(number_ref)
}
}
}
impl From<f64> for CFNumber {
#[inline]
fn from(value: f64) -> Self {
unsafe {
let number_ref = CFNumberCreate(
kCFAllocatorDefault,
kCFNumberFloat64Type,
&value as *const f64 as *const c_void,
);
TCFType::wrap_under_create_rule(number_ref)
}
}
}

View File

@@ -0,0 +1,334 @@
// 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.
//! Core Foundation property lists
use core::ffi::c_void;
use std::mem;
use std::ptr;
use crate::base::{CFType, TCFType, TCFTypeRef};
use crate::data::CFData;
use crate::error::CFError;
use core_foundation_sys::base::{
kCFAllocatorDefault, CFGetRetainCount, CFGetTypeID, CFIndex, CFRetain, CFShow, CFTypeID,
};
use core_foundation_sys::error::CFErrorRef;
pub use core_foundation_sys::propertylist::*;
pub fn create_with_data(
data: CFData,
options: CFPropertyListMutabilityOptions,
) -> Result<(*const c_void, CFPropertyListFormat), CFError> {
unsafe {
let mut error: CFErrorRef = ptr::null_mut();
let mut format: CFPropertyListFormat = 0;
let property_list = CFPropertyListCreateWithData(
kCFAllocatorDefault,
data.as_concrete_TypeRef(),
options,
&mut format,
&mut error,
);
if property_list.is_null() {
Err(TCFType::wrap_under_create_rule(error))
} else {
Ok((property_list, format))
}
}
}
pub fn create_data(
property_list: *const c_void,
format: CFPropertyListFormat,
) -> Result<CFData, CFError> {
unsafe {
let mut error: CFErrorRef = ptr::null_mut();
let data_ref =
CFPropertyListCreateData(kCFAllocatorDefault, property_list, format, 0, &mut error);
if data_ref.is_null() {
Err(TCFType::wrap_under_create_rule(error))
} else {
Ok(TCFType::wrap_under_create_rule(data_ref))
}
}
}
/// Trait for all subclasses of [`CFPropertyList`].
///
/// [`CFPropertyList`]: struct.CFPropertyList.html
pub trait CFPropertyListSubClass: TCFType {
/// Create an instance of the superclass type [`CFPropertyList`] for this instance.
///
/// [`CFPropertyList`]: struct.CFPropertyList.html
#[inline]
fn to_CFPropertyList(&self) -> CFPropertyList {
unsafe { CFPropertyList::wrap_under_get_rule(self.as_concrete_TypeRef().as_void_ptr()) }
}
/// Equal to [`to_CFPropertyList`], but consumes self and avoids changing the reference count.
///
/// [`to_CFPropertyList`]: #method.to_CFPropertyList
#[inline]
fn into_CFPropertyList(self) -> CFPropertyList
where
Self: Sized,
{
let reference = self.as_concrete_TypeRef().as_void_ptr();
mem::forget(self);
unsafe { CFPropertyList::wrap_under_create_rule(reference) }
}
}
impl CFPropertyListSubClass for crate::data::CFData {}
impl CFPropertyListSubClass for crate::string::CFString {}
impl CFPropertyListSubClass for crate::array::CFArray {}
impl CFPropertyListSubClass for crate::dictionary::CFDictionary {}
impl CFPropertyListSubClass for crate::date::CFDate {}
impl CFPropertyListSubClass for crate::boolean::CFBoolean {}
impl CFPropertyListSubClass for crate::number::CFNumber {}
declare_TCFType! {
/// A CFPropertyList struct. This is superclass to [`CFData`], [`CFString`], [`CFArray`],
/// [`CFDictionary`], [`CFDate`], [`CFBoolean`], and [`CFNumber`].
///
/// This superclass type does not have its own `CFTypeID`, instead each instance has the `CFTypeID`
/// of the subclass it is an instance of. Thus, this type cannot implement the [`TCFType`] trait,
/// since it cannot implement the static [`TCFType::type_id()`] method.
///
/// [`CFData`]: ../data/struct.CFData.html
/// [`CFString`]: ../string/struct.CFString.html
/// [`CFArray`]: ../array/struct.CFArray.html
/// [`CFDictionary`]: ../dictionary/struct.CFDictionary.html
/// [`CFDate`]: ../date/struct.CFDate.html
/// [`CFBoolean`]: ../boolean/struct.CFBoolean.html
/// [`CFNumber`]: ../number/struct.CFNumber.html
/// [`TCFType`]: ../base/trait.TCFType.html
/// [`TCFType::type_id()`]: ../base/trait.TCFType.html#method.type_of
CFPropertyList, CFPropertyListRef
}
impl_CFTypeDescription!(CFPropertyList);
impl CFPropertyList {
#[inline]
pub fn as_concrete_TypeRef(&self) -> CFPropertyListRef {
self.0
}
#[inline]
pub unsafe fn wrap_under_get_rule(reference: CFPropertyListRef) -> CFPropertyList {
assert!(!reference.is_null(), "Attempted to create a NULL object.");
let reference = CFRetain(reference);
CFPropertyList(reference)
}
#[inline]
pub fn as_CFType(&self) -> CFType {
unsafe { CFType::wrap_under_get_rule(self.as_CFTypeRef()) }
}
#[inline]
pub fn into_CFType(self) -> CFType
where
Self: Sized,
{
let reference = self.as_CFTypeRef();
mem::forget(self);
unsafe { TCFType::wrap_under_create_rule(reference) }
}
#[inline]
pub fn as_CFTypeRef(&self) -> ::core_foundation_sys::base::CFTypeRef {
self.as_concrete_TypeRef()
}
#[inline]
pub unsafe fn wrap_under_create_rule(obj: CFPropertyListRef) -> CFPropertyList {
assert!(!obj.is_null(), "Attempted to create a NULL object.");
CFPropertyList(obj)
}
/// 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]
pub fn retain_count(&self) -> CFIndex {
unsafe { CFGetRetainCount(self.as_CFTypeRef()) }
}
/// Returns the type ID of this object. Will be one of `CFData`, `CFString`, `CFArray`,
/// `CFDictionary`, `CFDate`, `CFBoolean`, or `CFNumber`.
#[inline]
pub fn type_of(&self) -> CFTypeID {
unsafe { CFGetTypeID(self.as_CFTypeRef()) }
}
/// Writes a debugging version of this object on standard error.
pub fn show(&self) {
unsafe { CFShow(self.as_CFTypeRef()) }
}
/// Returns `true` if this value is an instance of another type.
#[inline]
pub fn instance_of<OtherCFType: TCFType>(&self) -> bool {
self.type_of() == OtherCFType::type_id()
}
}
impl Clone for CFPropertyList {
#[inline]
fn clone(&self) -> CFPropertyList {
unsafe { CFPropertyList::wrap_under_get_rule(self.0) }
}
}
impl PartialEq for CFPropertyList {
#[inline]
fn eq(&self, other: &CFPropertyList) -> bool {
self.as_CFType().eq(&other.as_CFType())
}
}
impl Eq for CFPropertyList {}
impl CFPropertyList {
/// Try to downcast the [`CFPropertyList`] 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 [`CFType::downcast`].
///
/// # Examples
///
/// ```
/// # use core_foundation::string::CFString;
/// # use core_foundation::propertylist::{CFPropertyList, CFPropertyListSubClass};
/// #
/// // Create a string.
/// let string: CFString = CFString::from_static_string("FooBar");
/// // Cast it up to a property list.
/// let propertylist: CFPropertyList = string.to_CFPropertyList();
/// // Cast it down again.
/// assert_eq!(propertylist.downcast::<CFString>().unwrap().to_string(), "FooBar");
/// ```
///
/// [`CFPropertyList`]: struct.CFPropertyList.html
/// [`Box::downcast`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast
pub fn downcast<T: CFPropertyListSubClass>(&self) -> Option<T> {
if self.instance_of::<T>() {
unsafe {
let subclass_ref = T::Ref::from_void_ptr(self.0);
Some(T::wrap_under_get_rule(subclass_ref))
}
} else {
None
}
}
/// Similar to [`downcast`], but consumes self and can thus avoid touching the retain count.
///
/// [`downcast`]: #method.downcast
pub fn downcast_into<T: CFPropertyListSubClass>(self) -> Option<T> {
if self.instance_of::<T>() {
unsafe {
let subclass_ref = T::Ref::from_void_ptr(self.0);
mem::forget(self);
Some(T::wrap_under_create_rule(subclass_ref))
}
} else {
None
}
}
}
#[cfg(test)]
pub mod test {
use super::*;
use crate::boolean::CFBoolean;
use crate::string::CFString;
#[test]
fn test_property_list_serialization() {
use super::*;
use crate::base::{CFEqual, TCFType};
use crate::boolean::CFBoolean;
use crate::dictionary::CFDictionary;
use crate::number::CFNumber;
use crate::string::CFString;
let bar = CFString::from_static_string("Bar");
let baz = CFString::from_static_string("Baz");
let boo = CFString::from_static_string("Boo");
let foo = CFString::from_static_string("Foo");
let tru = CFBoolean::true_value();
let n42 = CFNumber::from(1i64 << 33);
let dict1 = CFDictionary::from_CFType_pairs(&[
(bar.as_CFType(), boo.as_CFType()),
(baz.as_CFType(), tru.as_CFType()),
(foo.as_CFType(), n42.as_CFType()),
]);
let data = create_data(dict1.as_CFTypeRef(), kCFPropertyListXMLFormat_v1_0).unwrap();
let (dict2, _) = create_with_data(data, kCFPropertyListImmutable).unwrap();
unsafe {
assert_eq!(CFEqual(dict1.as_CFTypeRef(), dict2), 1);
}
}
#[test]
fn to_propertylist_retain_count() {
let string = CFString::from_static_string("alongerstring");
assert_eq!(string.retain_count(), 1);
let propertylist = string.to_CFPropertyList();
assert_eq!(string.retain_count(), 2);
assert_eq!(propertylist.retain_count(), 2);
mem::drop(string);
assert_eq!(propertylist.retain_count(), 1);
}
#[test]
fn downcast_string() {
let propertylist = CFString::from_static_string("Bar").to_CFPropertyList();
assert_eq!(
propertylist.downcast::<CFString>().unwrap().to_string(),
"Bar"
);
assert!(propertylist.downcast::<CFBoolean>().is_none());
}
#[test]
fn downcast_boolean() {
let propertylist = CFBoolean::true_value().to_CFPropertyList();
assert!(propertylist.downcast::<CFBoolean>().is_some());
assert!(propertylist.downcast::<CFString>().is_none());
}
#[test]
fn downcast_into_fail() {
let string = CFString::from_static_string("alongerstring");
let propertylist = string.to_CFPropertyList();
assert_eq!(string.retain_count(), 2);
assert!(propertylist.downcast_into::<CFBoolean>().is_none());
assert_eq!(string.retain_count(), 1);
}
#[test]
fn downcast_into() {
let string = CFString::from_static_string("alongerstring");
let propertylist = string.to_CFPropertyList();
assert_eq!(string.retain_count(), 2);
let string2 = propertylist.downcast_into::<CFString>().unwrap();
assert_eq!(string2.to_string(), "alongerstring");
assert_eq!(string2.retain_count(), 2);
}
}

304
vendor/core-foundation/src/runloop.rs vendored Normal file
View File

@@ -0,0 +1,304 @@
// 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.
#![allow(non_upper_case_globals)]
use core_foundation_sys::base::CFIndex;
use core_foundation_sys::base::{kCFAllocatorDefault, CFOptionFlags};
pub use core_foundation_sys::runloop::*;
use core_foundation_sys::string::CFStringRef;
use crate::base::TCFType;
use crate::date::{CFAbsoluteTime, CFTimeInterval};
use crate::filedescriptor::CFFileDescriptor;
use crate::string::CFString;
pub type CFRunLoopMode = CFStringRef;
declare_TCFType!(CFRunLoop, CFRunLoopRef);
impl_TCFType!(CFRunLoop, CFRunLoopRef, CFRunLoopGetTypeID);
impl_CFTypeDescription!(CFRunLoop);
// https://github.com/servo/core-foundation-rs/issues/550
unsafe impl Send for CFRunLoop {}
unsafe impl Sync for CFRunLoop {}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum CFRunLoopRunResult {
Finished = 1,
Stopped = 2,
TimedOut = 3,
HandledSource = 4,
}
impl CFRunLoop {
pub fn get_current() -> CFRunLoop {
unsafe {
let run_loop_ref = CFRunLoopGetCurrent();
TCFType::wrap_under_get_rule(run_loop_ref)
}
}
pub fn get_main() -> CFRunLoop {
unsafe {
let run_loop_ref = CFRunLoopGetMain();
TCFType::wrap_under_get_rule(run_loop_ref)
}
}
pub fn run_current() {
unsafe {
CFRunLoopRun();
}
}
pub fn run_in_mode(
mode: CFStringRef,
duration: std::time::Duration,
return_after_source_handled: bool,
) -> CFRunLoopRunResult {
let seconds = duration.as_secs_f64();
let return_after_source_handled = if return_after_source_handled { 1 } else { 0 };
unsafe {
match CFRunLoopRunInMode(mode, seconds, return_after_source_handled) {
2 => CFRunLoopRunResult::Stopped,
3 => CFRunLoopRunResult::TimedOut,
4 => CFRunLoopRunResult::HandledSource,
_ => CFRunLoopRunResult::Finished,
}
}
}
pub fn stop(&self) {
unsafe {
CFRunLoopStop(self.0);
}
}
pub fn current_mode(&self) -> Option<String> {
unsafe {
let string_ref = CFRunLoopCopyCurrentMode(self.0);
if string_ref.is_null() {
return None;
}
let cf_string: CFString = TCFType::wrap_under_create_rule(string_ref);
Some(cf_string.to_string())
}
}
pub fn contains_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) -> bool {
unsafe { CFRunLoopContainsTimer(self.0, timer.0, mode) != 0 }
}
pub fn add_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) {
unsafe {
CFRunLoopAddTimer(self.0, timer.0, mode);
}
}
pub fn remove_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) {
unsafe {
CFRunLoopRemoveTimer(self.0, timer.0, mode);
}
}
pub fn contains_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) -> bool {
unsafe { CFRunLoopContainsSource(self.0, source.0, mode) != 0 }
}
pub fn add_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) {
unsafe {
CFRunLoopAddSource(self.0, source.0, mode);
}
}
pub fn remove_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) {
unsafe {
CFRunLoopRemoveSource(self.0, source.0, mode);
}
}
pub fn contains_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) -> bool {
unsafe { CFRunLoopContainsObserver(self.0, observer.0, mode) != 0 }
}
pub fn add_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) {
unsafe {
CFRunLoopAddObserver(self.0, observer.0, mode);
}
}
pub fn remove_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) {
unsafe {
CFRunLoopRemoveObserver(self.0, observer.0, mode);
}
}
}
declare_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef);
impl_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef, CFRunLoopTimerGetTypeID);
impl CFRunLoopTimer {
pub fn new(
fireDate: CFAbsoluteTime,
interval: CFTimeInterval,
flags: CFOptionFlags,
order: CFIndex,
callout: CFRunLoopTimerCallBack,
context: *mut CFRunLoopTimerContext,
) -> CFRunLoopTimer {
unsafe {
let timer_ref = CFRunLoopTimerCreate(
kCFAllocatorDefault,
fireDate,
interval,
flags,
order,
callout,
context,
);
TCFType::wrap_under_create_rule(timer_ref)
}
}
}
declare_TCFType!(CFRunLoopSource, CFRunLoopSourceRef);
impl_TCFType!(
CFRunLoopSource,
CFRunLoopSourceRef,
CFRunLoopSourceGetTypeID
);
impl CFRunLoopSource {
pub fn from_file_descriptor(fd: &CFFileDescriptor, order: CFIndex) -> Option<CFRunLoopSource> {
fd.to_run_loop_source(order)
}
}
declare_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef);
impl_TCFType!(
CFRunLoopObserver,
CFRunLoopObserverRef,
CFRunLoopObserverGetTypeID
);
#[cfg(test)]
mod test {
use super::*;
use crate::base::Boolean;
use crate::date::{CFAbsoluteTime, CFDate};
use core::ffi::c_void;
use std::mem;
use std::ptr::null_mut;
use std::sync::mpsc;
use std::thread::spawn;
use std::time::Duration;
#[test]
fn wait_200_milliseconds() {
let run_loop = CFRunLoop::get_current();
let now = CFDate::now().abs_time();
let (elapsed_tx, elapsed_rx) = mpsc::channel();
let mut info = Info {
start_time: now,
elapsed_tx,
};
let mut context = CFRunLoopTimerContext {
version: 0,
info: &mut info as *mut _ as *mut c_void,
retain: None,
release: None,
copyDescription: None,
};
let run_loop_timer =
CFRunLoopTimer::new(now + 0.20f64, 0f64, 0, 0, timer_popped, &mut context);
unsafe {
run_loop.add_timer(&run_loop_timer, kCFRunLoopDefaultMode);
}
CFRunLoop::run_current();
let elapsed = elapsed_rx.try_recv().unwrap();
println!("wait_200_milliseconds, elapsed: {}", elapsed);
assert!(elapsed > 0.19 && elapsed < 0.35);
}
struct Info {
start_time: CFAbsoluteTime,
elapsed_tx: mpsc::Sender<f64>,
}
extern "C" fn timer_popped(_timer: CFRunLoopTimerRef, raw_info: *mut c_void) {
let info: *mut Info = unsafe { mem::transmute(raw_info) };
let now = CFDate::now().abs_time();
let elapsed = now - unsafe { (*info).start_time };
let _ = unsafe { (*info).elapsed_tx.send(elapsed) };
CFRunLoop::get_current().stop();
}
extern "C" fn observe(_: CFRunLoopObserverRef, _: CFRunLoopActivity, context: *mut c_void) {
let tx: &mpsc::Sender<CFRunLoop> = unsafe { &*(context as *const _) };
let _ = tx.send(CFRunLoop::get_current());
}
extern "C" fn observe_timer_popped(_: CFRunLoopTimerRef, _: *mut c_void) {
panic!("timer popped unexpectedly");
}
#[test]
fn observe_runloop() {
let (tx, rx) = mpsc::channel();
spawn(move || {
let mut context = CFRunLoopObserverContext {
version: 0,
info: &tx as *const _ as *mut c_void,
retain: None,
release: None,
copyDescription: None,
};
let observer = unsafe {
CFRunLoopObserver::wrap_under_create_rule(CFRunLoopObserverCreate(
kCFAllocatorDefault,
kCFRunLoopEntry,
false as Boolean,
0,
observe,
&mut context,
))
};
let runloop = CFRunLoop::get_current();
runloop.add_observer(&observer, unsafe { kCFRunLoopDefaultMode });
let timer = CFRunLoopTimer::new(
CFDate::now().abs_time() + 1f64,
0f64,
0,
0,
observe_timer_popped,
null_mut(),
);
runloop.add_timer(&timer, unsafe { kCFRunLoopDefaultMode });
let result = unsafe {
CFRunLoop::run_in_mode(kCFRunLoopDefaultMode, Duration::from_secs(10), false)
};
assert_eq!(result, CFRunLoopRunResult::Stopped);
drop(tx);
});
let runloop: CFRunLoop = rx.recv().unwrap();
runloop.stop();
}
}

61
vendor/core-foundation/src/set.rs vendored Normal file
View File

@@ -0,0 +1,61 @@
// 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.
//! An immutable bag of elements.
use core_foundation_sys::base::{kCFAllocatorDefault, CFRelease, CFTypeRef};
pub use core_foundation_sys::set::*;
use crate::base::{CFIndexConvertible, TCFType};
use core::ffi::c_void;
use std::marker::PhantomData;
/// An immutable bag of elements.
pub struct CFSet<T = *const c_void>(CFSetRef, PhantomData<T>);
impl<T> Drop for CFSet<T> {
fn drop(&mut self) {
unsafe { CFRelease(self.as_CFTypeRef()) }
}
}
impl_TCFType!(CFSet<T>, CFSetRef, CFSetGetTypeID);
impl_CFTypeDescription!(CFSet);
impl CFSet {
/// Creates a new set from a list of `CFType` instances.
pub fn from_slice<T>(elems: &[T]) -> CFSet<T>
where
T: TCFType,
{
unsafe {
let elems: Vec<CFTypeRef> = elems.iter().map(|elem| elem.as_CFTypeRef()).collect();
let set_ref = CFSetCreate(
kCFAllocatorDefault,
elems.as_ptr(),
elems.len().to_CFIndex(),
&kCFTypeSetCallBacks,
);
TCFType::wrap_under_create_rule(set_ref)
}
}
}
impl<T> CFSet<T> {
/// Get the number of elements in the `CFSet`.
pub fn len(&self) -> usize {
unsafe { CFSetGetCount(self.0) as usize }
}
/// Returns `true` if the set contains no elements.
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}

209
vendor/core-foundation/src/string.rs vendored Normal file
View File

@@ -0,0 +1,209 @@
// 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.
//! Immutable strings.
pub use core_foundation_sys::string::*;
use crate::base::{CFIndexConvertible, TCFType};
use core_foundation_sys::base::{kCFAllocatorDefault, kCFAllocatorNull};
use core_foundation_sys::base::{Boolean, CFIndex, CFRange};
use std::borrow::Cow;
use std::ffi::CStr;
use std::fmt;
use std::ptr;
use std::str::{self, FromStr};
declare_TCFType! {
/// An immutable string in one of a variety of encodings.
CFString, CFStringRef
}
impl_TCFType!(CFString, CFStringRef, CFStringGetTypeID);
impl FromStr for CFString {
type Err = ();
/// See also [`CFString::new()`] for a variant of this which does not return a `Result`.
#[inline]
fn from_str(string: &str) -> Result<CFString, ()> {
Ok(CFString::new(string))
}
}
impl<'a> From<&'a str> for CFString {
#[inline]
fn from(string: &'a str) -> CFString {
CFString::new(string)
}
}
impl<'a> From<&'a CFString> for Cow<'a, str> {
fn from(cf_str: &'a CFString) -> Cow<'a, str> {
unsafe {
// Do this without allocating if we can get away with it
let c_string = CFStringGetCStringPtr(cf_str.0, kCFStringEncodingUTF8);
if !c_string.is_null() {
let c_str = CStr::from_ptr(c_string);
Cow::Borrowed(str::from_utf8_unchecked(c_str.to_bytes()))
} else {
let char_len = cf_str.char_len();
// First, ask how big the buffer ought to be.
let mut bytes_required: CFIndex = 0;
CFStringGetBytes(
cf_str.0,
CFRange {
location: 0,
length: char_len,
},
kCFStringEncodingUTF8,
0,
false as Boolean,
ptr::null_mut(),
0,
&mut bytes_required,
);
// Then, allocate the buffer and actually copy.
let mut buffer = vec![b'\x00'; bytes_required as usize];
let mut bytes_used: CFIndex = 0;
let chars_written = CFStringGetBytes(
cf_str.0,
CFRange {
location: 0,
length: char_len,
},
kCFStringEncodingUTF8,
0,
false as Boolean,
buffer.as_mut_ptr(),
buffer.len().to_CFIndex(),
&mut bytes_used,
);
assert_eq!(chars_written, char_len);
// This is dangerous; we over-allocate and null-terminate the string (during
// initialization).
assert_eq!(bytes_used, buffer.len().to_CFIndex());
Cow::Owned(String::from_utf8_unchecked(buffer))
}
}
}
}
impl fmt::Display for CFString {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(&Cow::from(self))
}
}
impl fmt::Debug for CFString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\"{}\"", self)
}
}
impl CFString {
/// Creates a new `CFString` instance from a Rust string.
#[inline]
pub fn new(string: &str) -> CFString {
unsafe {
let string_ref = CFStringCreateWithBytes(
kCFAllocatorDefault,
string.as_ptr(),
string.len().to_CFIndex(),
kCFStringEncodingUTF8,
false as Boolean,
);
CFString::wrap_under_create_rule(string_ref)
}
}
/// Like `CFString::new`, but references a string that can be used as a backing store
/// by virtue of being statically allocated.
#[inline]
pub fn from_static_string(string: &'static str) -> CFString {
unsafe {
let string_ref = CFStringCreateWithBytesNoCopy(
kCFAllocatorDefault,
string.as_ptr(),
string.len().to_CFIndex(),
kCFStringEncodingUTF8,
false as Boolean,
kCFAllocatorNull,
);
TCFType::wrap_under_create_rule(string_ref)
}
}
/// Returns the number of characters in the string.
#[inline]
pub fn char_len(&self) -> CFIndex {
unsafe { CFStringGetLength(self.0) }
}
}
impl PartialEq<&str> for CFString {
fn eq(&self, other: &&str) -> bool {
unsafe {
let temp = CFStringCreateWithBytesNoCopy(
kCFAllocatorDefault,
other.as_ptr(),
other.len().to_CFIndex(),
kCFStringEncodingUTF8,
false as Boolean,
kCFAllocatorNull,
);
self.eq(&CFString::wrap_under_create_rule(temp))
}
}
}
impl PartialEq<CFString> for &str {
#[inline]
fn eq(&self, other: &CFString) -> bool {
other.eq(self)
}
}
impl PartialEq<CFString> for String {
#[inline]
fn eq(&self, other: &CFString) -> bool {
other.eq(&self.as_str())
}
}
impl PartialEq<String> for CFString {
#[inline]
fn eq(&self, other: &String) -> bool {
self.eq(&other.as_str())
}
}
#[test]
fn str_cmp() {
let cfstr = CFString::new("hello");
assert_eq!("hello", cfstr);
assert_eq!(cfstr, "hello");
assert_ne!(cfstr, "wrong");
assert_ne!("wrong", cfstr);
let hello = String::from("hello");
assert_eq!(hello, cfstr);
assert_eq!(cfstr, hello);
}
#[test]
fn string_and_back() {
let original = "The quick brown fox jumped over the slow lazy dog.";
let cfstr = CFString::from_static_string(original);
let converted = cfstr.to_string();
assert_eq!(converted, original);
}

73
vendor/core-foundation/src/timezone.rs vendored Normal file
View File

@@ -0,0 +1,73 @@
// 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.
//! Core Foundation time zone objects.
use core_foundation_sys::base::kCFAllocatorDefault;
pub use core_foundation_sys::timezone::*;
use crate::base::TCFType;
use crate::date::{CFDate, CFTimeInterval};
use crate::string::CFString;
declare_TCFType! {
/// A time zone.
CFTimeZone, CFTimeZoneRef
}
impl_TCFType!(CFTimeZone, CFTimeZoneRef, CFTimeZoneGetTypeID);
impl_CFTypeDescription!(CFTimeZone);
impl Default for CFTimeZone {
fn default() -> CFTimeZone {
unsafe {
let tz_ref = CFTimeZoneCopyDefault();
TCFType::wrap_under_create_rule(tz_ref)
}
}
}
impl CFTimeZone {
#[inline]
pub fn new(interval: CFTimeInterval) -> CFTimeZone {
unsafe {
let tz_ref = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, interval);
TCFType::wrap_under_create_rule(tz_ref)
}
}
#[inline]
pub fn system() -> CFTimeZone {
unsafe {
let tz_ref = CFTimeZoneCopySystem();
TCFType::wrap_under_create_rule(tz_ref)
}
}
pub fn seconds_from_gmt(&self, date: CFDate) -> CFTimeInterval {
unsafe { CFTimeZoneGetSecondsFromGMT(self.0, date.abs_time()) }
}
/// The timezone database ID that identifies the time zone. E.g. `"America/Los_Angeles" `or
/// `"Europe/Paris"`.
pub fn name(&self) -> CFString {
unsafe { CFString::wrap_under_get_rule(CFTimeZoneGetName(self.0)) }
}
}
#[cfg(test)]
mod test {
use super::CFTimeZone;
#[test]
fn timezone_comparison() {
let system = CFTimeZone::system();
let default = CFTimeZone::default();
assert_eq!(system, default);
}
}

185
vendor/core-foundation/src/url.rs vendored Normal file
View File

@@ -0,0 +1,185 @@
// 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.
//! A URL type for Core Foundation.
pub use core_foundation_sys::url::*;
use crate::base::{CFIndex, TCFType};
use crate::string::CFString;
use core::ffi::c_char;
use core_foundation_sys::base::{kCFAllocatorDefault, Boolean};
use std::fmt;
use std::path::{Path, PathBuf};
use std::ptr;
use libc::{strlen, PATH_MAX};
#[cfg(unix)]
use std::ffi::OsStr;
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;
declare_TCFType!(CFURL, CFURLRef);
impl_TCFType!(CFURL, CFURLRef, CFURLGetTypeID);
impl fmt::Debug for CFURL {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
unsafe {
let string: CFString = TCFType::wrap_under_get_rule(CFURLGetString(self.0));
write!(f, "{}", string)
}
}
}
impl CFURL {
pub fn from_path<P: AsRef<Path>>(path: P, isDirectory: bool) -> Option<CFURL> {
let path_bytes;
#[cfg(unix)]
{
path_bytes = path.as_ref().as_os_str().as_bytes()
}
#[cfg(not(unix))]
{
// XXX: Getting non-valid UTF8 paths into CoreFoundation on Windows is going to be unpleasant
// CFURLGetWideFileSystemRepresentation might help
path_bytes = match path.as_ref().to_str() {
Some(path) => path,
None => return None,
}
}
unsafe {
let url_ref = CFURLCreateFromFileSystemRepresentation(
ptr::null_mut(),
path_bytes.as_ptr(),
path_bytes.len() as CFIndex,
isDirectory as u8,
);
if url_ref.is_null() {
return None;
}
Some(TCFType::wrap_under_create_rule(url_ref))
}
}
pub fn from_file_system_path(
filePath: CFString,
pathStyle: CFURLPathStyle,
isDirectory: bool,
) -> CFURL {
unsafe {
let url_ref = CFURLCreateWithFileSystemPath(
kCFAllocatorDefault,
filePath.as_concrete_TypeRef(),
pathStyle,
isDirectory as u8,
);
TCFType::wrap_under_create_rule(url_ref)
}
}
#[cfg(unix)]
pub fn to_path(&self) -> Option<PathBuf> {
// implementing this on Windows is more complicated because of the different OsStr representation
unsafe {
let mut buf = [0u8; PATH_MAX as usize];
let result = CFURLGetFileSystemRepresentation(
self.0,
true as Boolean,
buf.as_mut_ptr(),
buf.len() as CFIndex,
);
if result == false as Boolean {
return None;
}
let len = strlen(buf.as_ptr() as *const c_char);
let path = OsStr::from_bytes(&buf[0..len]);
Some(PathBuf::from(path))
}
}
pub fn get_string(&self) -> CFString {
unsafe { TCFType::wrap_under_get_rule(CFURLGetString(self.0)) }
}
pub fn get_file_system_path(&self, pathStyle: CFURLPathStyle) -> CFString {
unsafe {
TCFType::wrap_under_create_rule(CFURLCopyFileSystemPath(
self.as_concrete_TypeRef(),
pathStyle,
))
}
}
pub fn absolute(&self) -> CFURL {
unsafe { TCFType::wrap_under_create_rule(CFURLCopyAbsoluteURL(self.as_concrete_TypeRef())) }
}
}
#[test]
fn file_url_from_path() {
let path = "/usr/local/foo/";
let cfstr_path = CFString::from_static_string(path);
let cfurl = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true);
assert_eq!(cfurl.get_string().to_string(), "file:///usr/local/foo/");
}
#[cfg(unix)]
#[test]
fn non_utf8() {
use std::ffi::OsStr;
let path = Path::new(OsStr::from_bytes(b"/\xC0/blame"));
let cfurl = CFURL::from_path(path, false).unwrap();
assert_eq!(cfurl.to_path().unwrap(), path);
let len = unsafe { CFURLGetBytes(cfurl.as_concrete_TypeRef(), ptr::null_mut(), 0) };
assert_eq!(len, 17);
}
#[test]
fn absolute_file_url() {
use core_foundation_sys::url::CFURLCreateWithFileSystemPathRelativeToBase;
use std::path::PathBuf;
let path = "/usr/local/foo";
let file = "bar";
let cfstr_path = CFString::from_static_string(path);
let cfstr_file = CFString::from_static_string(file);
let cfurl_base = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true);
let cfurl_relative: CFURL = unsafe {
let url_ref = CFURLCreateWithFileSystemPathRelativeToBase(
kCFAllocatorDefault,
cfstr_file.as_concrete_TypeRef(),
kCFURLPOSIXPathStyle,
false as u8,
cfurl_base.as_concrete_TypeRef(),
);
TCFType::wrap_under_create_rule(url_ref)
};
let mut absolute_path = PathBuf::from(path);
absolute_path.push(file);
assert_eq!(
cfurl_relative
.get_file_system_path(kCFURLPOSIXPathStyle)
.to_string(),
file
);
assert_eq!(
cfurl_relative
.absolute()
.get_file_system_path(kCFURLPOSIXPathStyle)
.to_string(),
absolute_path.to_str().unwrap()
);
}

97
vendor/core-foundation/src/uuid.rs vendored Normal file
View File

@@ -0,0 +1,97 @@
// 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.
//! Core Foundation UUID objects.
use core_foundation_sys::base::kCFAllocatorDefault;
pub use core_foundation_sys::uuid::*;
use crate::base::TCFType;
#[cfg(feature = "with-uuid")]
use uuid::Uuid;
declare_TCFType! {
/// A UUID.
CFUUID, CFUUIDRef
}
impl_TCFType!(CFUUID, CFUUIDRef, CFUUIDGetTypeID);
impl_CFTypeDescription!(CFUUID);
impl CFUUID {
#[inline]
pub fn new() -> CFUUID {
unsafe {
let uuid_ref = CFUUIDCreate(kCFAllocatorDefault);
TCFType::wrap_under_create_rule(uuid_ref)
}
}
}
impl Default for CFUUID {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "with-uuid")]
impl From<CFUUID> for Uuid {
fn from(val: CFUUID) -> Self {
let b = unsafe { CFUUIDGetUUIDBytes(val.0) };
let bytes = [
b.byte0, b.byte1, b.byte2, b.byte3, b.byte4, b.byte5, b.byte6, b.byte7, b.byte8,
b.byte9, b.byte10, b.byte11, b.byte12, b.byte13, b.byte14, b.byte15,
];
Uuid::from_bytes(bytes)
}
}
#[cfg(feature = "with-uuid")]
impl From<Uuid> for CFUUID {
fn from(uuid: Uuid) -> CFUUID {
let b = uuid.as_bytes();
let bytes = CFUUIDBytes {
byte0: b[0],
byte1: b[1],
byte2: b[2],
byte3: b[3],
byte4: b[4],
byte5: b[5],
byte6: b[6],
byte7: b[7],
byte8: b[8],
byte9: b[9],
byte10: b[10],
byte11: b[11],
byte12: b[12],
byte13: b[13],
byte14: b[14],
byte15: b[15],
};
unsafe {
let uuid_ref = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, bytes);
TCFType::wrap_under_create_rule(uuid_ref)
}
}
}
#[cfg(test)]
#[cfg(feature = "with-uuid")]
mod test {
use super::CFUUID;
use uuid::Uuid;
#[test]
fn uuid_conversion() {
let cf_uuid = CFUUID::new();
let uuid: Uuid = cf_uuid.clone().into();
let converted = CFUUID::from(uuid);
assert_eq!(cf_uuid, converted);
}
}