summaryrefslogtreecommitdiffstats
path: root/third_party/rust/core-foundation/src
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/core-foundation/src')
-rw-r--r--third_party/rust/core-foundation/src/array.rs286
-rw-r--r--third_party/rust/core-foundation/src/attributed_string.rs98
-rw-r--r--third_party/rust/core-foundation/src/base.rs452
-rw-r--r--third_party/rust/core-foundation/src/boolean.rs70
-rw-r--r--third_party/rust/core-foundation/src/bundle.rs190
-rw-r--r--third_party/rust/core-foundation/src/characterset.rs21
-rw-r--r--third_party/rust/core-foundation/src/data.rs144
-rw-r--r--third_party/rust/core-foundation/src/date.rs130
-rw-r--r--third_party/rust/core-foundation/src/dictionary.rs409
-rw-r--r--third_party/rust/core-foundation/src/error.rs71
-rw-r--r--third_party/rust/core-foundation/src/filedescriptor.rs194
-rw-r--r--third_party/rust/core-foundation/src/lib.rs236
-rw-r--r--third_party/rust/core-foundation/src/mach_port.rs28
-rw-r--r--third_party/rust/core-foundation/src/number.rs120
-rw-r--r--third_party/rust/core-foundation/src/propertylist.rs329
-rw-r--r--third_party/rust/core-foundation/src/runloop.rs224
-rw-r--r--third_party/rust/core-foundation/src/set.rs53
-rw-r--r--third_party/rust/core-foundation/src/string.rs197
-rw-r--r--third_party/rust/core-foundation/src/timezone.rs104
-rw-r--r--third_party/rust/core-foundation/src/url.rs155
-rw-r--r--third_party/rust/core-foundation/src/uuid.rs118
21 files changed, 3629 insertions, 0 deletions
diff --git a/third_party/rust/core-foundation/src/array.rs b/third_party/rust/core-foundation/src/array.rs
new file mode 100644
index 0000000000..d66ffc5b82
--- /dev/null
+++ b/third_party/rust/core-foundation/src/array.rs
@@ -0,0 +1,286 @@
+// 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.
+
+pub use core_foundation_sys::array::*;
+pub use core_foundation_sys::base::CFIndex;
+use core_foundation_sys::base::{CFTypeRef, CFRelease, kCFAllocatorDefault};
+use std::mem;
+use std::marker::PhantomData;
+use std::os::raw::c_void;
+use std::ptr;
+use ConcreteCFType;
+
+use base::{CFIndexConvertible, TCFType, CFRange};
+use 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<'a, T: FromVoid> ExactSizeIterator for CFArrayIterator<'a, 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<'a>(&'a self) -> CFArrayIterator<'a, T> {
+ CFArrayIterator {
+ array: self,
+ index: 0,
+ len: self.len(),
+ }
+ }
+
+ #[inline]
+ pub fn len(&self) -> CFIndex {
+ unsafe {
+ CFArrayGetCount(self.0)
+ }
+ }
+
+ #[inline]
+ pub unsafe fn get_unchecked<'a>(&'a self, index: CFIndex) -> ItemRef<'a, T> where T: FromVoid {
+ T::from_void(CFArrayGetValueAtIndex(self.0, index))
+ }
+
+ #[inline]
+ pub fn get<'a>(&'a self, index: CFIndex) -> Option<ItemRef<'a, 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 super::*;
+ use std::mem;
+ use base::CFType;
+
+ #[test]
+ fn to_untyped_correct_retain_count() {
+ let array = CFArray::<CFType>::from_CFTypes(&[]);
+ 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(&[]);
+ 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 string::CFString;
+
+ let string = CFString::from_static_string("bar");
+ 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(), "bar");
+ }
+ }
+ assert_eq!(x.retain_count(), 1);
+ }
+
+ #[test]
+ fn iter_untyped_array() {
+ use string::{CFString, CFStringRef};
+ use base::TCFTypeRef;
+
+ let cf_string = CFString::from_static_string("bar");
+ 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[..], &["bar"]);
+ }
+
+ #[test]
+ fn should_box_and_unbox() {
+ use 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);
+ }
+}
diff --git a/third_party/rust/core-foundation/src/attributed_string.rs b/third_party/rust/core-foundation/src/attributed_string.rs
new file mode 100644
index 0000000000..d4a467946d
--- /dev/null
+++ b/third_party/rust/core-foundation/src/attributed_string.rs
@@ -0,0 +1,98 @@
+// 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 base::TCFType;
+use core_foundation_sys::base::{CFIndex, CFRange, kCFAllocatorDefault};
+use std::ptr::null;
+use string::{CFString, CFStringRef};
+
+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());
+ }
+} \ No newline at end of file
diff --git a/third_party/rust/core-foundation/src/base.rs b/third_party/rust/core-foundation/src/base.rs
new file mode 100644
index 0000000000..f08f2b2e85
--- /dev/null
+++ b/third_party/rust/core-foundation/src/base.rs
@@ -0,0 +1,452 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std;
+use std::fmt;
+use std::marker::PhantomData;
+use std::mem;
+use std::mem::ManuallyDrop;
+use std::ops::{Deref, DerefMut};
+use std::os::raw::c_void;
+
+pub use core_foundation_sys::base::*;
+
+use string::CFString;
+use ConcreteCFType;
+
+pub trait CFIndexConvertible {
+ /// Always use this method to construct a `CFIndex` value. It performs bounds checking to
+ /// ensure the value is in range.
+ fn to_CFIndex(self) -> CFIndex;
+}
+
+impl CFIndexConvertible for usize {
+ #[inline]
+ fn to_CFIndex(self) -> CFIndex {
+ let max_CFIndex = CFIndex::max_value();
+ if self > (max_CFIndex as usize) {
+ panic!("value out of range")
+ }
+ self as CFIndex
+ }
+}
+
+declare_TCFType!{
+ /// Superclass of all Core Foundation objects.
+ CFType, CFTypeRef
+}
+
+impl CFType {
+ /// Try to downcast the `CFType` to a subclass. Checking if the instance is the
+ /// correct subclass happens at runtime and `None` is returned if it is not the correct type.
+ /// Works similar to [`Box::downcast`] and [`CFPropertyList::downcast`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use core_foundation::string::CFString;
+ /// # use core_foundation::boolean::CFBoolean;
+ /// # use core_foundation::base::{CFType, TCFType};
+ /// #
+ /// // Create a string.
+ /// let string: CFString = CFString::from_static_string("FooBar");
+ /// // Cast it up to a CFType.
+ /// let cf_type: CFType = string.as_CFType();
+ /// // Cast it down again.
+ /// assert_eq!(cf_type.downcast::<CFString>().unwrap().to_string(), "FooBar");
+ /// // Casting it to some other type will yield `None`
+ /// assert!(cf_type.downcast::<CFBoolean>().is_none());
+ /// ```
+ ///
+ /// ```compile_fail
+ /// # use core_foundation::array::CFArray;
+ /// # use core_foundation::base::TCFType;
+ /// # use core_foundation::boolean::CFBoolean;
+ /// # use core_foundation::string::CFString;
+ /// #
+ /// let boolean_array = CFArray::from_CFTypes(&[CFBoolean::true_value()]).into_CFType();
+ ///
+ /// // This downcast is not allowed and causes compiler error, since it would cause undefined
+ /// // behavior to access the elements of the array as a CFString:
+ /// let invalid_string_array = boolean_array
+ /// .downcast_into::<CFArray<CFString>>()
+ /// .unwrap();
+ /// ```
+ ///
+ /// [`Box::downcast`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast
+ /// [`CFPropertyList::downcast`]: ../propertylist/struct.CFPropertyList.html#method.downcast
+ #[inline]
+ pub fn downcast<T: ConcreteCFType>(&self) -> Option<T> {
+ if self.instance_of::<T>() {
+ unsafe {
+ let reference = T::Ref::from_void_ptr(self.0);
+ Some(T::wrap_under_get_rule(reference))
+ }
+ } else {
+ None
+ }
+ }
+
+ /// Similar to [`downcast`], but consumes self and can thus avoid touching the retain count.
+ ///
+ /// [`downcast`]: #method.downcast
+ #[inline]
+ pub fn downcast_into<T: ConcreteCFType>(self) -> Option<T> {
+ if self.instance_of::<T>() {
+ unsafe {
+ let reference = T::Ref::from_void_ptr(self.0);
+ mem::forget(self);
+ Some(T::wrap_under_create_rule(reference))
+ }
+ } else {
+ None
+ }
+ }
+}
+
+impl fmt::Debug for CFType {
+ /// Formats the value using [`CFCopyDescription`].
+ ///
+ /// [`CFCopyDescription`]: https://developer.apple.com/documentation/corefoundation/1521252-cfcopydescription?language=objc
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let desc = unsafe {
+ CFString::wrap_under_create_rule(CFCopyDescription(self.0))
+ };
+ desc.fmt(f)
+ }
+}
+
+impl Clone for CFType {
+ #[inline]
+ fn clone(&self) -> CFType {
+ unsafe {
+ TCFType::wrap_under_get_rule(self.0)
+ }
+ }
+}
+
+impl PartialEq for CFType {
+ #[inline]
+ fn eq(&self, other: &CFType) -> bool {
+ unsafe {
+ CFEqual(self.as_CFTypeRef(), other.as_CFTypeRef()) != 0
+ }
+ }
+}
+
+declare_TCFType!(CFAllocator, CFAllocatorRef);
+impl_TCFType!(CFAllocator, CFAllocatorRef, CFAllocatorGetTypeID);
+
+impl CFAllocator {
+ #[inline]
+ pub fn new(mut context: CFAllocatorContext) -> CFAllocator {
+ unsafe {
+ let allocator_ref = CFAllocatorCreate(kCFAllocatorDefault, &mut context);
+ TCFType::wrap_under_create_rule(allocator_ref)
+ }
+ }
+}
+
+
+/// All Core Foundation types implement this trait. The associated type `Ref` specifies the
+/// associated Core Foundation type: e.g. for `CFType` this is `CFTypeRef`; for `CFArray` this is
+/// `CFArrayRef`.
+///
+/// Most structs that implement this trait will do so via the [`impl_TCFType`] macro.
+///
+/// [`impl_TCFType`]: ../macro.impl_TCFType.html
+pub trait TCFType {
+ /// The reference type wrapped inside this type.
+ type Ref: TCFTypeRef;
+
+ /// Returns the object as its concrete TypeRef.
+ fn as_concrete_TypeRef(&self) -> Self::Ref;
+
+ /// Returns an instance of the object, wrapping the underlying `CFTypeRef` subclass. Use this
+ /// when following Core Foundation's "Create Rule". The reference count is *not* bumped.
+ unsafe fn wrap_under_create_rule(obj: Self::Ref) -> Self;
+
+ /// Returns the type ID for this class.
+ fn type_id() -> CFTypeID;
+
+ /// Returns the object as a wrapped `CFType`. The reference count is incremented by one.
+ #[inline]
+ fn as_CFType(&self) -> CFType {
+ unsafe {
+ TCFType::wrap_under_get_rule(self.as_CFTypeRef())
+ }
+ }
+
+ /// Returns the object as a wrapped `CFType`. Consumes self and avoids changing the reference
+ /// count.
+ #[inline]
+ fn into_CFType(self) -> CFType
+ where
+ Self: Sized,
+ {
+ let reference = self.as_CFTypeRef();
+ mem::forget(self);
+ unsafe { TCFType::wrap_under_create_rule(reference) }
+ }
+
+ /// Returns the object as a raw `CFTypeRef`. The reference count is not adjusted.
+ fn as_CFTypeRef(&self) -> CFTypeRef;
+
+ /// Returns an instance of the object, wrapping the underlying `CFTypeRef` subclass. Use this
+ /// when following Core Foundation's "Get Rule". The reference count *is* bumped.
+ unsafe fn wrap_under_get_rule(reference: Self::Ref) -> Self;
+
+ /// Returns the reference count of the object. It is unwise to do anything other than test
+ /// whether the return value of this method is greater than zero.
+ #[inline]
+ fn retain_count(&self) -> CFIndex {
+ unsafe {
+ CFGetRetainCount(self.as_CFTypeRef())
+ }
+ }
+
+ /// Returns the type ID of this object.
+ #[inline]
+ fn type_of(&self) -> CFTypeID {
+ unsafe {
+ CFGetTypeID(self.as_CFTypeRef())
+ }
+ }
+
+ /// Writes a debugging version of this object on standard error.
+ fn show(&self) {
+ unsafe {
+ CFShow(self.as_CFTypeRef())
+ }
+ }
+
+ /// Returns true if this value is an instance of another type.
+ #[inline]
+ fn instance_of<OtherCFType: TCFType>(&self) -> bool {
+ self.type_of() == OtherCFType::type_id()
+ }
+}
+
+impl TCFType for CFType {
+ type Ref = CFTypeRef;
+
+ #[inline]
+ fn as_concrete_TypeRef(&self) -> CFTypeRef {
+ self.0
+ }
+
+ #[inline]
+ unsafe fn wrap_under_get_rule(reference: CFTypeRef) -> CFType {
+ assert!(!reference.is_null(), "Attempted to create a NULL object.");
+ let reference: CFTypeRef = CFRetain(reference);
+ TCFType::wrap_under_create_rule(reference)
+ }
+
+ #[inline]
+ fn as_CFTypeRef(&self) -> CFTypeRef {
+ self.as_concrete_TypeRef()
+ }
+
+ #[inline]
+ unsafe fn wrap_under_create_rule(obj: CFTypeRef) -> CFType {
+ assert!(!obj.is_null(), "Attempted to create a NULL object.");
+ CFType(obj)
+ }
+
+ #[inline]
+ fn type_id() -> CFTypeID {
+ // FIXME(pcwalton): Is this right?
+ 0
+ }
+}
+
+/// A reference to an element inside a container
+pub struct ItemRef<'a, T: 'a>(ManuallyDrop<T>, PhantomData<&'a T>);
+
+impl<'a, T> Deref for ItemRef<'a, T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ &self.0
+ }
+}
+
+impl<'a, T: fmt::Debug> fmt::Debug for ItemRef<'a, T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ self.0.fmt(f)
+ }
+}
+
+impl<'a, T: PartialEq> PartialEq for ItemRef<'a, T> {
+ fn eq(&self, other: &Self) -> bool {
+ self.0.eq(&other.0)
+ }
+}
+
+/// A reference to a mutable element inside a container
+pub struct ItemMutRef<'a, T: 'a>(ManuallyDrop<T>, PhantomData<&'a T>);
+
+impl<'a, T> Deref for ItemMutRef<'a, T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ &self.0
+ }
+}
+
+impl<'a, T> DerefMut for ItemMutRef<'a, T> {
+ fn deref_mut(&mut self) -> &mut T {
+ &mut self.0
+ }
+}
+
+impl<'a, T: fmt::Debug> fmt::Debug for ItemMutRef<'a, T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ self.0.fmt(f)
+ }
+}
+
+impl<'a, T: PartialEq> PartialEq for ItemMutRef<'a, T> {
+ fn eq(&self, other: &Self) -> bool {
+ self.0.eq(&other.0)
+ }
+}
+
+/// A trait describing how to convert from the stored *mut c_void to the desired T
+pub unsafe trait FromMutVoid {
+ unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> where Self: std::marker::Sized;
+}
+
+unsafe impl FromMutVoid for u32 {
+ unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> {
+ ItemMutRef(ManuallyDrop::new(x as u32), PhantomData)
+ }
+}
+
+unsafe impl FromMutVoid for *const c_void {
+ unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> {
+ ItemMutRef(ManuallyDrop::new(x), PhantomData)
+ }
+}
+
+unsafe impl<T: TCFType> FromMutVoid for T {
+ unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> {
+ ItemMutRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData)
+ }
+}
+
+/// A trait describing how to convert from the stored *const c_void to the desired T
+pub unsafe trait FromVoid {
+ unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> where Self: std::marker::Sized;
+}
+
+unsafe impl FromVoid for u32 {
+ unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> {
+ // Functions like CGFontCopyTableTags treat the void*'s as u32's
+ // so we convert by casting directly
+ ItemRef(ManuallyDrop::new(x as u32), PhantomData)
+ }
+}
+
+unsafe impl FromVoid for *const c_void {
+ unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> {
+ ItemRef(ManuallyDrop::new(x), PhantomData)
+ }
+}
+
+unsafe impl<T: TCFType> FromVoid for T {
+ unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> {
+ ItemRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData)
+ }
+}
+
+/// A trait describing how to convert from the stored *const c_void to the desired T
+pub unsafe trait ToVoid<T> {
+ fn to_void(&self) -> *const c_void;
+}
+
+unsafe impl ToVoid<*const c_void> for *const c_void {
+ fn to_void(&self) -> *const c_void {
+ *self
+ }
+}
+
+unsafe impl<'a> ToVoid<CFType> for &'a CFType {
+ fn to_void(&self) -> *const ::std::os::raw::c_void {
+ self.as_concrete_TypeRef().as_void_ptr()
+ }
+}
+
+unsafe impl ToVoid<CFType> for CFType {
+ fn to_void(&self) -> *const ::std::os::raw::c_void {
+ self.as_concrete_TypeRef().as_void_ptr()
+ }
+}
+
+unsafe impl ToVoid<CFType> for CFTypeRef {
+ fn to_void(&self) -> *const ::std::os::raw::c_void {
+ self.as_void_ptr()
+ }
+}
+
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::mem;
+ use boolean::CFBoolean;
+
+ #[test]
+ fn cftype_instance_of() {
+ let string = CFString::from_static_string("foo");
+ let cftype = string.as_CFType();
+
+ assert!(cftype.instance_of::<CFString>());
+ assert!(!cftype.instance_of::<CFBoolean>());
+ }
+
+ #[test]
+ fn as_cftype_retain_count() {
+ let string = CFString::from_static_string("bar");
+ assert_eq!(string.retain_count(), 1);
+ let cftype = string.as_CFType();
+ assert_eq!(cftype.retain_count(), 2);
+ mem::drop(string);
+ assert_eq!(cftype.retain_count(), 1);
+ }
+
+ #[test]
+ fn into_cftype_retain_count() {
+ let string = CFString::from_static_string("bar");
+ assert_eq!(string.retain_count(), 1);
+ let cftype = string.into_CFType();
+ assert_eq!(cftype.retain_count(), 1);
+ }
+
+ #[test]
+ fn as_cftype_and_downcast() {
+ let string = CFString::from_static_string("bar");
+ let cftype = string.as_CFType();
+ let string2 = cftype.downcast::<CFString>().unwrap();
+ assert_eq!(string2.to_string(), "bar");
+
+ assert_eq!(string.retain_count(), 3);
+ assert_eq!(cftype.retain_count(), 3);
+ assert_eq!(string2.retain_count(), 3);
+ }
+
+ #[test]
+ fn into_cftype_and_downcast_into() {
+ let string = CFString::from_static_string("bar");
+ let cftype = string.into_CFType();
+ let string2 = cftype.downcast_into::<CFString>().unwrap();
+ assert_eq!(string2.to_string(), "bar");
+ assert_eq!(string2.retain_count(), 1);
+ }
+}
diff --git a/third_party/rust/core-foundation/src/boolean.rs b/third_party/rust/core-foundation/src/boolean.rs
new file mode 100644
index 0000000000..8c13b907da
--- /dev/null
+++ b/third_party/rust/core-foundation/src/boolean.rs
@@ -0,0 +1,70 @@
+// 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::{CFBooleanRef, CFBooleanGetTypeID, kCFBooleanTrue, kCFBooleanFalse};
+
+use 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));
+ }
+}
diff --git a/third_party/rust/core-foundation/src/bundle.rs b/third_party/rust/core-foundation/src/bundle.rs
new file mode 100644
index 0000000000..b9ab1f65f6
--- /dev/null
+++ b/third_party/rust/core-foundation/src/bundle.rs
@@ -0,0 +1,190 @@
+// 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_foundation_sys::base::kCFAllocatorDefault;
+pub use core_foundation_sys::bundle::*;
+use core_foundation_sys::url::kCFURLPOSIXPathStyle;
+use std::path::PathBuf;
+
+use base::{CFType, TCFType};
+use url::CFURL;
+use dictionary::CFDictionary;
+use std::os::raw::c_void;
+use string::CFString;
+
+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 string::CFString;
+ use url::{CFURL, kCFURLPOSIXPathStyle};
+
+ 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 string::CFString;
+ use url::{CFURL, kCFURLPOSIXPathStyle};
+
+ 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_existant_bundle() {
+ use string::CFString;
+ use url::{CFURL, kCFURLPOSIXPathStyle};
+
+ 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());
+}
diff --git a/third_party/rust/core-foundation/src/characterset.rs b/third_party/rust/core-foundation/src/characterset.rs
new file mode 100644
index 0000000000..d1b9439d6e
--- /dev/null
+++ b/third_party/rust/core-foundation/src/characterset.rs
@@ -0,0 +1,21 @@
+// 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::*;
+
+use base::TCFType;
+
+declare_TCFType!{
+ /// An immutable set of Unicde characters.
+ CFCharacterSet, CFCharacterSetRef
+}
+impl_TCFType!(CFCharacterSet, CFCharacterSetRef, CFCharacterSetGetTypeID);
+impl_CFTypeDescription!(CFCharacterSet);
diff --git a/third_party/rust/core-foundation/src/data.rs b/third_party/rust/core-foundation/src/data.rs
new file mode 100644
index 0000000000..c510c7434d
--- /dev/null
+++ b/third_party/rust/core-foundation/src/data.rs
@@ -0,0 +1,144 @@
+// 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.
+
+pub use core_foundation_sys::data::*;
+use core_foundation_sys::base::CFIndex;
+use core_foundation_sys::base::{kCFAllocatorDefault};
+use std::ops::Deref;
+use std::slice;
+use std::sync::Arc;
+
+
+use 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 std::os::raw::c_void;
+ use crate::base::{CFAllocator, CFAllocatorContext};
+
+ 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<'a>(&'a self) -> &'a [u8] {
+ unsafe {
+ slice::from_raw_parts(CFDataGetBytePtr(self.0), self.len() as usize)
+ }
+ }
+
+ /// Returns the length of this byte buffer.
+ #[inline]
+ pub fn len(&self) -> CFIndex {
+ unsafe {
+ CFDataGetLength(self.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))
+ }
+}
diff --git a/third_party/rust/core-foundation/src/date.rs b/third_party/rust/core-foundation/src/date.rs
new file mode 100644
index 0000000000..57ee7211e6
--- /dev/null
+++ b/third_party/rust/core-foundation/src/date.rs
@@ -0,0 +1,130 @@
+// 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.
+
+pub use core_foundation_sys::date::*;
+use core_foundation_sys::base::kCFAllocatorDefault;
+
+use base::TCFType;
+
+#[cfg(feature = "with-chrono")]
+use chrono::NaiveDateTime;
+
+
+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(feature = "with-chrono")]
+ pub fn naive_utc(&self) -> NaiveDateTime {
+ let ts = unsafe {
+ self.abs_time() + kCFAbsoluteTimeIntervalSince1970
+ };
+ let (secs, nanos) = if ts.is_sign_positive() {
+ (ts.trunc() as i64, ts.fract())
+ } else {
+ // nanoseconds can't be negative in NaiveDateTime
+ (ts.trunc() as i64 - 1, 1.0 - ts.fract().abs())
+ };
+ NaiveDateTime::from_timestamp(secs, (nanos * 1e9).floor() as u32)
+ }
+
+ #[cfg(feature = "with-chrono")]
+ pub fn from_naive_utc(time: NaiveDateTime) -> CFDate {
+ let secs = time.timestamp();
+ let nanos = time.timestamp_subsec_nanos();
+ let ts = unsafe {
+ secs as f64 + (nanos as f64 / 1e9) - kCFAbsoluteTimeIntervalSince1970
+ };
+ CFDate::new(ts)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::CFDate;
+ use std::cmp::Ordering;
+
+ #[cfg(feature = "with-chrono")]
+ use chrono::NaiveDateTime;
+
+ #[cfg(feature = "with-chrono")]
+ fn approx_eq(a: f64, b: f64) -> bool {
+ use std::f64;
+
+ let same_sign = a.is_sign_positive() == b.is_sign_positive();
+ let equal = ((a - b).abs() / f64::min(a.abs() + b.abs(), f64::MAX)) < f64::EPSILON;
+ (same_sign && equal)
+ }
+
+ #[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);
+ }
+
+ #[test]
+ #[cfg(feature = "with-chrono")]
+ fn date_chrono_conversion_positive() {
+ let date = CFDate::now();
+ let datetime = date.naive_utc();
+ let converted = CFDate::from_naive_utc(datetime);
+ assert!(approx_eq(date.abs_time(), converted.abs_time()));
+ }
+
+ #[test]
+ #[cfg(feature = "with-chrono")]
+ fn date_chrono_conversion_negative() {
+ use super::kCFAbsoluteTimeIntervalSince1970;
+
+ let ts = unsafe {
+ kCFAbsoluteTimeIntervalSince1970 - 420.0
+ };
+ let date = CFDate::new(ts);
+ let datetime: NaiveDateTime = date.naive_utc();
+ let converted = CFDate::from_naive_utc(datetime);
+ assert!(approx_eq(date.abs_time(), converted.abs_time()));
+ }
+}
diff --git a/third_party/rust/core-foundation/src/dictionary.rs b/third_party/rust/core-foundation/src/dictionary.rs
new file mode 100644
index 0000000000..efcbba1178
--- /dev/null
+++ b/third_party/rust/core-foundation/src/dictionary.rs
@@ -0,0 +1,409 @@
+// 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_foundation_sys::base::{CFTypeRef, CFRelease, kCFAllocatorDefault};
+use std::mem;
+use std::os::raw::c_void;
+use std::ptr;
+use std::marker::PhantomData;
+
+use base::{ItemRef, FromVoid, ToVoid};
+use base::{CFIndexConvertible, TCFType};
+use ConcreteCFType;
+
+// consume the type parameters with PhantomDatas
+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(|&(ref key, ref 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<'a, T: ToVoid<K>>(&'a self, key: T) -> 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, T: ToVoid<K>>(&'a self, key: T) -> 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)
+ }
+}
+
+// consume the type parameters with PhantomDatas
+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 &(ref key, ref 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 base::{CFType, TCFType};
+ use boolean::CFBoolean;
+ use number::CFNumber;
+ use 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);
+ }
+}
diff --git a/third_party/rust/core-foundation/src/error.rs b/third_party/rust/core-foundation/src/error.rs
new file mode 100644
index 0000000000..f100171bc9
--- /dev/null
+++ b/third_party/rust/core-foundation/src/error.rs
@@ -0,0 +1,71 @@
+// 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 base::{CFIndex, TCFType};
+use 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)
+ }
+ }
+}
diff --git a/third_party/rust/core-foundation/src/filedescriptor.rs b/third_party/rust/core-foundation/src/filedescriptor.rs
new file mode 100644
index 0000000000..e153c70b2f
--- /dev/null
+++ b/third_party/rust/core-foundation/src/filedescriptor.rs
@@ -0,0 +1,194 @@
+// 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::{Boolean, CFIndex};
+use core_foundation_sys::base::{kCFAllocatorDefault, CFOptionFlags};
+
+use base::TCFType;
+use 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 {
+ extern crate libc;
+
+ use super::*;
+ use std::ffi::CString;
+ use std::os::raw::c_void;
+ use core_foundation_sys::base::{CFOptionFlags};
+ use core_foundation_sys::runloop::{kCFRunLoopDefaultMode};
+ use libc::O_RDWR;
+ use runloop::{CFRunLoop};
+
+ #[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();
+ }
+}
diff --git a/third_party/rust/core-foundation/src/lib.rs b/third_party/rust/core-foundation/src/lib.rs
new file mode 100644
index 0000000000..b935938996
--- /dev/null
+++ b/third_party/rust/core-foundation/src/lib.rs
@@ -0,0 +1,236 @@
+// 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.
+
+extern crate core_foundation_sys;
+extern crate libc;
+
+#[cfg(feature = "with-chrono")]
+extern crate chrono;
+
+use 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.
+///
+/// ```
+/// #[macro_use] extern crate core_foundation;
+/// // 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
+ ) => {
+ $(#[$doc])*
+ pub struct $ty($raw);
+
+ impl Drop for $ty {
+ fn drop(&mut self) {
+ 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;
+
+ #[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 ::std::os::raw::c_void) as $ty_ref;
+ $crate::base::TCFType::wrap_under_create_rule(reference)
+ }
+
+ #[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()
+ }
+ }
+ }
+
+ impl Clone for $ty {
+ #[inline]
+ fn clone(&self) -> $ty {
+ unsafe {
+ $ty::wrap_under_get_rule(self.0)
+ }
+ }
+ }
+
+ impl PartialEq for $ty {
+ #[inline]
+ fn eq(&self, other: &$ty) -> bool {
+ self.as_CFType().eq(&other.as_CFType())
+ }
+ }
+
+ impl Eq for $ty { }
+
+ unsafe impl<'a> $crate::base::ToVoid<$ty> for &'a $ty {
+ fn to_void(&self) -> *const ::std::os::raw::c_void {
+ use $crate::base::TCFTypeRef;
+ self.as_concrete_TypeRef().as_void_ptr()
+ }
+ }
+
+ unsafe impl $crate::base::ToVoid<$ty> for $ty {
+ fn to_void(&self) -> *const ::std::os::raw::c_void {
+ use $crate::base::TCFTypeRef;
+ self.as_concrete_TypeRef().as_void_ptr()
+ }
+ }
+
+ unsafe impl $crate::base::ToVoid<$ty> for $ty_ref {
+ fn to_void(&self) -> *const ::std::os::raw::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)*),*>) => {
+ impl<$($p $(: $bound)*),*> ::std::fmt::Debug for $ty<$($p),*> {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ self.as_CFType().fmt(f)
+ }
+ }
+ }
+}
+
+#[macro_export]
+macro_rules! impl_CFComparison {
+ ($ty:ident, $compare:ident) => {
+ impl PartialOrd for $ty {
+ #[inline]
+ fn partial_cmp(&self, other: &$ty) -> Option<::std::cmp::Ordering> {
+ unsafe {
+ Some($compare(self.as_concrete_TypeRef(), other.as_concrete_TypeRef(), ::std::ptr::null_mut()).into())
+ }
+ }
+ }
+
+ impl Ord for $ty {
+ #[inline]
+ fn cmp(&self, other: &$ty) -> ::std::cmp::Ordering {
+ self.partial_cmp(other).unwrap()
+ }
+ }
+ }
+}
+
+pub mod array;
+pub mod attributed_string;
+pub mod base;
+pub mod boolean;
+pub mod characterset;
+pub mod data;
+pub mod date;
+pub mod dictionary;
+pub mod error;
+pub mod filedescriptor;
+pub mod number;
+pub mod set;
+pub mod string;
+pub mod url;
+pub mod bundle;
+pub mod propertylist;
+pub mod runloop;
+pub mod timezone;
+pub mod uuid;
+pub mod mach_port;
diff --git a/third_party/rust/core-foundation/src/mach_port.rs b/third_party/rust/core-foundation/src/mach_port.rs
new file mode 100644
index 0000000000..6112e3aae0
--- /dev/null
+++ b/third_party/rust/core-foundation/src/mach_port.rs
@@ -0,0 +1,28 @@
+use base::TCFType;
+use core_foundation_sys::base::kCFAllocatorDefault;
+use runloop::CFRunLoopSource;
+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))
+ }
+ }
+ }
+}
diff --git a/third_party/rust/core-foundation/src/number.rs b/third_party/rust/core-foundation/src/number.rs
new file mode 100644
index 0000000000..a4b2affaa7
--- /dev/null
+++ b/third_party/rust/core-foundation/src/number.rs
@@ -0,0 +1,120 @@
+// 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_foundation_sys::base::kCFAllocatorDefault;
+pub use core_foundation_sys::number::*;
+use std::os::raw::c_void;
+
+use 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)
+ }
+ }
+}
diff --git a/third_party/rust/core-foundation/src/propertylist.rs b/third_party/rust/core-foundation/src/propertylist.rs
new file mode 100644
index 0000000000..e8fceac58d
--- /dev/null
+++ b/third_party/rust/core-foundation/src/propertylist.rs
@@ -0,0 +1,329 @@
+// 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 std::ptr;
+use std::mem;
+use std::os::raw::c_void;
+
+use error::CFError;
+use data::CFData;
+use base::{CFType, TCFType, TCFTypeRef};
+
+pub use core_foundation_sys::propertylist::*;
+use core_foundation_sys::error::CFErrorRef;
+use core_foundation_sys::base::{CFGetRetainCount, CFGetTypeID, CFIndex, CFRetain,
+ CFShow, CFTypeID, kCFAllocatorDefault};
+
+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 ::data::CFData {}
+impl CFPropertyListSubClass for ::string::CFString {}
+impl CFPropertyListSubClass for ::array::CFArray {}
+impl CFPropertyListSubClass for ::dictionary::CFDictionary {}
+impl CFPropertyListSubClass for ::date::CFDate {}
+impl CFPropertyListSubClass for ::boolean::CFBoolean {}
+impl CFPropertyListSubClass for ::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 string::CFString;
+ use boolean::CFBoolean;
+
+ #[test]
+ fn test_property_list_serialization() {
+ use base::{TCFType, CFEqual};
+ use boolean::CFBoolean;
+ use number::CFNumber;
+ use dictionary::CFDictionary;
+ use string::CFString;
+ use super::*;
+
+ 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("Bar");
+ 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("Bar");
+ 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("Bar");
+ let propertylist = string.to_CFPropertyList();
+ assert_eq!(string.retain_count(), 2);
+
+ let string2 = propertylist.downcast_into::<CFString>().unwrap();
+ assert_eq!(string2.to_string(), "Bar");
+ assert_eq!(string2.retain_count(), 2);
+ }
+}
diff --git a/third_party/rust/core-foundation/src/runloop.rs b/third_party/rust/core-foundation/src/runloop.rs
new file mode 100644
index 0000000000..be06f4ec7f
--- /dev/null
+++ b/third_party/rust/core-foundation/src/runloop.rs
@@ -0,0 +1,224 @@
+// 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)]
+
+pub use core_foundation_sys::runloop::*;
+use core_foundation_sys::base::CFIndex;
+use core_foundation_sys::base::{kCFAllocatorDefault, CFOptionFlags};
+use core_foundation_sys::string::CFStringRef;
+
+use base::{TCFType};
+use date::{CFAbsoluteTime, CFTimeInterval};
+use filedescriptor::CFFileDescriptor;
+use string::{CFString};
+
+pub type CFRunLoopMode = CFStringRef;
+
+
+declare_TCFType!(CFRunLoop, CFRunLoopRef);
+impl_TCFType!(CFRunLoop, CFRunLoopRef, CFRunLoopGetTypeID);
+impl_CFTypeDescription!(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 date::{CFDate, CFAbsoluteTime};
+ use std::mem;
+ use std::os::raw::c_void;
+ use std::sync::mpsc;
+
+ #[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();
+ }
+}
diff --git a/third_party/rust/core-foundation/src/set.rs b/third_party/rust/core-foundation/src/set.rs
new file mode 100644
index 0000000000..eb1d357a03
--- /dev/null
+++ b/third_party/rust/core-foundation/src/set.rs
@@ -0,0 +1,53 @@
+// 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.
+
+pub use core_foundation_sys::set::*;
+use core_foundation_sys::base::{CFTypeRef, CFRelease, kCFAllocatorDefault};
+
+use base::{CFIndexConvertible, TCFType};
+
+use std::os::raw::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
+ }
+ }
+}
diff --git a/third_party/rust/core-foundation/src/string.rs b/third_party/rust/core-foundation/src/string.rs
new file mode 100644
index 0000000000..3f5994bc5a
--- /dev/null
+++ b/third_party/rust/core-foundation/src/string.rs
@@ -0,0 +1,197 @@
+// 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 base::{CFIndexConvertible, TCFType};
+
+use core_foundation_sys::base::{Boolean, CFIndex, CFRange};
+use core_foundation_sys::base::{kCFAllocatorDefault, kCFAllocatorNull};
+use std::borrow::Cow;
+use std::fmt;
+use std::str::{self, FromStr};
+use std::ptr;
+use std::ffi::CStr;
+
+
+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<'a> PartialEq<&'a 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<'a> PartialEq<CFString> for &'a 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);
+}
diff --git a/third_party/rust/core-foundation/src/timezone.rs b/third_party/rust/core-foundation/src/timezone.rs
new file mode 100644
index 0000000000..a8bb2ed1d2
--- /dev/null
+++ b/third_party/rust/core-foundation/src/timezone.rs
@@ -0,0 +1,104 @@
+// 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.
+
+pub use core_foundation_sys::timezone::*;
+use core_foundation_sys::base::kCFAllocatorDefault;
+
+use base::TCFType;
+use date::{CFDate, CFTimeInterval};
+use string::CFString;
+
+#[cfg(feature = "with-chrono")]
+use chrono::{FixedOffset, NaiveDateTime};
+
+
+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())
+ }
+ }
+
+ #[cfg(feature = "with-chrono")]
+ pub fn offset_at_date(&self, date: NaiveDateTime) -> FixedOffset {
+ let date = CFDate::from_naive_utc(date);
+ FixedOffset::east(self.seconds_from_gmt(date) as i32)
+ }
+
+ #[cfg(feature = "with-chrono")]
+ pub fn from_offset(offset: FixedOffset) -> CFTimeZone {
+ CFTimeZone::new(offset.local_minus_utc() as f64)
+ }
+
+ /// 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;
+
+ #[cfg(feature = "with-chrono")]
+ use chrono::{NaiveDateTime, FixedOffset};
+
+ #[test]
+ fn timezone_comparison() {
+ let system = CFTimeZone::system();
+ let default = CFTimeZone::default();
+ assert_eq!(system, default);
+ }
+
+ #[test]
+ #[cfg(feature = "with-chrono")]
+ fn timezone_chrono_conversion() {
+ let offset = FixedOffset::west(28800);
+ let tz = CFTimeZone::from_offset(offset);
+ let converted = tz.offset_at_date(NaiveDateTime::from_timestamp(0, 0));
+ assert_eq!(offset, converted);
+ }
+}
diff --git a/third_party/rust/core-foundation/src/url.rs b/third_party/rust/core-foundation/src/url.rs
new file mode 100644
index 0000000000..064dd7b5e0
--- /dev/null
+++ b/third_party/rust/core-foundation/src/url.rs
@@ -0,0 +1,155 @@
+// 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 base::{TCFType, CFIndex};
+use string::{CFString};
+
+use core_foundation_sys::base::{kCFAllocatorDefault, Boolean};
+use std::fmt;
+use std::ptr;
+use std::path::{Path, PathBuf};
+
+use libc::{c_char, strlen, PATH_MAX};
+
+#[cfg(unix)]
+use std::os::unix::ffi::OsStrExt;
+#[cfg(unix)]
+use std::ffi::OsStr;
+
+
+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.to_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());
+}
diff --git a/third_party/rust/core-foundation/src/uuid.rs b/third_party/rust/core-foundation/src/uuid.rs
new file mode 100644
index 0000000000..6be734dabc
--- /dev/null
+++ b/third_party/rust/core-foundation/src/uuid.rs
@@ -0,0 +1,118 @@
+// 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.
+
+#[cfg(feature = "with-uuid")]
+extern crate uuid;
+
+pub use core_foundation_sys::uuid::*;
+use core_foundation_sys::base::kCFAllocatorDefault;
+
+use base::TCFType;
+
+#[cfg(feature = "with-uuid")]
+use self::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 Into<Uuid> for CFUUID {
+ fn into(self) -> Uuid {
+ let b = unsafe {
+ CFUUIDGetUUIDBytes(self.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).unwrap()
+ }
+}
+
+#[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);
+ }
+}