From d51d228c05cf68df9119423aafb9e6565b34a30f Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Wed, 7 Sep 2016 12:22:06 +0200 Subject: [PATCH 1/2] Rewrite all the bindings in a better way All the FFI functions have fancy types now and use references instead of raw pointers for arguments. Now, a CFRef value represents a refcounted value to be released on Drop, CFShared represents a shared value that can be retained to produce a new CFRef (this will be a useful distinction for mutable types, where a bare T shouldn't be retainable to keep unique ownership). To simplify things and avoid either having wrappers of wrappers of all methods behind traits, I put the safe and thin methods directly on the opaque FFI types. Let's begin the infinite bikeshedding! --- core-foundation-sys/Cargo.toml | 4 +- core-foundation-sys/src/allocator.rs | 148 +++ core-foundation-sys/src/array.rs | 473 +++++++- core-foundation-sys/src/bag.rs | 112 ++ core-foundation-sys/src/base.rs | 290 ++++- core-foundation-sys/src/boolean.rs | 125 ++ core-foundation-sys/src/bundle.rs | 214 +++- core-foundation-sys/src/characterset.rs | 26 + core-foundation-sys/src/data.rs | 188 ++- core-foundation-sys/src/dictionary.rs | 280 ++++- core-foundation-sys/src/error.rs | 105 +- core-foundation-sys/src/lib.rs | 78 +- core-foundation-sys/src/locale.rs | 26 + core-foundation-sys/src/null.rs | 46 + core-foundation-sys/src/number.rs | 236 +++- core-foundation-sys/src/plugin.rs | 26 + core-foundation-sys/src/runloop.rs | 651 +++++++++-- core-foundation-sys/src/set.rs | 200 +++- core-foundation-sys/src/string.rs | 1093 +++++++++++++----- core-foundation-sys/src/sync.rs | 157 +++ core-foundation-sys/src/{date.rs => time.rs} | 7 +- core-foundation-sys/src/url.rs | 764 +++++++++--- core-foundation-sys/src/version.rs | 58 + core-foundation/Cargo.toml | 5 +- core-foundation/src/array.rs | 122 +- core-foundation/src/base.rs | 136 +-- core-foundation/src/boolean.rs | 36 +- core-foundation/src/bundle.rs | 36 +- core-foundation/src/data.rs | 60 +- core-foundation/src/dictionary.rs | 96 +- core-foundation/src/error.rs | 67 +- core-foundation/src/lib.rs | 76 +- core-foundation/src/number.rs | 78 +- core-foundation/src/runloop.rs | 135 +-- core-foundation/src/set.rs | 37 +- core-foundation/src/string.rs | 144 +-- core-foundation/src/time.rs | 10 + core-foundation/src/url.rs | 55 +- 38 files changed, 4558 insertions(+), 1842 deletions(-) create mode 100644 core-foundation-sys/src/allocator.rs create mode 100644 core-foundation-sys/src/bag.rs create mode 100644 core-foundation-sys/src/boolean.rs create mode 100644 core-foundation-sys/src/characterset.rs create mode 100644 core-foundation-sys/src/locale.rs create mode 100644 core-foundation-sys/src/null.rs create mode 100644 core-foundation-sys/src/plugin.rs create mode 100644 core-foundation-sys/src/sync.rs rename core-foundation-sys/src/{date.rs => time.rs} (67%) create mode 100644 core-foundation-sys/src/version.rs create mode 100644 core-foundation/src/time.rs diff --git a/core-foundation-sys/Cargo.toml b/core-foundation-sys/Cargo.toml index ec62c0e..0fc1887 100644 --- a/core-foundation-sys/Cargo.toml +++ b/core-foundation-sys/Cargo.toml @@ -3,11 +3,11 @@ name = "core-foundation-sys" description = "Bindings to Core Foundation for OS X" homepage = "https://github.com/servo/core-foundation-rs" repository = "https://github.com/servo/core-foundation-rs" -version = "0.2.2" +version = "0.3.0" authors = ["The Servo Project Developers"] license = "MIT / Apache-2.0" build = "build.rs" links = "CoreFoundation.framework" [dependencies] -libc = "0.2" +bitflags = "0.7" diff --git a/core-foundation-sys/src/allocator.rs b/core-foundation-sys/src/allocator.rs new file mode 100644 index 0000000..1253c98 --- /dev/null +++ b/core-foundation-sys/src/allocator.rs @@ -0,0 +1,148 @@ +// Copyright 2013-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use base::{CFDowncast, CFIndex, CFObject, CFOptionFlags, CFType, CFTypeID}; +use std::fmt; +use std::os::raw::c_void; +use string::CFString; +use sync::{CFShared, CFRef}; +use version::CFVersion0; + +pub type CFAllocatorRef = CFRef; + +#[repr(C)] +pub struct CFAllocator(CFObject); + +unsafe impl Send for CFAllocator {} +unsafe impl Sync for CFAllocator {} + +unsafe impl CFType for CFAllocator { + #[inline] + fn as_object(&self) -> &CFObject { + &self.0 + } +} + +unsafe impl CFDowncast for CFAllocator { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFAllocatorGetTypeID() } + } +} + +impl CFAllocator { + #[inline] + pub fn null_allocator() -> &'static CFShared { + kCFAllocatorNull.unwrap() + } +} + +impl fmt::Debug for CFAllocator { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + formatter + .debug_tuple("CFAllocator") + .field(&format_args!("{:p}", self)) + .finish() + } +} + +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] +#[repr(C)] +pub struct CFAllocatorContext { + pub version: CFVersion0, + pub info: *mut c_void, + pub retain: Option, + pub release: Option, + pub copyDescription: Option, + pub allocate: CFAllocatorAllocateCallBack, + pub reallocate: Option, + pub deallocate: Option, + pub preferredSize: CFAllocatorPreferredSizeCallBack, +} + +pub type CFAllocatorRetainCallBack = + unsafe extern fn(info: *const c_void) -> *const c_void; + +pub type CFAllocatorReleaseCallBack = + unsafe extern fn(info: *const c_void); + +pub type CFAllocatorCopyDescriptionCallBack = + unsafe extern fn( + info: *const c_void) + -> Option<&'static CFShared>; + +pub type CFAllocatorAllocateCallBack = + unsafe extern fn( + allocSize: CFIndex, hint: CFSizeHint, info: *mut c_void) + -> *mut c_void; + +pub type CFAllocatorReallocateCallBack = + unsafe extern fn( + ptr: *mut c_void, + newsize: CFIndex, + hint: CFSizeHint, + info: *mut c_void) + -> *mut c_void; + +pub type CFAllocatorDeallocateCallBack = + unsafe extern fn(ptr: *mut c_void, info: *mut c_void); + +pub type CFAllocatorPreferredSizeCallBack = + unsafe extern fn( + size: CFIndex, hint: CFSizeHint, info: *mut c_void) -> CFIndex; + +#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)] +#[repr(C)] +pub struct CFSizeHint { flags: CFOptionFlags } + +impl CFSizeHint { + #[inline] + pub fn new() -> Self { + CFSizeHint { flags: 0 } + } +} + +extern { + pub static kCFAllocatorNull: Option<&'static CFShared>; + + pub fn CFAllocatorGetTypeID() -> CFTypeID; + pub fn CFAllocatorSetDefault(allocator: &'static CFAllocator); + pub fn CFAllocatorGetDefault() -> Option<&'static CFShared>; + + pub fn CFAllocatorCreate( + allocator: Option<&'static CFAllocator>, + context: &'static mut CFAllocatorContext) + -> *const CFShared; + + pub fn CFAllocatorAllocate( + allocator: Option<&'static CFAllocator>, + size: CFIndex, + hint: CFSizeHint) + -> *mut c_void; + + pub fn CFAllocatorReallocate( + allocator: Option<&'static CFAllocator>, + ptr: *mut c_void, + newsize: CFIndex, + hint: CFSizeHint) + -> *mut c_void; + + pub fn CFAllocatorDeallocate( + allocator: Option<&'static CFAllocator>, ptr: *mut c_void); + + pub fn CFAllocatorGetPreferredSizeForSize( + allocator: Option<&'static CFAllocator>, + size: CFIndex, + hint: CFSizeHint) + -> CFIndex; + + pub fn CFAllocatorGetContext( + allocator: Option<&'static CFAllocator>, + context: &mut CFAllocatorContext); +} diff --git a/core-foundation-sys/src/array.rs b/core-foundation-sys/src/array.rs index d85f0b7..b54a5d4 100644 --- a/core-foundation-sys/src/array.rs +++ b/core-foundation-sys/src/array.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 ; -/// FIXME(pcwalton): This is wrong. -pub type CFArrayReleaseCallBack = *const u8; +/// Encapsulate array values. +/// +/// Most of the methods on this type are unsafe because it doesn't abstract +/// over the underlying `*const c_void` values passed around in the Core +/// Foundation framework. +#[repr(C)] +pub struct CFArray { obj: CFObject } + +unsafe impl Send for CFArray {} +unsafe impl Sync for CFArray {} + +unsafe impl CFType for CFArray { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +unsafe impl CFDowncast for CFArray { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFArrayGetTypeID() } + } +} + +impl CFArray { + #[inline] + pub fn from_objects(input: &[&CFShared]) -> CFArrayRef { + unsafe { + CFArray::new( + &*(input as *const _ as *const _), Some(&kCFTypeArrayCallBacks)) + } + } + + #[inline] + pub unsafe fn new( + values: &[*const c_void], callbacks: Option<&CFArrayCallBacks>) + -> CFArrayRef { + CFRef::from_retained( + CFArrayCreate( + None, values.as_ptr(), values.len().into_index(), callbacks)) + } + + #[inline] + pub fn duplicate(&self) -> CFArrayRef { + unsafe { CFRef::from_retained(CFArrayCreateCopy(None, self)) } + } + + #[inline] + pub fn len(&self) -> usize { + unsafe { usize::from_index(CFArrayGetCount(self)) } + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + #[inline] + pub unsafe fn count_value(&self, value: *const c_void) -> usize { + self.count_value_in_range(value, 0..self.len()) + } + + #[inline] + pub unsafe fn count_value_in_range( + &self, value: *const c_void, range: Range) + -> usize { + let len = self.len(); + assert!(range.end <= len); + usize::from_index(CFArrayGetCountOfValue(self, range.into(), value)) + } + + pub unsafe fn contains_value(&self, value: *const c_void) -> bool { + self.contains_value_in_range(value, 0..self.len()) + } + + #[inline] + pub unsafe fn contains_value_in_range( + &self, value: *const c_void, range: Range) + -> bool { + CFArrayContainsValue(self, range.into(), value) + } + + #[inline] + pub fn get(&self, index: usize) -> Option<*const c_void> { + if index < self.len() { + Some(unsafe { CFArrayGetValueAtIndex(self, index as i64) }) + } else { + None + } + } + + #[inline] + pub fn values(&self) -> Vec<*const c_void> { + self.values_in_range(0..self.len()) + } -/// FIXME(pcwalton): This is wrong. -pub type CFArrayCopyDescriptionCallBack = *const u8; + #[inline] + pub fn values_in_range(&self, range: Range) -> Vec<*const c_void> { + let len = self.len(); + assert!(range.end <= len); + let mut output = vec![ptr::null(); self.len()]; + unsafe { CFArrayGetValues(self, range.into(), output.as_mut_ptr()) } + output + } + + #[inline] + pub unsafe fn inspect( + &self, + applier: unsafe extern fn(value: *const c_void, context: &mut T), + context: &mut T) { + self.inspect_in_range(applier, context, 0..self.len()) + } + + #[inline] + pub unsafe fn inspect_in_range( + &self, + applier: unsafe extern fn(value: *const c_void, context: &mut T), + context: &mut T, + range: Range) { + let len = self.len(); + assert!(range.end <= len); + CFArrayApplyFunction( + self, + range.into(), + mem::transmute(applier), + &mut *(context as *mut _ as *mut _)); + } + + #[inline] + pub fn iter(&self) -> Iter { + self.into_iter() + } + + #[inline] + pub unsafe fn position(&self, value: *const c_void) -> Option { + self.position_in_range(value, 0..self.len()) + } + + #[inline] + pub unsafe fn position_in_range( + &self, value: *const c_void, range: Range) + -> Option { + let len = self.len(); + assert!(range.end <= len); + let index = CFArrayGetFirstIndexOfValue(self, range.into(), value); + if index < 0 { + None + } else { + Some(usize::from_index(index)) + } + } + + #[inline] + pub unsafe fn rposition(&self, value: *const c_void) -> Option { + self.position_in_range(value, 0..self.len()) + } + + #[inline] + pub unsafe fn rposition_in_range( + &self, value: *const c_void, range: Range) + -> Option { + let len = self.len(); + assert!(range.end <= len); + let index = CFArrayGetLastIndexOfValue(self, range.into(), value); + if index < 0 { + None + } else { + Some(usize::from_index(index)) + } + } + + #[inline] + pub unsafe fn binary_search( + &self, + value: *const c_void, + comparator: + unsafe extern fn( + value1: *const c_void, + value2: *const c_void, + context: &mut T) + -> CFComparisonResult, + context: &mut T) + -> usize { + self.binary_search_in_range(value, comparator, context, 0..self.len()) + } + + #[inline] + pub unsafe fn binary_search_in_range( + &self, + value: *const c_void, + comparator: + unsafe extern fn( + value1: *const c_void, + value2: *const c_void, + context: &mut T) + -> CFComparisonResult, + context: &mut T, + range: Range) + -> usize { + let len = self.len(); + assert!(range.end <= len); + let index = CFArrayBSearchValues( + self, + range.into(), + value, + mem::transmute(comparator), + &mut *(context as *mut _ as *mut _)); + assert!(index >= 0); + usize::from_index(index) + } + + #[inline] + pub fn iter_in_range(&self, range: Range) -> Iter { + let len = self.len(); + assert!(range.start <= len); + assert!(range.end <= len); + Iter { + array: self, + range: range, + } + } +} + +impl fmt::Debug for CFArray { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + formatter + .debug_tuple("CFArray") + .field(&(self as *const _)) + .field(&self.iter()) + .finish() + } +} + +impl<'a, T: CFType> From<&'a [&'a CFShared]> for CFArrayRef { + #[inline] + fn from(input: &'a [&'a CFShared]) -> Self { + CFArray::from_objects(input) + } +} + +impl<'a> From<&'a CFArray> for Vec<*const c_void> { + fn from(input: &'a CFArray) -> Self { + input.values() + } +} -/// FIXME(pcwalton): This is wrong. -pub type CFArrayEqualCallBack = *const u8; +macro_rules! into_iter_impl { + ($name:ident for $type_:ty) => { + into_iter_impl!($name[] for $type_); + }; + ($name:ident<$($lt:tt),*> for $type_:ty) => { + into_iter_impl!($name[$($lt),*] for $type_); + }; + ($name:ident[$($lt:tt),*] for $type_:ty) => { + impl<$($lt),*> IntoIterator for $type_ { + type Item = *const c_void; + type IntoIter = $name<$($lt),*>; + #[inline] + fn into_iter(self) -> $name<$($lt),*> { + let len = self.len(); + $name { + array: self, + range: 0..len, + } + } + } + + #[derive(Clone)] + pub struct $name<$($lt),*> { + array: $type_, + range: Range, + } + + impl<$($lt),*> Iterator for $name<$($lt),*> { + type Item = *const c_void; + + #[inline] + fn next(&mut self) -> Option<*const c_void> { + self.range.next().map(|index| { + self.array.get(index).unwrap() + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.range.size_hint() + } + } + + impl<$($lt),*> DoubleEndedIterator for $name<$($lt),*> { + #[inline] + fn next_back(&mut self) -> Option<*const c_void> { + self.range.next_back().map(|index| { + self.array.get(index).unwrap() + }) + } + } + + impl<$($lt),*> ExactSizeIterator for $name<$($lt),*> { + #[inline] + fn len(&self) -> usize { + self.range.len() + } + } + + impl<$($lt),*> fmt::Debug for $name<$($lt),*> { + fn fmt( + &self, formatter: &mut fmt::Formatter) + -> Result<(), fmt::Error> { + formatter.debug_list().entries(self.clone()).finish() + } + } + }; +} + +into_iter_impl!(Iter<'a> for &'a CFArray); +into_iter_impl!(IntoIter for CFArrayRef); + +#[derive(Default)] #[repr(C)] -#[derive(Clone, Copy)] pub struct CFArrayCallBacks { - pub version: CFIndex, - pub retain: CFArrayRetainCallBack, - pub release: CFArrayReleaseCallBack, - pub copyDescription: CFArrayCopyDescriptionCallBack, - pub equal: CFArrayEqualCallBack, + pub version: CFVersion0, + pub retain: Option, + pub release: Option, + pub copyDescription: Option, + pub equal: Option, } -#[repr(C)] -pub struct __CFArray(c_void); +pub type CFArrayRetainCallBack = + unsafe extern fn(allocator: &CFAllocator, value: *const c_void) + -> *const c_void; + +pub type CFArrayReleaseCallBack = + unsafe extern fn(allocator: &CFAllocator, value: *const c_void); + +pub type CFArrayCopyDescriptionCallBack = + unsafe extern fn( + value: *const c_void) + -> Option<&'static CFShared>; + +pub type CFArrayEqualCallBack = + unsafe extern fn(value1: *const c_void, value2: *const c_void) -> bool; + +pub type CFArrayApplierFunction = + unsafe extern fn(value: *const c_void, context: *mut c_void); + +#[test] +fn test_should_box_and_unbox() { + use base::CFObject; + use number::CFNumber; + use sync::CFShared; + + let arr = CFArray::from_objects(&[ + &CFNumber::from_i64(1), + &CFNumber::from_i64(2), + &CFNumber::from_i64(3), + &CFNumber::from_i64(4), + &CFNumber::from_i64(5), + ]); -pub type CFArrayRef = *const __CFArray; + unsafe { + let mut sum = 0; + + for elem in arr.iter() { + let object = &*(elem as *const CFShared); + let number = object.downcast::().unwrap(); + sum += number.to_i64().unwrap(); + } + + assert!(sum == 15); + + for elem in arr.iter() { + let object = &*(elem as *const CFShared); + let number = object.downcast::().unwrap(); + sum += number.to_i64().unwrap(); + } + + assert!(sum == 30); + } +} extern { - /* - * CFArray.h - */ pub static kCFTypeArrayCallBacks: CFArrayCallBacks; - pub fn CFArrayCreate(allocator: CFAllocatorRef, values: *const *const c_void, - numValues: CFIndex, callBacks: *const CFArrayCallBacks) -> CFArrayRef; - pub fn CFArrayCreateCopy(allocator: CFAllocatorRef , theArray: CFArrayRef) -> CFArrayRef; - - // CFArrayBSearchValues - // CFArrayContainsValue - pub fn CFArrayGetCount(theArray: CFArrayRef) -> CFIndex; - // CFArrayGetCountOfValue - // CFArrayGetFirstIndexOfValue - // CFArrayGetLastIndexOfValue - // CFArrayGetValues - pub fn CFArrayGetValueAtIndex(theArray: CFArrayRef, idx: CFIndex) -> *const c_void; - // CFArrayApplyFunction pub fn CFArrayGetTypeID() -> CFTypeID; + + pub fn CFArrayCreate( + allocator: Option<&'static CFAllocator>, + values: *const *const c_void, + numValues: CFIndex, + callBacks: Option<&CFArrayCallBacks>) + -> *const CFShared; + + pub fn CFArrayCreateCopy( + allocator: Option<&'static CFAllocator>, theArray: &CFArray) + -> *const CFShared; + + pub fn CFArrayGetCount(theArray: &CFArray) -> CFIndex; + + pub fn CFArrayGetCountOfValue( + theArray: &CFArray, range: CFRange, value: *const c_void) + -> CFIndex; + + pub fn CFArrayContainsValue( + theArray: &CFArray, range: CFRange, value: *const c_void) -> bool; + + pub fn CFArrayGetValueAtIndex( + theArray: &CFArray, idx: CFIndex) + -> *const c_void; + + pub fn CFArrayGetValues( + theArray: &CFArray, range: CFRange, values: *mut *const c_void); + + pub fn CFArrayApplyFunction( + theArray: &CFArray, + range: CFRange, + applier: CFArrayApplierFunction, + context: *mut c_void); + + pub fn CFArrayGetFirstIndexOfValue( + theArray: &CFArray, range: CFRange, value: *const c_void) + -> CFIndex; + + pub fn CFArrayGetLastIndexOfValue( + theArray: &CFArray, range: CFRange, value: *const c_void) + -> CFIndex; + + pub fn CFArrayBSearchValues( + theArray: &CFArray, + range: CFRange, + value: *const c_void, + comparator: CFComparatorFunction, + context: *mut c_void) + -> CFIndex; } diff --git a/core-foundation-sys/src/bag.rs b/core-foundation-sys/src/bag.rs new file mode 100644 index 0000000..d853c21 --- /dev/null +++ b/core-foundation-sys/src/bag.rs @@ -0,0 +1,112 @@ +// Copyright 2013-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Binds the `CFBag` type. + +use allocator::CFAllocator; +use base::{CFDowncast, CFIndex, CFHashCode, CFObject, CFType, CFTypeID}; +use std::os::raw::c_void; +use string::CFString; +use sync::{CFRef, CFShared}; + +pub type CFBagRef = CFRef; + +#[repr(C)] +pub struct CFBag { obj: CFObject } + +unsafe impl Send for CFBag {} +unsafe impl Sync for CFBag {} + +unsafe impl CFType for CFBag { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +unsafe impl CFDowncast for CFBag { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFBagGetTypeID() } + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[repr(C)] +pub struct CFBagCallBacks { + version: CFIndex, + retain: Option, + release: Option, + copyDescription: Option, + equal: Option, + hash: Option, +} + +pub type CFBagRetainCallBack = + unsafe extern fn( + allocator: Option<&'static CFAllocator>, value: *const c_void) + -> *const c_void; + +pub type CFBagReleaseCallBack = + unsafe extern fn( + allocator: Option<&'static CFAllocator>, value: *const c_void); + +pub type CFBagCopyDescriptionCallBack = + unsafe extern fn( + value: *const c_void) + -> Option<&'static CFShared>; + +pub type CFBagEqualCallBack = + unsafe extern fn(value1: *const c_void, value2: *const c_void) -> bool; + +pub type CFBagHashCallBack = + unsafe extern fn(value: *const c_void) -> CFHashCode; + +pub type CFBagApplierFunction = + unsafe extern fn(value: *const c_void, context: *mut c_void); + +extern { + pub static kCFTypeBagCallBacks: CFBagCallBacks; + pub static kCFCopyStringBagCallBacks: CFBagCallBacks; + + pub fn CFBagGetTypeID() -> CFTypeID; + + pub fn CFBagCreate( + allocator: Option<&'static CFAllocator>, + values: *const *const c_void, + numValues: CFIndex, + callBacks: Option<&CFBagCallBacks>) + -> *const CFShared; + + pub fn CFBagCreateCopy( + allocator: Option<&'static CFAllocator>, theBag: &CFBag) + -> *const CFShared; + + pub fn CFBagGetCount(theBag: &CFBag) -> CFIndex; + + pub fn CFBagGetCountOfValue( + theBag: &CFBag, value: *const c_void) + -> CFIndex; + + pub fn CFBagContainsValue(theBag: &CFBag, value: *const c_void) -> bool; + pub fn CFBagGetValue(theBag: &CFBag, value: *const c_void) -> *const c_void; + + pub fn CFBagGetValueIfPresent( + theBag: &CFBag, + candidate: *const c_void, + value: &mut *const c_void) + -> bool; + + pub fn CFBagGetValues(theBag: &CFBag, values: *mut *const c_void); + + pub fn CFBagApplyFunction( + theBag: &CFBag, + applier: CFBagApplierFunction, + context: *mut c_void); +} diff --git a/core-foundation-sys/src/base.rs b/core-foundation-sys/src/base.rs index 6cf8cb6..a7a72cf 100644 --- a/core-foundation-sys/src/base.rs +++ b/core-foundation-sys/src/base.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 ; #[repr(C)] -#[derive(Clone, Copy)] +pub struct CFObject { opaque: [c_void; 0] } + +unsafe impl Send for CFObject {} +unsafe impl Sync for CFObject {} + +unsafe impl CFType for CFObject { + #[inline] + fn as_object(&self) -> &CFObject { + self + } +} + +impl CFObject { + /// Returns the type id of this object. + #[inline] + pub fn type_id(&self) -> CFTypeID { + unsafe { CFGetTypeID(self) } + } + + /// Returns the reference count of this object. + #[inline] + pub fn retain_count(&self) -> usize { + unsafe { CFGetRetainCount(self) as usize } + } + + /// Returns the CF hash of this object. + #[inline] + pub fn hash_code(&self) -> CFHashCode { + unsafe { CFHash(self) } + } + + /// Describes the type of this object. + #[inline] + pub fn describe(&self) -> CFStringRef { + unsafe { CFRef::from_retained(CFCopyDescription(self)) } + } + + /// Returns whether this object is an instance of a more specific CF type. + #[inline] + pub fn is(&self) -> bool { + self.type_id() == T::type_id() + } + + /// Downcasts this object to a more specific CF type. + /// + /// Also available as `>::downcast` and `<&CFShared>::downcast`. + #[inline] + pub fn downcast(&self) -> Result<&T, ()> { + if self.is::() { + Ok(unsafe { &*(self as *const _ as *const _) }) + } else { + Err(()) + } + } +} + +impl CFShared { + /// Downcasts this object to a more specific CF type. + #[inline] + pub fn downcast(&self) -> Result<&CFShared, ()> { + (&**self).downcast::().map(|result| { + unsafe { &*(result as *const _ as *const _) } + }) + } +} + +impl CFObjectRef { + /// Downcasts this object to a more specific CF type. + /// + /// If the operation was not possible, `Err(self)` is returned to be + /// able to get the original object back again. + #[inline] + pub fn downcast(self) -> Result, Self> { + if self.is::() { + let result = unsafe { + CFRef::from_retained(&*self as *const _ as *const _) + }; + mem::forget(self); + Ok(result) + } else { + Err(self) + } + } +} + +impl fmt::Debug for CFObject { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + formatter + .debug_tuple("CFObject") + .field(&format_args!("{:p}", self)) + .finish() + } +} + +impl Hash for CFObject { + fn hash(&self, state: &mut H) { + self.hash_code().hash(state) + } +} + +impl PartialEq for CFObject { + fn eq(&self, other: &Self) -> bool { + unsafe { CFEqual(self, other) } + } +} + +/// Represents a Core Foundation type. +pub unsafe trait CFType { + #[inline] + fn as_object(&self) -> &CFObject; +} + +impl CFShared { + #[inline] + pub fn as_shared_object(&self) -> &CFShared { + unsafe { &*(self.as_object() as *const _ as *const _) } + } +} + +pub unsafe trait CFDowncast: CFType { + #[inline] + fn type_id() -> CFTypeID; +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(C)] +pub struct CFTypeID { id: c_ulong } + +impl CFTypeID { + pub fn describe(self) -> CFStringRef { + unsafe { CFRef::from_retained(CFCopyTypeIDDescription(self)) } + } +} + +pub type CFOptionFlags = c_ulong; + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(C)] +pub struct CFHashCode { id: c_ulong } + +pub type CFIndex = i64; + +pub const kCFNotFound: CFIndex = -1; + +pub trait IntoCFIndex { + #[inline] + fn into_index(self) -> CFIndex; +} + +impl IntoCFIndex for usize { + #[inline] + fn into_index(self) -> CFIndex { + assert!(self as u64 <= CFIndex::max_value() as u64); + self as CFIndex + } +} + +pub trait FromCFIndex { + #[inline] + fn from_index(input: CFIndex) -> Self; +} + +impl FromCFIndex for usize { + #[inline] + fn from_index(input: CFIndex) -> Self { + assert!(input >= 0); + assert!(input as u64 <= usize::max_value() as u64); + input as usize + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[repr(i64)] +pub enum CFComparisonResult { + Less = -1, + Equal = 0, + Greater = 1, +} + +impl From for Ordering { + #[inline] + fn from(result: CFComparisonResult) -> Self { + match result { + CFComparisonResult::Less => Ordering::Less, + CFComparisonResult::Equal => Ordering::Equal, + CFComparisonResult::Greater => Ordering::Greater, + } + } +} + +pub type CFComparatorFunction = + unsafe extern fn( + val1: *const c_void, val2: *const c_void, context: *mut c_void) + -> CFComparisonResult; + +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[repr(C)] pub struct CFRange { pub location: CFIndex, - pub length: CFIndex + pub length: CFIndex, } -// for back-compat -impl CFRange { - pub fn init(location: CFIndex, length: CFIndex) -> CFRange { +impl From> for CFRange { + #[inline] + fn from(input: Range) -> Self { + assert!(input.start < input.end); + let location = input.start.into_index(); CFRange { location: location, - length: length, + length: input.end.into_index() - location, + } + } +} + +impl From for Range { + #[inline] + fn from(input: CFRange) -> Self { + let start = usize::from_index(input.location); + Range { + start: start, + end: start.checked_add(usize::from_index(input.length)).unwrap(), } } } extern { - /* - * CFBase.h - */ - - /* CFAllocator Reference */ - // N.B. Many CFAllocator functions and constants are omitted here. - pub static kCFAllocatorDefault: CFAllocatorRef; - pub static kCFAllocatorSystemDefault: CFAllocatorRef; - pub static kCFAllocatorMalloc: CFAllocatorRef; - pub static kCFAllocatorMallocZone: CFAllocatorRef; - pub static kCFAllocatorNull: CFAllocatorRef; - pub static kCFAllocatorUseContext: CFAllocatorRef; - - /* CFNull Reference */ - - pub static kCFNull: CFNullRef; - - /* CFType Reference */ - - //fn CFCopyDescription - //fn CFCopyTypeIDDescription - //fn CFEqual - //fn CFGetAllocator - pub fn CFGetRetainCount(cf: CFTypeRef) -> CFIndex; - pub fn CFGetTypeID(cf: CFTypeRef) -> CFTypeID; - pub fn CFHash(cf: CFTypeRef) -> CFHashCode; - //fn CFMakeCollectable - pub fn CFRelease(cf: CFTypeRef); - pub fn CFRetain(cf: CFTypeRef) -> CFTypeRef; - pub fn CFShow(obj: CFTypeRef); - - /* Base Utilities Reference */ - // N.B. Some things missing here. + pub fn CFGetTypeID(cf: &CFObject) -> CFTypeID; + + pub fn CFCopyTypeIDDescription( + type_id: CFTypeID) + -> *const CFShared; + + pub fn CFRetain(cf: &CFShared) -> *const CFShared; + pub fn CFRelease(cf: *const CFObject); + pub fn CFGetRetainCount(cf: &CFObject) -> CFIndex; + pub fn CFEqual(cf1: &CFObject, cf2: &CFObject) -> bool; + pub fn CFHash(cf: &CFObject) -> CFHashCode; + pub fn CFCopyDescription(cf: &CFObject) -> *const CFShared; + pub fn CFGetAllocator(cf: &CFObject) -> *const CFAllocator; } diff --git a/core-foundation-sys/src/boolean.rs b/core-foundation-sys/src/boolean.rs new file mode 100644 index 0000000..81bffe9 --- /dev/null +++ b/core-foundation-sys/src/boolean.rs @@ -0,0 +1,125 @@ +// Copyright 2013-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Binds the `CFBoolean` type. + +use base::{CFDowncast, CFObject, CFType, CFTypeID}; +use std::cmp::{Eq, PartialEq}; +use std::fmt; +use sync::{CFRef, CFShared}; + +pub type CFBooleanRef = CFRef; + +/// Encapsulates boolean values. +#[repr(C)] +pub struct CFBoolean { obj: CFObject } + +unsafe impl Send for CFBoolean {} +unsafe impl Sync for CFBoolean {} + +unsafe impl CFType for CFBoolean { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +unsafe impl CFDowncast for CFBoolean { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFBooleanGetTypeID() } + } +} + +impl CFBoolean { + /// Returns a static reference to one of the two `CFBoolean` values. + /// + /// Also available as `<&'static CFShared as From>::from`. + #[inline] + pub fn new(input: bool) -> &'static CFShared { + if input { + kCFBooleanTrue.unwrap() + } else { + kCFBooleanFalse.unwrap() + } + } + + /// Returns the raw boolean value of this instance of `CFBoolean`. + /// + /// Also available as `bool::from`. + #[inline] + pub fn to_bool(&self) -> bool { + unsafe { CFBooleanGetValue(self) } + } +} + +impl<'a> From<&'a CFBoolean> for bool { + #[inline] + fn from(input: &'a CFBoolean) -> bool { + input.to_bool() + } +} + +impl From for &'static CFShared { + #[inline] + fn from(input: bool) -> Self { + CFBoolean::new(input) + } +} + +impl fmt::Debug for CFBoolean { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + formatter + .debug_tuple("CFBoolean") + .field(&self.to_bool()) + .finish() + } +} + +impl Default for &'static CFShared { + #[inline] + fn default() -> Self { + kCFBooleanFalse.unwrap() + } +} + +impl Eq for CFBoolean {} + +impl PartialEq for CFBoolean { + #[inline] + fn eq(&self, other: &Self) -> bool { + self as *const _ == other as *const _ + } +} + +#[test] +fn test_conversions() { + let cf_true = CFBoolean::new(true); + assert_eq!(cf_true.to_bool(), true); + + let cf_false = CFBoolean::new(true); + assert_eq!(cf_false.to_bool(), true); +} + +#[test] +fn test_equality() { + assert_eq!(CFBoolean::new(true), CFBoolean::new(true)); + assert_eq!(CFBoolean::new(false), CFBoolean::new(false)); + + assert!(CFBoolean::new(true) != CFBoolean::new(false)); + assert!(CFBoolean::new(false) != CFBoolean::new(true)); +} + +extern { + pub static kCFBooleanTrue: Option<&'static CFShared>; + pub static kCFBooleanFalse: Option<&'static CFShared>; + + pub fn CFBooleanGetTypeID() -> CFTypeID; + pub fn CFBooleanGetValue(boolean: &CFBoolean) -> bool; +} diff --git a/core-foundation-sys/src/bundle.rs b/core-foundation-sys/src/bundle.rs index 51746a6..c2a9e97 100644 --- a/core-foundation-sys/src/bundle.rs +++ b/core-foundation-sys/src/bundle.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 ; #[repr(C)] -pub struct __CFBundle(c_void); +pub struct CFBundle { obj: CFObject } -pub type CFBundleRef = *const __CFBundle; +unsafe impl Send for CFBundle {} +unsafe impl Sync for CFBundle {} + +unsafe impl CFType for CFBundle { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +unsafe impl CFDowncast for CFBundle { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFBundleGetTypeID() } + } +} + +impl CFBundle { + #[inline] + pub fn main_bundle() -> Option<&'static CFShared> { + unsafe { CFBundleGetMainBundle() } + } + + #[inline] + pub fn info_dictionary(&self) -> Option<&CFShared> { + unsafe { CFBundleGetInfoDictionary(self) } + } +} extern { - /* - * CFBundle.h - */ - pub fn CFBundleGetBundleWithIdentifier(bundleID: CFStringRef) -> CFBundleRef; - pub fn CFBundleGetFunctionPointerForName(bundle: CFBundleRef, function_name: CFStringRef) -> *const c_void; - pub fn CFBundleGetMainBundle() -> CFBundleRef; - pub fn CFBundleGetInfoDictionary(bundle: CFBundleRef) -> CFDictionaryRef; + pub fn CFBundleGetMainBundle() -> Option<&'static CFShared>; + + pub fn CFBundleGetBundleWithIdentifier<'a>( + bundleID: &CFString) + -> Option<&'a CFShared>; + + pub fn CFBundleGetAllBundles() -> Option<&'static CFShared>; pub fn CFBundleGetTypeID() -> CFTypeID; + + pub fn CFBundleCreate( + allocator: Option<&'static CFAllocator>, bundleURL: &CFURL) + -> *const CFShared; + + pub fn CFBundleCreateBundlesFromDirectory( + allocator: Option<&'static CFAllocator>, + directoryURL: &CFURL, + bundleType: Option<&CFString>) + -> *const CFShared; + + pub fn CFBundleCopyBundleURL(bundle: &CFBundle) -> *const CFURL; + + pub fn CFBundleGetValueForInfoDictionaryKey( + bundle: &CFBundle, key: &CFString) + -> *const CFShared; + + pub fn CFBundleGetInfoDictionary( + bundle: &CFBundle) + -> Option<&CFShared>; + + pub fn CFBundleGetLocalInfoDictionary( + bundle: &CFBundle) + -> Option<&CFShared>; + + pub fn CFBundleGetPackageInfo( + bundle: &CFBundle, packageType: &mut u32, packageCreator: &mut u32); + + pub fn CFBundleGetIdentifier( + bundle: &CFBundle) + -> Option<&CFShared>; + + pub fn CFBundleGetVersionNumber(bundle: &CFBundle) -> u32; + + pub fn CFBundleCopyInfoDictionaryInDirectory( + bundleURL: &CFURL) + -> *const CFShared; + + pub fn CFBundleGetPackageInfoInDirectory( + bundleURL: &CFURL, packageType: &mut u32, packageCreator: &mut u32) + -> bool; + + pub fn CFBundleCopyResourceURL( + bundle: &CFBundle, + resourceName: &CFString, + resourceType: Option<&CFString>, + subDirName: Option<&CFString>) + -> *const CFShared; + + pub fn CFBundleCopyResourceURLsOfType( + bundle: &CFBundle, + resourceType: &CFString, + subDirName: Option<&CFString>) + -> *const CFShared; + + pub fn CFBundleCopyLocalizedString( + bundle: &CFBundle, + key: &CFShared, + value: Option<&CFShared>, + tableName: &CFString) + -> *const CFShared; + + pub fn CFBundleCopyResourceURLInDirectory( + bundleURL: &CFURL, + resourceName: &CFString, + resourceType: Option<&CFString>, + subDirName: Option<&CFString>) + -> *const CFShared; + + pub fn CFBundleCopyResourceURLsOfTypeInDirectory( + bundleURL: &CFURL, + resourceType: &CFString, + subDirName: Option<&CFString>) + -> *const CFShared; + + pub fn CFBundleCopyBundleLocalizations( + bundle: &CFBundle) + -> *const CFShared; + + pub fn CFBundleCopyPreferredLocalizationsFromArray( + array: &CFArray) + -> *const CFShared; + + pub fn CFBundleCopyLocalizationsForPreferences( + locArray: &CFArray, prefArray: Option<&CFArray>) + -> *const CFShared; + + pub fn CFBundleCopyResourceURLForLocalization( + bundle: &CFBundle, + resourceName: &CFString, + resourceType: &CFString, + subDirName: Option<&CFString>, + localizationName: &CFString) + -> *const CFShared; + + pub fn CFBundleCopyResourceURLsOfTypeForLocalization( + bundle: &CFBundle, + resourceType: &CFString, + subDirName: Option<&CFString>, + localizationName: &CFString) + -> *const CFShared; + + pub fn CFBundleCopyInfoDictionaryForURL(url: &CFURL) -> *const CFDictionary; + + pub fn CFBundleCopyExecutableArchitecturesForURL( + url: &CFURL) + -> *const CFShared; + + pub fn CFBundleCopyExecutableURL( + bundle: &CFBundle) + -> *const CFShared; + + pub fn CFBundleCopyExecutableArchitectures( + bundle: &CFBundle) + -> *const CFShared; + + pub fn CFBundlePreflightExecutable( + bundle: &CFBundle, error: &mut *const CFShared) + -> bool; + + pub fn CFBundleLoadExecutableAndReturnError( + bundle: &CFBundle, error: &mut *const CFShared) + -> bool; + + pub fn CFBundleLoadExecutable(bundle: &CFBundle) -> bool; + pub fn CFBundleIsExecutableLoaded(bundle: &CFBundle) -> bool; + pub fn CFBundleUnloadExecutable(bundle: &CFBundle) -> bool; + + pub fn CFBundleGetFunctionPointerForName( + bundle: &CFBundle, functionName: &CFString) + -> *mut c_void; + + pub fn CFBundleGetFunctionPointersForNames( + bundle: &CFBundle, + functionNames: &CFArray, + ftbl: *mut *mut c_void); + + pub fn CFBundleGetDataPointerForName( + bundle: &CFBundle, symbolName: &CFString) + -> *mut c_void; + + pub fn CFBundleGetDataPointersForNames( + bundle: &CFBundle, + symbolNames: &CFArray, + stbl: *mut *mut c_void); + + pub fn CFBundleCopyAuxiliaryExecutableURL( + bundle: &CFBundle, + executableName: &CFString) + -> *const CFShared; + + pub fn CFBundleGetPlugIn(bundle: &CFBundle) -> Option<&CFShared>; } diff --git a/core-foundation-sys/src/characterset.rs b/core-foundation-sys/src/characterset.rs new file mode 100644 index 0000000..ea1f954 --- /dev/null +++ b/core-foundation-sys/src/characterset.rs @@ -0,0 +1,26 @@ +// Copyright 2013-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use base::{CFObject, CFType}; +use sync::CFRef; + +pub type CFCharacterSetRef = CFRef; + +#[repr(C)] +pub struct CFCharacterSet { obj: CFObject } + +unsafe impl Send for CFCharacterSet {} +unsafe impl Sync for CFCharacterSet {} + +unsafe impl CFType for CFCharacterSet { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} diff --git a/core-foundation-sys/src/data.rs b/core-foundation-sys/src/data.rs index 6a42b2b..5b38f85 100644 --- a/core-foundation-sys/src/data.rs +++ b/core-foundation-sys/src/data.rs @@ -1,22 +1,184 @@ -use libc::c_void; +// Copyright 2013-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. -use base::{CFAllocatorRef, CFTypeID, CFIndex}; +use allocator::CFAllocator; +use base::{CFDowncast, CFIndex, CFObject, CFOptionFlags, CFRange, CFType}; +use base::{CFTypeID, FromCFIndex, IntoCFIndex}; +use std::borrow::Borrow; +use std::fmt; +use std::ops::{Deref, Range}; +use std::slice; +use sync::{CFRef, CFShared}; + +pub type CFDataRef = CFRef; #[repr(C)] -pub struct __CFData(c_void); +pub struct CFData { obj: CFObject } -pub type CFDataRef = *const __CFData; +unsafe impl Send for CFData {} +unsafe impl Sync for CFData {} -extern { - /* - * CFData.h - */ +unsafe impl CFType for CFData { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +unsafe impl CFDowncast for CFData { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFDataGetTypeID() } + } +} + +impl CFData { + #[inline] + pub fn from_slice(input: &[u8]) -> CFDataRef { + unsafe { + CFRef::from_retained( + CFDataCreate( + None, input.as_ptr(), input.len().into_index())) + } + } + + #[inline] + pub fn from_static_slice(input: &'static [u8]) -> CFDataRef { + unsafe { + CFRef::from_retained( + CFDataCreateWithBytesNoCopy( + None, + input.as_ptr(), + input.len().into_index(), + Some(CFAllocator::null_allocator()))) + } + } + + #[inline] + pub fn duplicate(&self) -> CFDataRef { + unsafe { CFRef::from_retained(CFDataCreateCopy(None, self)) } + } + + #[inline] + pub fn len(&self) -> usize { + unsafe { usize::from_index(CFDataGetLength(self)) } + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + #[inline] + pub fn to_slice(&self) -> &[u8] { + unsafe { + let ptr = CFDataGetBytePtr(self); + assert!(!ptr.is_null()); + slice::from_raw_parts(ptr, self.len()) + } + } + + #[inline] + pub fn find( + &self, needle: &CFData, options: CFDataSearchFlags) + -> Option> { + self.find_in_range(needle, options, 0..self.len()) + } + + #[inline] + pub fn find_in_range( + &self, + needle: &CFData, + options: CFDataSearchFlags, + range: Range) + -> Option> { + let len = self.len(); + assert!(range.end <= len); + let result = unsafe { CFDataFind(self, needle, range.into(), options) }; + if result.location < 0 { + None + } else { + Some(result.into()) + } + } +} + +impl fmt::Debug for CFData { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + formatter + .debug_tuple("CFData") + .field(&format_args!("{:p}", self)) + .field(&*self) + .finish() + } +} + +impl Deref for CFData { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + self.to_slice() + } +} - pub fn CFDataCreate(allocator: CFAllocatorRef, - bytes: *const u8, length: CFIndex) -> CFDataRef; - //fn CFDataFind - pub fn CFDataGetBytePtr(theData: CFDataRef) -> *const u8; - pub fn CFDataGetLength(theData: CFDataRef) -> CFIndex; +impl Borrow<[u8]> for CFData { + #[inline] + fn borrow(&self) -> &[u8] { + self.to_slice() + } +} + +impl<'a> From<&'a [u8]> for CFDataRef { + #[inline] + fn from(input: &'a [u8]) -> Self { + CFData::from_slice(input) + } +} +bitflags! { + #[repr(C)] + pub flags CFDataSearchFlags: CFOptionFlags { + const SEARCH_BACKWARDS = 1, + const SEARCH_ANCHORED = 2, + } +} + +extern { pub fn CFDataGetTypeID() -> CFTypeID; + + pub fn CFDataCreate( + allocator: Option<&'static CFAllocator>, + bytes: *const u8, + length: CFIndex) + -> *const CFShared; + + pub fn CFDataCreateWithBytesNoCopy( + allocator: Option<&'static CFAllocator>, + bytes: *const u8, + length: CFIndex, + bytesDeallocator: Option<&'static CFAllocator>) + -> *const CFShared; + + pub fn CFDataCreateCopy( + allocator: Option<&'static CFAllocator>, + theData: &CFData) + -> *const CFShared; + + pub fn CFDataGetLength(theData: &CFData) -> CFIndex; + pub fn CFDataGetBytePtr(theData: &CFData) -> *const u8; + pub fn CFDataGetBytes(theData: &CFData, range: CFRange, buffer: *mut u8); + + pub fn CFDataFind( + theData: &CFData, + dataToFind: &CFData, + searchRange: CFRange, + compareOptions: CFDataSearchFlags) + -> CFRange; } diff --git a/core-foundation-sys/src/dictionary.rs b/core-foundation-sys/src/dictionary.rs index e1d159a..4510b76 100644 --- a/core-foundation-sys/src/dictionary.rs +++ b/core-foundation-sys/src/dictionary.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 ; -pub type CFDictionaryApplierFunction = *const u8; -pub type CFDictionaryCopyDescriptionCallBack = *const u8; -pub type CFDictionaryEqualCallBack = *const u8; -pub type CFDictionaryHashCallBack = *const u8; -pub type CFDictionaryReleaseCallBack = *const u8; -pub type CFDictionaryRetainCallBack = *const u8; +#[repr(C)] +pub struct CFDictionary { obj: CFObject } + +unsafe impl Send for CFDictionary {} +unsafe impl Sync for CFDictionary {} + +unsafe impl CFType for CFDictionary { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +unsafe impl CFDowncast for CFDictionary { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFDictionaryGetTypeID() } + } +} + +impl CFDictionary { + #[inline] + pub fn from_objects( + keys: &[&CFShared], + values: &[&CFShared]) + -> CFDictionaryRef + where K: CFType, V: CFType + { + unsafe { + CFDictionary::new( + &*(keys as *const _ as *const _), + &*(values as *const _ as *const _), + Some(&kCFTypeDictionaryKeyCallBacks), + Some(&kCFTypeDictionaryValueCallBacks)) + } + } + + #[inline] + pub fn from_duplicated_strings_and_objects( + keys: &[&CFShared], + values: &[&CFShared]) + -> CFDictionaryRef + where V: CFType + { + unsafe { + CFDictionary::new( + &*(keys as *const _ as *const _), + &*(values as *const _ as *const _), + Some(&kCFCopyStringDictionaryKeyCallBacks), + Some(&kCFTypeDictionaryValueCallBacks)) + } + } + + #[inline] + pub unsafe fn new( + keys: &[*const c_void], + values: &[*const c_void], + key_callbacks: Option<&CFDictionaryKeyCallBacks>, + value_callbacks: Option<&CFDictionaryValueCallBacks>) + -> CFDictionaryRef { + assert!(keys.len() == values.len()); + CFRef::from_retained( + CFDictionaryCreate( + None, + keys.as_ptr(), + values.as_ptr(), + keys.len().into_index(), + key_callbacks, + value_callbacks)) + } + + #[inline] + pub fn duplicate(&self) -> CFDictionaryRef { + unsafe { + CFRef::from_retained(CFDictionaryCreateCopy(None, self)) + } + } + + #[inline] + pub fn len(&self) -> usize { + unsafe { usize::from_index(CFDictionaryGetCount(self)) } + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + #[inline] + pub unsafe fn count_key(&self, key: *const c_void) -> usize { + usize::from_index(CFDictionaryGetCountOfKey(self, key)) + } + + #[inline] + pub unsafe fn count_value(&self, value: *const c_void) -> usize { + usize::from_index(CFDictionaryGetCountOfValue(self, value)) + } + + #[inline] + pub unsafe fn contains_key(&self, key: *const c_void) -> bool { + CFDictionaryContainsKey(self, key) + } + + #[inline] + pub unsafe fn contains_value(&self, value: *const c_void) -> bool { + CFDictionaryContainsValue(self, value) + } + + #[inline] + pub unsafe fn get(&self, key: *const c_void) -> Option<*const c_void> { + let mut value = ptr::null(); + if CFDictionaryGetValueIfPresent(self, key, &mut value) { + Some(value) + } else { + None + } + } + + #[inline] + pub unsafe fn inspect( + &self, + applier: + unsafe extern fn( + key: *const c_void, value: *const c_void, context: &mut T), + context: &mut T) { + CFDictionaryApplyFunction( + self, mem::transmute(applier), &mut *(context as *mut _ as *mut _)); + } +} -#[allow(dead_code)] +impl fmt::Debug for CFDictionary { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + formatter + .debug_tuple("CFDictionary") + .field(&format_args!("{:p}", self)) + .field(&self.len()) + .finish() + } +} + +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[repr(C)] -#[derive(Clone, Copy)] pub struct CFDictionaryKeyCallBacks { - pub version: CFIndex, - pub retain: CFDictionaryRetainCallBack, - pub release: CFDictionaryReleaseCallBack, - pub copyDescription: CFDictionaryCopyDescriptionCallBack, - pub equal: CFDictionaryEqualCallBack, - pub hash: CFDictionaryHashCallBack + version: CFVersion0, + retain: Option, + release: Option, + copyDescription: Option, + equal: Option, + hash: Option, } -#[allow(dead_code)] +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[repr(C)] -#[derive(Clone, Copy)] pub struct CFDictionaryValueCallBacks { - pub version: CFIndex, - pub retain: CFDictionaryRetainCallBack, - pub release: CFDictionaryReleaseCallBack, - pub copyDescription: CFDictionaryCopyDescriptionCallBack, - pub equal: CFDictionaryEqualCallBack + pub version: CFVersion0, + pub retain: Option, + pub release: Option, + pub copyDescription: Option, + pub equal: Option, } -#[repr(C)] -pub struct __CFDictionary(c_void); +pub type CFDictionaryRetainCallBack = + unsafe extern fn( + allocator: Option<&'static CFAllocator>, value: *const c_void) + -> *const c_void; -pub type CFDictionaryRef = *const __CFDictionary; +pub type CFDictionaryReleaseCallBack = + unsafe extern fn( + allocator: Option<&'static CFAllocator>, value: *const c_void); -extern { - /* - * CFDictionary.h - */ +pub type CFDictionaryCopyDescriptionCallBack = + unsafe extern fn( + value: *const c_void) + -> Option<&'static CFShared>; + +pub type CFDictionaryEqualCallBack = + unsafe extern fn(value1: *const c_void, value2: *const c_void) -> bool; +pub type CFDictionaryHashCallBack = + unsafe extern fn(value: *const c_void) -> CFHashCode; + +pub type CFDictionaryApplierFunction = + unsafe extern fn( + key: *const c_void, value: *const c_void, context: *mut c_void); + +extern { pub static kCFTypeDictionaryKeyCallBacks: CFDictionaryKeyCallBacks; + pub static kCFCopyStringDictionaryKeyCallBacks: CFDictionaryKeyCallBacks; pub static kCFTypeDictionaryValueCallBacks: CFDictionaryValueCallBacks; - pub fn CFDictionaryContainsKey(theDict: CFDictionaryRef, key: *const c_void) -> Boolean; - pub fn CFDictionaryCreate(allocator: CFAllocatorRef, keys: *const *const c_void, values: *const *const c_void, - numValues: CFIndex, keyCallBacks: *const CFDictionaryKeyCallBacks, - valueCallBacks: *const CFDictionaryValueCallBacks) - -> CFDictionaryRef; - pub fn CFDictionaryGetCount(theDict: CFDictionaryRef) -> CFIndex; pub fn CFDictionaryGetTypeID() -> CFTypeID; - pub fn CFDictionaryGetValueIfPresent(theDict: CFDictionaryRef, key: *const c_void, value: *mut *const c_void) - -> Boolean; - pub fn CFDictionarySetValue(theDict: CFDictionaryRef, - key: *const c_void, - value: *const c_void); + + pub fn CFDictionaryCreate( + allocator: Option<&'static CFAllocator>, + keys: *const *const c_void, + values: *const *const c_void, + numValues: CFIndex, + keyCallBacks: Option<&CFDictionaryKeyCallBacks>, + valueCallBacks: Option<&CFDictionaryValueCallBacks>) + -> *const CFShared; + + pub fn CFDictionaryCreateCopy( + allocator: Option<&'static CFAllocator>, theDict: &CFDictionary) + -> *const CFShared; + + pub fn CFDictionaryGetCount(theDict: &CFDictionary) -> CFIndex; + + pub fn CFDictionaryGetCountOfKey( + theDict: &CFDictionary, key: *const c_void) + -> CFIndex; + + pub fn CFDictionaryGetCountOfValue( + theDict: &CFDictionary, value: *const c_void) + -> CFIndex; + + pub fn CFDictionaryContainsKey( + theDict: &CFDictionary, key: *const c_void) + -> bool; + + pub fn CFDictionaryContainsValue( + theDict: &CFDictionary, value: *const c_void) + -> bool; + + pub fn CFDictionaryGetValue( + theDict: &CFDictionary, key: *const c_void) + -> *const c_void; + + pub fn CFDictionaryGetValueIfPresent( + theDict: &CFDictionary, + key: *const c_void, + value: &mut *const c_void) + -> bool; + + pub fn CFDictionaryGetKeysAndValues( + theDict: &CFDictionary, + keys: *mut *const c_void, + values: *mut *const c_void); + + pub fn CFDictionaryApplyFunction( + theDict: &CFDictionary, + applier: CFDictionaryApplierFunction, + context: *mut c_void); } diff --git a/core-foundation-sys/src/error.rs b/core-foundation-sys/src/error.rs index 68097da..1a7870e 100644 --- a/core-foundation-sys/src/error.rs +++ b/core-foundation-sys/src/error.rs @@ -7,26 +7,105 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use libc::c_void; +use allocator::CFAllocator; +use base::{CFDowncast, CFIndex, CFObject, CFType, CFTypeID}; +use dictionary::{CFDictionary, CFDictionaryRef}; +use std::os::raw::c_void; +use string::{CFString, CFStringRef}; +use sync::{CFRef, CFShared}; -use base::{CFTypeID, CFIndex}; -use string::CFStringRef; +pub type CFErrorRef = CFRef; #[repr(C)] -pub struct __CFError(c_void); +pub struct CFError { obj: CFObject } -pub type CFErrorRef = *mut __CFError; +unsafe impl Send for CFError {} +unsafe impl Sync for CFError {} -extern "C" { +unsafe impl CFType for CFError { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +unsafe impl CFDowncast for CFError { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFErrorGetTypeID() } + } +} + +impl CFError { + #[inline] + pub fn new( + domain: &CFString, code: CFIndex, user_info: Option<&CFDictionary>) + -> CFErrorRef { + unsafe { + CFRef::from_retained( + CFErrorCreate(None, domain, code, user_info)) + } + } + + #[inline] + pub fn domain(&self) -> &CFShared { + unsafe { CFErrorGetDomain(self).unwrap() } + } + + #[inline] + pub fn code(&self) -> CFIndex { + unsafe { CFErrorGetCode(self) } + } + + #[inline] + pub fn user_info(&self) -> CFDictionaryRef { + unsafe { CFRef::from_retained(CFErrorCopyUserInfo(self)) } + } + + #[inline] + pub fn description(&self) -> CFStringRef { + unsafe { CFRef::from_retained(CFErrorCopyDescription(self)) } + } + + #[inline] + pub fn failure_reason(&self) -> Option { + unsafe { CFRef::try_from_retained(CFErrorCopyFailureReason(self)).ok() } + } + + #[inline] + pub fn recovery_suggestion(&self) -> Option { + unsafe { + CFRef::try_from_retained(CFErrorCopyRecoverySuggestion(self)).ok() + } + } +} + +extern { pub fn CFErrorGetTypeID() -> CFTypeID; - pub static kCFErrorDomainPOSIX: CFStringRef; - pub static kCFErrorDomainOSStatus: CFStringRef; - pub static kCFErrorDomainMach: CFStringRef; - pub static kCFErrorDomainCocoa: CFStringRef; + pub fn CFErrorCreate( + allocator: Option<&'static CFAllocator>, + domain: &CFString, + code: CFIndex, + userInfo: Option<&CFDictionary>) + -> *const CFShared; + + pub fn CFErrorCreateWithUserInfoKeysAndValues( + allocator: Option<&'static CFAllocator>, + domain: &CFShared, + code: CFIndex, + userInfoKeys: *const *const c_void, + userInfoValues: *const *const c_void, + numUserInfoValues: CFIndex) + -> *const CFShared; - pub fn CFErrorGetDomain(err: CFErrorRef) -> CFStringRef; - pub fn CFErrorGetCode(err: CFErrorRef) -> CFIndex; + pub fn CFErrorGetDomain(err: &CFError) -> Option<&CFShared>; + pub fn CFErrorGetCode(err: &CFError) -> CFIndex; + pub fn CFErrorCopyUserInfo(err: &CFError) -> *const CFShared; + pub fn CFErrorCopyDescription(err: &CFError) -> *const CFShared; + pub fn CFErrorCopyFailureReason(err: &CFError) -> *const CFShared; - pub fn CFErrorCopyDescription(err: CFErrorRef) -> CFStringRef; + pub fn CFErrorCopyRecoverySuggestion( + err: &CFError) + -> *const CFShared; } diff --git a/core-foundation-sys/src/lib.rs b/core-foundation-sys/src/lib.rs index 584d825..51398df 100644 --- a/core-foundation-sys/src/lib.rs +++ b/core-foundation-sys/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals, improper_ctypes)] -extern crate libc; +//! Bindings to the Core Foundation framework. +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] + +#[macro_use] +extern crate bitflags; + +pub mod allocator; pub mod array; +pub mod bag; pub mod base; +pub mod boolean; pub mod bundle; +pub mod characterset; pub mod data; -pub mod date; pub mod dictionary; pub mod error; +pub mod locale; +pub mod null; pub mod number; +pub mod plugin; pub mod runloop; pub mod set; pub mod string; +pub mod sync; +pub mod time; pub mod url; +pub mod version; + +pub use allocator::{CFAllocator, CFAllocatorRef}; +pub use array::{CFArray, CFArrayRef}; +pub use bag::{CFBag, CFBagRef}; +pub use base::{CFObject, CFObjectRef, CFDowncast, CFType, CFTypeID}; +pub use boolean::{CFBoolean, CFBooleanRef}; +pub use bundle::{CFBundle, CFBundleRef}; +pub use characterset::{CFCharacterSet, CFCharacterSetRef}; +pub use data::{CFData, CFDataRef}; +pub use dictionary::{CFDictionary, CFDictionaryRef}; +pub use error::{CFError, CFErrorRef}; +pub use locale::{CFLocale, CFLocaleRef}; +pub use null::{CFNull, CFNullRef}; +pub use number::{CFNumber, CFNumberRef}; +pub use plugin::{CFPlugIn, CFPlugInRef}; +pub use runloop::{CFRunLoop, CFRunLoopRef}; +pub use runloop::{CFRunLoopObserver, CFRunLoopObserverRef}; +pub use runloop::{CFRunLoopSource, CFRunLoopSourceRef}; +pub use runloop::{CFRunLoopTimer, CFRunLoopTimerRef}; +pub use set::{CFSet, CFSetRef}; +pub use string::{CFString, CFStringCompareFlags}; +pub use sync::{CFRef, CFShared}; +pub use time::{CFAbsoluteTime, CFTimeInterval}; +pub use url::{CFURL, CFURLRef}; + +#[cfg(test)] +mod test { + #[test] + fn test_stuff() { + use boolean::CFBoolean; + use number::CFNumber; + use dictionary::CFDictionary; + use string::CFString; + + let bar = CFString::from_static_str("Bar"); + let baz = CFString::from_static_str("Baz"); + let boo = CFString::from_static_str("Boo"); + let foo = CFString::from_static_str("Foo"); + let tru = CFBoolean::new(true); + let n42 = CFNumber::from_i64(42); + + let keys = &[ + bar.as_shared_object(), + baz.as_shared_object(), + foo.as_shared_object(), + ]; + + let values = &[ + boo.as_shared_object(), + tru.as_shared_object(), + n42.as_shared_object(), + ]; + + let _d = CFDictionary::from_objects(keys, values); + } +} diff --git a/core-foundation-sys/src/locale.rs b/core-foundation-sys/src/locale.rs new file mode 100644 index 0000000..53eaf6c --- /dev/null +++ b/core-foundation-sys/src/locale.rs @@ -0,0 +1,26 @@ +// Copyright 2013-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use base::{CFObject, CFType}; +use sync::CFRef; + +pub type CFLocaleRef = CFRef; + +#[repr(C)] +pub struct CFLocale { obj: CFObject } + +unsafe impl Send for CFLocale {} +unsafe impl Sync for CFLocale {} + +unsafe impl CFType for CFLocale { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} diff --git a/core-foundation-sys/src/null.rs b/core-foundation-sys/src/null.rs new file mode 100644 index 0000000..ded1c74 --- /dev/null +++ b/core-foundation-sys/src/null.rs @@ -0,0 +1,46 @@ +// Copyright 2013-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use base::{CFDowncast, CFObject, CFType, CFTypeID}; +use sync::{CFRef, CFShared}; + +pub type CFNullRef = CFRef; + +#[repr(C)] +pub struct CFNull { obj: CFObject } + +unsafe impl Send for CFNull {} +unsafe impl Sync for CFNull {} + +unsafe impl CFType for CFNull { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +unsafe impl CFDowncast for CFNull { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFNullGetTypeID() } + } +} + +impl CFNull { + #[inline] + pub fn null() -> &'static CFShared { + kCFNull.unwrap() + } +} + +extern { + pub fn CFNullGetTypeID() -> CFTypeID; + + pub static kCFNull: Option<&'static CFShared>; +} diff --git a/core-foundation-sys/src/number.rs b/core-foundation-sys/src/number.rs index 05758f3..e43a5b4 100644 --- a/core-foundation-sys/src/number.rs +++ b/core-foundation-sys/src/number.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 ; + +/// Encapsulates C scalar numeric types. #[repr(C)] -pub struct __CFBoolean(c_void); - -pub type CFBooleanRef = *const __CFBoolean; - -pub type CFNumberType = u32; - -// members of enum CFNumberType -// static kCFNumberSInt8Type: CFNumberType = 1; -// static kCFNumberSInt16Type: CFNumberType = 2; -pub static kCFNumberSInt32Type: CFNumberType = 3; -pub static kCFNumberSInt64Type: CFNumberType = 4; -// static kCFNumberFloat32Type: CFNumberType = 5; -pub static kCFNumberFloat64Type: CFNumberType = 6; -// static kCFNumberCharType: CFNumberType = 7; -// static kCFNumberShortType: CFNumberType = 8; -// static kCFNumberIntType: CFNumberType = 9; -// static kCFNumberLongType: CFNumberType = 10; -// static kCFNumberLongLongType: CFNumberType = 11; -// static kCFNumberFloatType: CFNumberType = 12; -// static kCFNumberDoubleType: CFNumberType = 13; -// static kCFNumberCFIndexType: CFNumberType = 14; -// static kCFNumberNSIntegerType: CFNumberType = 15; -// static kCFNumberCGFloatType: CFNumberType = 16; -// static kCFNumberMaxType: CFNumberType = 16; +pub struct CFNumber { obj: CFObject } + +unsafe impl Send for CFNumber {} +unsafe impl Sync for CFNumber {} + +unsafe impl CFType for CFNumber { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +unsafe impl CFDowncast for CFNumber { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFNumberGetTypeID() } + } +} + +impl CFNumber { + /// Returns the number of bytes used by this number to store its value. + #[inline] + pub fn number_type(&self) -> CFNumberType { + unsafe { CFNumberGetType(self) } + } + + /// Returns the type used by this number to store its value. + #[inline] + pub fn byte_size(&self) -> usize { + unsafe { usize::from_index(CFNumberGetByteSize(self)) } + } + + /// Returns whether this number represents a floating-point value. + #[inline] + pub fn is_float(&self) -> bool { + unsafe { CFNumberIsFloatType(self) } + } +} + +pub trait FromCFNumber: Sized { + #[inline] + fn from_number(number: &CFNumber) -> Result; +} + +macro_rules! number_conversion { + ($type_:ident, $number_type:ident, $from:ident, $to:ident, $test:ident) => { + impl CFNumber { + /// Creates a new `CFNumberRef` from a primitive type. + /// + /// Also available as `CFNumberRef::from`. + #[inline] + pub fn $from(input: $type_) -> CFNumberRef { + unsafe { + CFRef::from_retained( + CFNumberCreate( + None, + CFNumberType::$number_type, + &input as *const _ as *const _)) + } + } + + /// Converts this number to a primitive type or returns an error. + /// + /// Also available as `FromCFNumber::from_number`. + #[inline] + pub fn $to(&self) -> Result<$type_, ()> { + let mut value = $type_::default(); + let success = unsafe { + CFNumberGetValue( + self, + CFNumberType::$number_type, + &mut value as *mut _ as *mut _) + }; + if success { + Ok(value) + } else { + Err(()) + } + } + } + + impl FromCFNumber for $type_ { + #[inline] + fn from_number(input: &CFNumber) -> Result { + input.$to() + } + } + + impl From<$type_> for CFNumberRef { + #[inline] + fn from(input: $type_) -> Self { + CFNumber::$from(input) + } + } + } +} +number_conversion!(i8, SInt8, from_i8, to_i8, test_i8); +number_conversion!(i16, SInt16, from_i16, to_i16, test_i16); +number_conversion!(i32, SInt32, from_i32, to_i32, test_i32); +number_conversion!(i64, SInt64, from_i64, to_i64, test_i64); +number_conversion!(f32, Float32, from_f32, to_f32, test_f32); +number_conversion!(f64, Float64, from_f64, to_f64, test_f64); + +impl Eq for CFNumber {} + +impl PartialEq for CFNumber { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.cmp(other) == Ordering::Equal + } +} + +impl Ord for CFNumber { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + unsafe { + let context = CFNumberCompareContext::default(); + CFNumberCompare(self, other, context).into() + } + } +} + +impl PartialOrd for CFNumber { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +#[repr(u64)] +pub enum CFNumberType { + SInt8 = 1, + SInt16 = 2, + SInt32 = 3, + SInt64 = 4, + Float32 = 5, + Float64 = 6, + Char = 7, + Short = 8, + Int = 9, + Long = 10, + LongLong = 11, + Float = 12, + Double = 13, + CFIndex = 14, + NSInteger = 15, + CGFloat = 16, +} + +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(C)] -pub struct __CFNumber; +pub struct CFNumberCompareContext { cx: usize } + +impl CFNumberCompareContext { + #[inline] + pub fn new() -> Self { + CFNumberCompareContext { cx: 0 } + } +} -pub type CFNumberRef = *const __CFNumber; +impl Default for CFNumberCompareContext { + #[inline] + fn default() -> Self { + CFNumberCompareContext::new() + } +} extern { - /* - * CFNumber.h - */ - pub static kCFBooleanTrue: CFBooleanRef; - pub static kCFBooleanFalse: CFBooleanRef; - - pub fn CFBooleanGetTypeID() -> CFTypeID; - pub fn CFNumberCreate(allocator: CFAllocatorRef, theType: CFNumberType, valuePtr: *const c_void) - -> CFNumberRef; - //fn CFNumberGetByteSize - pub fn CFNumberGetValue(number: CFNumberRef, theType: CFNumberType, valuePtr: *mut c_void) -> bool; - //fn CFNumberCompare pub fn CFNumberGetTypeID() -> CFTypeID; + + pub fn CFNumberCreate( + allocator: Option<&'static CFAllocator>, + theType: CFNumberType, + valuePtr: *const c_void) + -> *const CFShared; + + pub fn CFNumberGetType(number: &CFNumber) -> CFNumberType; + pub fn CFNumberGetByteSize(number: &CFNumber) -> CFIndex; + pub fn CFNumberIsFloatType(number: &CFNumber) -> bool; + + pub fn CFNumberGetValue( + number: &CFNumber, theType: CFNumberType, valuePtr: *mut c_void) + -> bool; + + pub fn CFNumberCompare( + number: &CFNumber, + otherNumber: &CFNumber, + context: CFNumberCompareContext) + -> CFComparisonResult; } diff --git a/core-foundation-sys/src/plugin.rs b/core-foundation-sys/src/plugin.rs new file mode 100644 index 0000000..d97c623 --- /dev/null +++ b/core-foundation-sys/src/plugin.rs @@ -0,0 +1,26 @@ +// Copyright 2013-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use base::{CFObject, CFType}; +use sync::CFRef; + +pub type CFPlugInRef = CFRef; + +#[repr(C)] +pub struct CFPlugIn { obj: CFObject } + +unsafe impl Send for CFPlugIn {} +unsafe impl Sync for CFPlugIn {} + +unsafe impl CFType for CFPlugIn { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} diff --git a/core-foundation-sys/src/runloop.rs b/core-foundation-sys/src/runloop.rs index 86414a5..f0f1123 100644 --- a/core-foundation-sys/src/runloop.rs +++ b/core-foundation-sys/src/runloop.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 ; #[repr(C)] -pub struct __CFRunLoop(c_void); +pub struct CFRunLoop { obj: CFObject } -pub type CFRunLoopRef = *const __CFRunLoop; +unsafe impl Send for CFRunLoop {} +unsafe impl Sync for CFRunLoop {} -#[repr(C)] -pub struct __CFRunLoopSource(c_void); +unsafe impl CFType for CFRunLoop { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +unsafe impl CFDowncast for CFRunLoop { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFRunLoopGetTypeID() } + } +} + +impl CFRunLoop { + #[inline] + pub fn current() -> CFRunLoopRef { + unsafe { (&*CFRunLoopGetCurrent()).retain() } + } + + #[inline] + pub fn main() -> CFRunLoopRef { + unsafe { (&*CFRunLoopGetMain()).retain() } + } + + #[inline] + pub fn current_mode(&self) -> Option { + unsafe { CFRef::try_from_retained(CFRunLoopCopyCurrentMode(self)).ok() } + } + + #[inline] + pub fn next_timer_fire_date(&self, mode: &CFString) -> CFAbsoluteTime { + unsafe { CFRunLoopGetNextTimerFireDate(self, mode) } + } + + #[inline] + pub fn run() { + unsafe { CFRunLoopRun() } + } + + #[inline] + pub fn run_in_mode( + mode: &CFString, + seconds: CFTimeInterval, + return_after_source_handled: bool) + -> CFRunLoopRunResult { + unsafe { + CFRunLoopRunInMode(mode, seconds, return_after_source_handled) + } + } + + #[inline] + pub fn is_waiting(&self) -> bool { + unsafe { CFRunLoopIsWaiting(self) } + } + + #[inline] + pub fn wakeup(&self) { + unsafe { CFRunLoopWakeUp(self) } + } + + #[inline] + pub fn stop(&self) { + unsafe { CFRunLoopStop(self) } + } + + #[inline] + pub fn contains_source( + &self, source: &CFRunLoopSource, mode: &CFString) + -> bool { + unsafe { CFRunLoopContainsSource(self, source, mode) } + } -pub type CFRunLoopSourceRef = *const __CFRunLoopSource; + #[inline] + pub fn add_source(&self, source: &CFRunLoopSource, mode: &CFString) { + unsafe { CFRunLoopAddSource(self, source, mode) } + } + + #[inline] + pub fn remove_source(&self, source: &CFRunLoopSource, mode: &CFString) { + unsafe { CFRunLoopRemoveSource(self, source, mode) } + } + + #[inline] + pub fn contains_observer( + &self, observer: &CFRunLoopObserver, mode: &CFString) + -> bool { + unsafe { CFRunLoopContainsObserver(self, observer, mode) } + } + + #[inline] + pub fn add_observer(&self, observer: &CFRunLoopObserver, mode: &CFString) { + unsafe { CFRunLoopAddObserver(self, observer, mode) } + } + + #[inline] + pub fn remove_observer( + &self, observer: &CFRunLoopObserver, mode: &CFString) { + unsafe { CFRunLoopRemoveObserver(self, observer, mode) } + } + + #[inline] + pub fn contains_timer( + &self, timer: &CFRunLoopTimer, mode: &CFString) + -> bool { + unsafe { CFRunLoopContainsTimer(self, timer, mode) } + } + + #[inline] + pub fn add_timer(&self, timer: &CFRunLoopTimer, mode: &CFString) { + unsafe { CFRunLoopAddTimer(self, timer, mode) } + } + + #[inline] + pub fn remove_timer(&self, timer: &CFRunLoopTimer, mode: &CFString) { + unsafe { CFRunLoopRemoveTimer(self, timer, mode) } + } +} + +#[repr(i32)] +pub enum CFRunLoopRunResult { + Finished = 1, + Stopped = 2, + TimedOut = 3, + HandledSource = 4, +} + +pub type CFRunLoopSourceRef = CFRef; #[repr(C)] -pub struct __CFRunLoopObserver(c_void); - -pub type CFRunLoopObserverRef = *const __CFRunLoopObserver; - -// Reasons for CFRunLoopRunInMode() to Return -pub const kCFRunLoopRunFinished: i32 = 1; -pub const kCFRunLoopRunStopped: i32 = 2; -pub const kCFRunLoopRunTimedOut: i32 = 3; -pub const kCFRunLoopRunHandledSource: i32 = 4; - -// Run Loop Observer Activities -//typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) { -pub type CFRunLoopActivity = CFOptionFlags; -pub const kCFRunLoopEntry: CFOptionFlags = 1 << 0; -pub const kCFRunLoopBeforeTimers: CFOptionFlags = 1 << 1; -pub const kCFRunLoopBeforeSources: CFOptionFlags = 1 << 2; -pub const kCFRunLoopBeforeWaiting: CFOptionFlags = 1 << 5; -pub const kCFRunLoopAfterWaiting: CFOptionFlags = 1 << 6; -pub const kCFRunLoopExit: CFOptionFlags = 1 << 7; -pub const kCFRunLoopAllActivities: CFOptionFlags = 0x0FFFFFFF; +pub struct CFRunLoopSource { obj: CFObject } + +unsafe impl Send for CFRunLoopSource {} +unsafe impl Sync for CFRunLoopSource {} + +unsafe impl CFType for CFRunLoopSource { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +unsafe impl CFDowncast for CFRunLoopSource { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFRunLoopSourceGetTypeID() } + } +} + +impl CFRunLoopSource { + #[inline] + pub fn order(&self) -> CFIndex { + unsafe { CFRunLoopSourceGetOrder(self) } + } + + #[inline] + pub fn invalidate(&self) { + unsafe { CFRunLoopSourceInvalidate(self) } + } + + #[inline] + pub fn is_valid(&self) -> bool { + unsafe { CFRunLoopSourceIsValid(self) } + } + + #[inline] + pub fn signal(&self) { + unsafe { CFRunLoopSourceSignal(self) } + } +} #[repr(C)] pub struct CFRunLoopSourceContext { - pub version: CFIndex, - pub info: *mut c_void, - pub retain: extern "C" fn (info: *const c_void) -> *const c_void, - pub release: extern "C" fn (info: *const c_void), - pub copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef, - pub equal: extern "C" fn (info1: *const c_void, info2: *const c_void) -> Boolean, - pub hash: extern "C" fn (info: *const c_void) -> CFHashCode, - pub schedule: extern "C" fn (info: *const c_void, rl: CFRunLoopRef, mode: CFStringRef), - pub cancel: extern "C" fn (info: *const c_void, rl: CFRunLoopRef, mode: CFStringRef), - pub perform: extern "C" fn (info: *const c_void), + version: CFVersion0, + info: *mut c_void, + retain: Option, + release: Option, + copyDescription: Option, + equal: Option, + hash: Option, + schedule: Option, + cancel: Option, + perform: CFRunLoopPerformCallBack, } +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(C)] pub struct CFRunLoopSourceContext1 { - pub version: CFIndex, - pub info: *mut c_void, - pub retain: extern "C" fn (info: *const c_void) -> *const c_void, - pub release: extern "C" fn (info: *const c_void), - pub copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef, - pub equal: extern "C" fn (info1: *const c_void, info2: *const c_void) -> Boolean, - pub hash: extern "C" fn (info: *const c_void) -> CFHashCode, - // note that the following two fields are platform dependent in the C header, the ones here are for OS X - pub getPort: extern "C" fn (info: *mut c_void) -> mach_port_t, - pub perform: extern "C" fn (msg: *mut c_void, size: CFIndex, allocator: CFAllocatorRef, info: *mut c_void) -> *mut c_void, + version: CFVersion1, + info: *mut c_void, + retain: Option, + release: Option, + copyDescription: Option, + equal: Option, + hash: Option, + getPort: Option, + perform: CFRunLoopPerformCallBack, } +pub type CFRunLoopRetainCallBack = + unsafe extern fn(info: *const c_void) -> *const c_void; + +pub type CFRunLoopReleaseCallBack = + unsafe extern fn(info: *const c_void); + +pub type CFRunLoopCopyDescriptionCallBack = + unsafe extern fn( + info: *const c_void) + -> Option<&'static CFShared>; + +pub type CFRunLoopEqualCallBack = + unsafe extern fn(info1: *const c_void, info2: *const c_void) -> bool; + +pub type CFRunLoopHashCallBack = + unsafe extern fn(info: *const c_void) -> CFHashCode; + +pub type CFRunLoopScheduleCallBack = + unsafe extern fn( + info: *mut c_void, + rl: &CFShared, + mode: &CFShared); + +pub type CFRunLoopCancelCallBack = + unsafe extern fn( + info: *mut c_void, + rl: &CFShared, + mode: &CFShared); + +pub type CFRunLoopPerformCallBack = + unsafe extern fn(info: *const c_void); + +pub type CFRunLoopGetPortCallBack = + unsafe extern fn(info: *const c_void) -> *const c_void; + +pub type CFRunLoopMachPerformCallBack = + unsafe extern fn( + info: *const c_void, + size: CFIndex, + allocator: &CFShared); + +pub type CFRunLoopObserverRef = CFRef; + +#[repr(C)] +pub struct CFRunLoopObserver { obj: CFObject } + +unsafe impl Send for CFRunLoopObserver {} +unsafe impl Sync for CFRunLoopObserver {} + +unsafe impl CFType for CFRunLoopObserver { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +bitflags! { + #[repr(C)] + pub flags CFRunLoopActivity: CFOptionFlags { + const RUN_LOOP_ENTRY = 1 << 0, + const RUN_LOOP_BEFORE_TIMERS = 1 << 1, + const RUN_LOOP_BEFORE_SOURCES = 1 << 2, + const RUN_LOOP_BEFORE_WAITING = 1 << 5, + const RUN_LOOP_AFTER_WAITING = 1 << 6, + const RUN_LOOP_EXIT = 1 << 7, + const RUN_LOOP_ALL_ACIVITIES = 0x0FFFFFFF, + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(C)] pub struct CFRunLoopObserverContext { - pub version: CFIndex, - pub info: *mut c_void, - pub retain: extern "C" fn (info: *const c_void) -> *const c_void, - pub release: extern "C" fn (info: *const c_void), - pub copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef, + version: CFVersion0, + info: *mut c_void, + retain: Option, + release: Option, + copyDescription: Option, +} + +pub type CFRunLoopObserverCallBack = + unsafe extern fn( + observer: &CFShared, + activity: CFRunLoopActivity, + info: *mut c_void); + +pub type CFRunLoopTimerRef = CFRef; + +#[repr(C)] +pub struct CFRunLoopTimer { obj: CFObject } + +unsafe impl CFType for CFRunLoopTimer { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +unsafe impl Send for CFRunLoopTimer {} +unsafe impl Sync for CFRunLoopTimer {} + +unsafe impl CFDowncast for CFRunLoopTimer { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFRunLoopTimerGetTypeID() } + } } -pub type CFRunLoopObserverCallBack = extern "C" fn (observer: CFRunLoopObserverRef, activity: CFRunLoopActivity, info: *mut c_void); +impl CFRunLoopTimer { + #[inline] + pub unsafe fn new( + fire_date: CFAbsoluteTime, + interval: CFTimeInterval, + callout: CFRunLoopTimerCallBack, + context: Option<&CFRunLoopTimerContext>) + -> CFRunLoopTimerRef { + CFRef::from_retained( + CFRunLoopTimerCreate( + None, + fire_date, + interval, + CFRunLoopTimerFlags::default(), + 0, + callout, + context)) + } + + #[inline] + pub fn next_fire_date(&self) -> CFAbsoluteTime { + unsafe { CFRunLoopTimerGetNextFireDate(self) } + } + + #[inline] + pub fn set_next_fire_date(&self, fire_date: CFAbsoluteTime) { + unsafe { CFRunLoopTimerSetNextFireDate(self, fire_date) } + } + + #[inline] + pub fn interval(&self) -> CFTimeInterval { + unsafe { CFRunLoopTimerGetInterval(self) } + } + + #[inline] + pub fn order(&self) -> CFIndex { + unsafe { CFRunLoopTimerGetOrder(self) } + } + + #[inline] + pub fn repeats(&self) -> bool { + unsafe { CFRunLoopTimerDoesRepeat(self) } + } + + #[inline] + pub fn invalidate(&self) { + unsafe { CFRunLoopTimerInvalidate(self) } + } + #[inline] + pub fn is_valid(&self) -> bool { + unsafe { CFRunLoopTimerIsValid(self) } + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(C)] pub struct CFRunLoopTimerContext { - pub version: CFIndex, - pub info: *mut c_void, - pub retain: extern "C" fn (info: *const c_void) -> *const c_void, - pub release: extern "C" fn (info: *const c_void), - pub copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef, + version: CFVersion0, + info: *mut c_void, + retain: Option, + release: Option, + copyDescription: Option, } -pub type CFRunLoopTimerCallBack = extern "C" fn (timer: CFRunLoopTimerRef, info: *mut c_void); +pub type CFRunLoopTimerCallBack = + unsafe extern fn(observer: &CFShared, info: *mut c_void); +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(C)] -pub struct __CFRunLoopTimer; +pub struct CFRunLoopTimerFlags { flags: CFOptionFlags } + +impl CFRunLoopTimerFlags { + #[inline] + fn new() -> Self { + CFRunLoopTimerFlags { flags: 0 } + } +} + +impl Default for CFRunLoopTimerFlags { + #[inline] + fn default() -> Self { + CFRunLoopTimerFlags::new() + } +} + +#[cfg(test)] +mod test { + use runloop::{CFRunLoop, CFRunLoopTimer}; + use runloop::{CFRunLoopTimerContext, kCFRunLoopDefaultMode}; + use std::os::raw::c_void; + use sync::CFShared; + use time::{CFAbsoluteTime, CFAbsoluteTimeGetCurrent}; -pub type CFRunLoopTimerRef = *const __CFRunLoopTimer; + #[test] + fn wait_200_milliseconds() { + let run_loop = CFRunLoop::current(); + let mut now = unsafe { CFAbsoluteTimeGetCurrent() }; + let context = CFRunLoopTimerContext { + version: Default::default(), + info: &mut now as *mut _ as *mut _, + retain: None, + release: None, + copyDescription: None, + }; + + let timer = unsafe { + CFRunLoopTimer::new( + now + 0.20f64, 0f64, timer_popped, Some(&context)) + }; + run_loop.add_timer(&timer, kCFRunLoopDefaultMode.unwrap()); + + CFRunLoop::run(); + } + + unsafe extern fn timer_popped( + _timer: &CFShared, info: *mut c_void) { + let previous_now = &*(info as *const CFAbsoluteTime); + let now = CFAbsoluteTimeGetCurrent(); + assert!(now - previous_now > 0.19 && now - previous_now < 0.21); + CFRunLoop::current().stop(); + } +} extern { - /* - * CFRunLoop.h - */ - pub static kCFRunLoopDefaultMode: CFStringRef; - pub static kCFRunLoopCommonModes: CFStringRef; + pub static kCFRunLoopDefaultMode: Option<&'static CFShared>; + pub fn CFRunLoopGetTypeID() -> CFTypeID; - pub fn CFRunLoopGetCurrent() -> CFRunLoopRef; - pub fn CFRunLoopGetMain() -> CFRunLoopRef; - pub fn CFRunLoopCopyCurrentMode(rl: CFRunLoopRef) -> CFStringRef; - pub fn CFRunLoopCopyAllModes(rl: CFRunLoopRef) -> CFArrayRef; - pub fn CFRunLoopAddCommonMode(rl: CFRunLoopRef, mode: CFStringRef); - pub fn CFRunLoopGetNextTimerFireDate(rl: CFRunLoopRef, mode: CFStringRef) -> CFAbsoluteTime; + + pub fn CFRunLoopGetCurrent() -> *const CFShared; + pub fn CFRunLoopGetMain() -> *const CFShared; + + pub fn CFRunLoopCopyCurrentMode( + rl: &CFRunLoop) + -> *const CFShared; + + pub fn CFRunLoopGetNextTimerFireDate( + rl: &CFRunLoop, mode: &CFString) + -> CFAbsoluteTime; + pub fn CFRunLoopRun(); - pub fn CFRunLoopRunInMode(mode: CFStringRef, seconds: CFTimeInterval, returnAfterSourceHandled: Boolean) -> i32; - pub fn CFRunLoopIsWaiting(rl: CFRunLoopRef) -> Boolean; - pub fn CFRunLoopWakeUp(rl: CFRunLoopRef); - pub fn CFRunLoopStop(rl: CFRunLoopRef); - // fn CFRunLoopPerformBlock(rl: CFRunLoopRef, mode: CFTypeRef, block: void (^)(void)); - pub fn CFRunLoopContainsSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef) -> Boolean; - pub fn CFRunLoopAddSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef); - pub fn CFRunLoopRemoveSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef); - pub fn CFRunLoopContainsObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef) -> Boolean; - pub fn CFRunLoopAddObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef); - pub fn CFRunLoopRemoveObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef); - pub fn CFRunLoopContainsTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef) -> Boolean; - pub fn CFRunLoopAddTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef); - pub fn CFRunLoopRemoveTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef); + + pub fn CFRunLoopRunInMode( + mode: &CFString, + seconds: CFTimeInterval, + returnAfterSourceHandled: bool) + -> CFRunLoopRunResult; + + pub fn CFRunLoopIsWaiting(rl: &CFRunLoop) -> bool; + pub fn CFRunLoopWakeUp(rl: &CFRunLoop); + pub fn CFRunLoopStop(rl: &CFRunLoop); + + pub fn CFRunLoopContainsSource( + rl: &CFRunLoop, source: &CFRunLoopSource, mode: &CFString) + -> bool; + + pub fn CFRunLoopAddSource( + rl: &CFRunLoop, source: &CFRunLoopSource, mode: &CFString); + + pub fn CFRunLoopRemoveSource( + rl: &CFRunLoop, source: &CFRunLoopSource, mode: &CFString); + + pub fn CFRunLoopContainsObserver( + rl: &CFRunLoop, observer: &CFRunLoopObserver, mode: &CFString) + -> bool; + + pub fn CFRunLoopAddObserver( + rl: &CFRunLoop, observer: &CFRunLoopObserver, mode: &CFString); + + pub fn CFRunLoopRemoveObserver( + rl: &CFRunLoop, observer: &CFRunLoopObserver, mode: &CFString); + + pub fn CFRunLoopContainsTimer( + rl: &CFRunLoop, timer: &CFRunLoopTimer, mode: &CFString) + -> bool; + + pub fn CFRunLoopAddTimer( + rl: &CFRunLoop, timer: &CFRunLoopTimer, mode: &CFString); + + pub fn CFRunLoopRemoveTimer( + rl: &CFRunLoop, timer: &CFRunLoopTimer, mode: &CFString); pub fn CFRunLoopSourceGetTypeID() -> CFTypeID; - pub fn CFRunLoopSourceCreate(allocator: CFAllocatorRef, order: CFIndex, context: *mut CFRunLoopSourceContext) -> CFRunLoopSourceRef; - pub fn CFRunLoopSourceGetOrder(source: CFRunLoopSourceRef) -> CFIndex; - pub fn CFRunLoopSourceInvalidate(source: CFRunLoopSourceRef); - pub fn CFRunLoopSourceIsValid(source: CFRunLoopSourceRef) -> Boolean; - pub fn CFRunLoopSourceGetContext(source: CFRunLoopSourceRef, context: *mut CFRunLoopSourceContext); - pub fn CFRunLoopSourceSignal(source: CFRunLoopSourceRef); + + pub fn CFRunLoopSourceCreate( + allocator: Option<&'static CFAllocator>, + order: CFIndex, + context: *const c_void) + -> *const CFShared; + + pub fn CFRunLoopSourceGetOrder(source: &CFRunLoopSource) -> CFIndex; + pub fn CFRunLoopSourceInvalidate(source: &CFRunLoopSource); + pub fn CFRunLoopSourceIsValid(source: &CFRunLoopSource) -> bool; + + pub fn CFRunLoopSourceGetContext( + source: &CFRunLoopSource, context: *mut c_void); + + pub fn CFRunLoopSourceSignal(source: &CFRunLoopSource); pub fn CFRunLoopObserverGetTypeID() -> CFTypeID; - pub fn CFRunLoopObserverCreate(allocator: CFAllocatorRef, activities: CFOptionFlags, repeats: Boolean, order: CFIndex, callout: CFRunLoopObserverCallBack, context: *mut CFRunLoopObserverContext) -> CFRunLoopObserverRef; - // fn CFRunLoopObserverCreateWithHandler(allocator: CFAllocatorRef, activities: CFOptionFlags, repeats: Boolean, order: CFIndex, block: void (^) (CFRunLoopObserverRef observer, CFRunLoopActivity activity)) -> CFRunLoopObserverRef; - pub fn CFRunLoopObserverGetActivities(observer: CFRunLoopObserverRef) -> CFOptionFlags; - pub fn CFRunLoopObserverDoesRepeat(observer: CFRunLoopObserverRef) -> Boolean; - pub fn CFRunLoopObserverGetOrder(observer: CFRunLoopObserverRef) -> CFIndex; - pub fn CFRunLoopObserverInvalidate(observer: CFRunLoopObserverRef); - pub fn CFRunLoopObserverIsValid(observer: CFRunLoopObserverRef) -> Boolean; - pub fn CFRunLoopObserverGetContext(observer: CFRunLoopObserverRef, context: *mut CFRunLoopObserverContext); + + pub fn CFRunLoopObserverCreate( + allocator: Option<&'static CFAllocator>, + activities: CFRunLoopActivity, + repeats: bool, + order: CFIndex, + callout: CFRunLoopObserverCallBack, + context: Option<&CFRunLoopObserverContext>) + -> *const CFShared; + + pub fn CFRunLoopObserverGetActivities( + observer: &CFRunLoopObserver) + -> CFRunLoopActivity; + + pub fn CFRunLoopObserverDoesRepeat(observer: &CFRunLoopObserver) -> bool; + pub fn CFRunLoopObserverGetOrder(observer: CFRunLoopObserver) -> CFIndex; + pub fn CFRunLoopObserverInvalidate(observer: CFRunLoopObserver); + pub fn CFRunLoopObserverIsValid(observer: &CFRunLoopObserver) -> bool; + + pub fn CFRunLoopObserverGetContext( + observer: &CFRunLoopObserver, + context: &mut CFRunLoopObserverContext); pub fn CFRunLoopTimerGetTypeID() -> CFTypeID; - pub fn CFRunLoopTimerCreate(allocator: CFAllocatorRef, fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext) -> CFRunLoopTimerRef; - // fn CFRunLoopTimerCreateWithHandler(allocator: CFAllocatorRef, fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, block: void (^) (CFRunLoopTimerRef timer)) -> CFRunLoopTimerRef; - pub fn CFRunLoopTimerGetNextFireDate(timer: CFRunLoopTimerRef) -> CFAbsoluteTime; - pub fn CFRunLoopTimerSetNextFireDate(timer: CFRunLoopTimerRef, fireDate: CFAbsoluteTime); - pub fn CFRunLoopTimerGetInterval(timer: CFRunLoopTimerRef) -> CFTimeInterval; - pub fn CFRunLoopTimerDoesRepeat(timer: CFRunLoopTimerRef) -> Boolean; - pub fn CFRunLoopTimerGetOrder(timer: CFRunLoopTimerRef) -> CFIndex; - pub fn CFRunLoopTimerInvalidate(timer: CFRunLoopTimerRef); - pub fn CFRunLoopTimerIsValid(timer: CFRunLoopTimerRef) -> Boolean; - pub fn CFRunLoopTimerGetContext(timer: CFRunLoopTimerRef, context: *mut CFRunLoopTimerContext); - pub fn CFRunLoopTimerGetTolerance(timer: CFRunLoopTimerRef) -> CFTimeInterval; - pub fn CFRunLoopTimerSetTolerance(timer: CFRunLoopTimerRef, tolerance: CFTimeInterval); + + pub fn CFRunLoopTimerCreate( + allocator: Option<&'static CFAllocator>, + fireDate: CFAbsoluteTime, + interval: CFTimeInterval, + flags: CFRunLoopTimerFlags, + order: CFIndex, + callout: CFRunLoopTimerCallBack, + context: Option<&CFRunLoopTimerContext>) + -> *const CFShared; + + pub fn CFRunLoopTimerGetNextFireDate( + timer: &CFRunLoopTimer) + -> CFAbsoluteTime; + + pub fn CFRunLoopTimerSetNextFireDate( + timer: &CFRunLoopTimer, fireDate: CFAbsoluteTime); + + pub fn CFRunLoopTimerGetInterval(timer: &CFRunLoopTimer) -> CFTimeInterval; + pub fn CFRunLoopTimerDoesRepeat(timer: &CFRunLoopTimer) -> bool; + pub fn CFRunLoopTimerGetOrder(timer: &CFRunLoopTimer) -> CFIndex; + pub fn CFRunLoopTimerInvalidate(timer: &CFRunLoopTimer); + pub fn CFRunLoopTimerIsValid(timer: &CFRunLoopTimer) -> bool; + + pub fn CFRunLoopTimerGetContext( + timer: &CFRunLoopTimer, context: &mut CFRunLoopTimerContext); } diff --git a/core-foundation-sys/src/set.rs b/core-foundation-sys/src/set.rs index 0e7e64c..6910dc5 100644 --- a/core-foundation-sys/src/set.rs +++ b/core-foundation-sys/src/set.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 ; -pub type CFSetRetainCallBack = *const u8; -pub type CFSetReleaseCallBack = *const u8; -pub type CFSetCopyDescriptionCallBack = *const u8; -pub type CFSetEqualCallBack = *const u8; -pub type CFSetHashCallBack = *const u8; +#[repr(C)] +pub struct CFSet { obj: CFObject } + +unsafe impl Send for CFSet {} +unsafe impl Sync for CFSet {} + +unsafe impl CFType for CFSet { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +unsafe impl CFDowncast for CFSet { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFSetGetTypeID() } + } +} + +impl CFSet { + #[inline] + pub fn from_objects(input: &[&CFShared]) -> CFSetRef { + unsafe { + CFSet::new( + &*(input as *const _ as *const _), Some(&kCFTypeSetCallBacks)) + } + } + + #[inline] + pub fn from_duplicated_strings(input: &[&CFShared]) -> CFSetRef { + unsafe { + CFSet::new( + &*(input as *const _ as *const _), + Some(&kCFCopyStringSetCallBacks)) + } + } + + #[inline] + pub unsafe fn new( + values: &[*const c_void], callbacks: Option<&CFSetCallBacks>) + -> CFSetRef { + CFRef::from_retained( + CFSetCreate( + None, values.as_ptr(), values.len().into_index(), callbacks)) + } + #[inline] + pub fn duplicate(&self) -> CFSetRef { + unsafe { CFRef::from_retained(CFSetCreateCopy(None, self)) } + } + + #[inline] + pub fn len(&self) -> usize { + unsafe { usize::from_index(CFSetGetCount(self)) } + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + #[inline] + pub unsafe fn count_value(&self, value: *const c_void) -> usize { + usize::from_index(CFSetGetCountOfValue(self, value)) + } + + #[inline] + pub unsafe fn contains_value(&self, value: *const c_void) -> bool { + CFSetContainsValue(self, value) + } + + #[inline] + pub unsafe fn get(&self, value: *const c_void) -> Option<*const c_void> { + let mut result = ptr::null(); + if CFSetGetValueIfPresent(self, value, &mut result) { + Some(result) + } else { + None + } + } + + #[inline] + pub fn values(&self) -> Vec<*const c_void> { + let mut result = vec![ptr::null(); self.len()]; + unsafe { CFSetGetValues(self, result.as_mut_ptr()) } + result + } + + #[inline] + pub unsafe fn inspect( + &self, + applier: unsafe extern fn(value: *const c_void, context: &mut T), + context: &mut T) { + CFSetApplyFunction( + self, + mem::transmute(applier), + &mut *(context as *mut _ as *mut _)); + } +} + +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] #[repr(C)] -#[derive(Clone, Copy)] pub struct CFSetCallBacks { - pub version: CFIndex, - pub retain: CFSetRetainCallBack, - pub release: CFSetReleaseCallBack, - pub copyDescription: CFSetCopyDescriptionCallBack, - pub equal: CFSetEqualCallBack, - pub hash: CFSetHashCallBack, + version: CFVersion0, + retain: Option, + release: Option, + copyDescription: Option, + equal: Option, + hash: Option, } -#[repr(C)] -pub struct __CFSet(c_void); +pub type CFSetRetainCallBack = + unsafe extern fn( + allocator: Option<&'static CFAllocator>, value: *const c_void) + -> *const c_void; -pub type CFSetRef = *const __CFSet; +pub type CFSetReleaseCallBack = + unsafe extern fn( + allocator: Option<&'static CFAllocator>, value: *const c_void); -extern { - /* - * CFSet.h - */ +pub type CFSetCopyDescriptionCallBack = + unsafe extern fn( + value: *const c_void) + -> Option<&'static CFShared>; - pub static kCFTypeSetCallBacks: CFSetCallBacks; +pub type CFSetEqualCallBack = + unsafe extern fn(value1: *const c_void, value2: *const c_void) -> bool; - /* Creating Sets */ - pub fn CFSetCreate(allocator: CFAllocatorRef, values: *const *const c_void, numValues: CFIndex, - callBacks: *const CFSetCallBacks) -> CFSetRef; +pub type CFSetHashCallBack = + unsafe extern fn(value: *const c_void) -> CFHashCode; - /* Applying a Function to Set Members */ - //fn CFSetApplyFunction +pub type CFSetApplierFunction = + unsafe extern fn(value: *const c_void, context: *mut c_void); + +extern { + pub static kCFTypeSetCallBacks: CFSetCallBacks; + pub static kCFCopyStringSetCallBacks: CFSetCallBacks; pub fn CFSetGetTypeID() -> CFTypeID; -} + pub fn CFSetCreate<'values>( + allocator: Option<&'static CFAllocator>, + values: *const *const c_void, + numValues: CFIndex, + callBacks: Option<&CFSetCallBacks>) + -> *const CFShared; + + pub fn CFSetCreateCopy<'values>( + allocator: Option<&'static CFAllocator>, + theSet: &CFSet) + -> *const CFShared; + + pub fn CFSetGetCount(theSet: &CFSet) -> CFIndex; + + pub fn CFSetGetCountOfValue( + theSet: &CFSet, value: *const c_void) + -> CFIndex; + + pub fn CFSetContainsValue(theSet: &CFSet, value: *const c_void) -> bool; + pub fn CFSetGetValue(theSet: &CFSet, value: *const c_void) -> *const c_void; + + pub fn CFSetGetValueIfPresent( + theSet: &CFSet, candidate: *const c_void, value: &mut *const c_void) + -> bool; + + pub fn CFSetGetValues(theSet: &CFSet, values: *mut *const c_void); + + pub fn CFSetApplyFunction( + theSet: &CFSet, + applier: CFSetApplierFunction, + context: *mut c_void); +} diff --git a/core-foundation-sys/src/string.rs b/core-foundation-sys/src/string.rs index 746368c..dbd0b8b 100644 --- a/core-foundation-sys/src/string.rs +++ b/core-foundation-sys/src/string.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 ; -// CFString.h +/// Encapsulates string values. +/// +/// Unless stated otherwise, all lengths and ranges taken and returned by +/// methods on this type are expressed in terms of WTF-16 code units. +#[repr(C)] +pub struct CFString { obj: CFObject } + +unsafe impl Send for CFString {} +unsafe impl Sync for CFString {} + +unsafe impl CFType for CFString { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +unsafe impl CFDowncast for CFString { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFStringGetTypeID() } + } +} + +/// ## Creating a `CFString` +impl CFString { + /// Creates a `CFString` from a WTF-16 slice. + #[inline] + pub fn from_slice(input: &[u16]) -> CFStringRef { + unsafe { + CFRef::from_retained( + CFStringCreateWithCharacters( + None, input.as_ptr(), input.len().into_index())) + } + } + + /// Creates a `CFString` from a static WTF-16 slice. + #[inline] + pub fn from_static_slice(input: &'static [u16]) -> CFStringRef { + unsafe { + CFRef::from_retained( + CFStringCreateWithCharactersNoCopy( + None, + input.as_ptr(), + input.len().into_index(), + Some(CFAllocator::null_allocator()))) + } + } + + /// Creates a `CFString` from a `str` slice. + #[inline] + pub fn from_str(input: &str) -> CFStringRef { + unsafe { + CFRef::from_retained( + CFStringCreateWithBytes( + None, + input.as_ptr(), + input.len().into_index(), + CFStringBuiltInEncodings::UTF8 as u32, + false)) + } + } + + /// Creates a `CFString` from a static `str` slice. + #[inline] + pub fn from_static_str(input: &'static str) -> CFStringRef { + unsafe { + CFRef::from_retained( + CFStringCreateWithBytesNoCopy( + None, + input.as_ptr(), + input.len().into_index(), + CFStringBuiltInEncodings::UTF8 as u32, + false, + Some(CFAllocator::null_allocator()))) + } + } + + /// Duplicates this string. + #[inline] + pub fn duplicate(&self) -> CFStringRef { + unsafe { CFRef::from_retained(CFStringCreateCopy(None, self)) } + } + + /// Creates a substring of this string. + #[inline] + pub fn substring(&self, range: Range) -> CFStringRef { + assert!(range.end <= self.len()); + unsafe { + CFRef::from_retained( + CFStringCreateWithSubstring(None, self, range.into())) + } + } +} + +/// ## Accessing characters +impl CFString { + /// Returns the length of the string in WTF-16 code units. + #[inline] + pub fn len(&self) -> usize { + unsafe { usize::from_index(CFStringGetLength(self)) } + } + + /// Returns whether the string is empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the string as a WTF-16 slice efficiently. + /// + /// This may return `None` if the string isn't internally stored as WTF-16. + #[inline] + pub fn to_slice(&self) -> Option<&[u16]> { + let len = self.len(); + if len == 0 { + return Some(&[]); + } + unsafe { + let ptr = CFStringGetCharactersPtr(self); + if !ptr.is_null() { + Some(slice::from_raw_parts(ptr, len)) + } else { + None + } + } + } + + /// Returns the string as a WTF-16 `Cow` slice. + /// + /// This may return `Cow::Owned(vec)` if the string isn't internally + /// stored as WTF-16. + #[inline] + pub fn to_cow(&self) -> Cow<[u16]> { + if let Some(slice) = self.to_slice() { + return slice.into(); + } + unsafe { + let len = self.len(); + let mut output = vec![0; len]; + CFStringGetCharacters(self, (0..len).into(), output.as_mut_ptr()); + output.into() + } + } + + /// Convenience method around `self.to_cow().into_owned()`. + #[inline] + pub fn to_vec(&self) -> Vec { + self.to_cow().into_owned() + } + + /// Returns the string as a `str` slice efficiently. + /// + /// This may return `None` if the string isn't internally stored + /// as a Pascal string or if it doesn't actually represent valid UTF-8 + /// text to begin with. + pub fn to_str(&self) -> Option<&str> { + if self.len() == 0 { + return Some(""); + } + unsafe { + // CFStringGetCStringPtr cannot be used here because it returns a + // result even if the string itself includes a NUL, thus truncating + // the result. + let pstr_ptr = CFStringGetPascalStringPtr( + self, CFStringBuiltInEncodings::UTF8 as u32); + if !pstr_ptr.is_null() { + let slice = slice::from_raw_parts( + pstr_ptr.offset(1), *pstr_ptr as usize); + return Some(str::from_utf8_unchecked(slice)); + } + None + } + } + + /// Returns the string as a `str` `Cow` slice. + /// + /// This may return `Ok(Cow::Owned(string))` if the string represents valid + /// UTF-8 text but isn't internally stored as a Pascal string. + /// + /// The value `Err(())` is returned if the string couldn't be converted + /// to UTF-8. + pub fn to_cow_str(&self) -> Result, ()> { + if let Some(str) = self.to_str() { + return Ok(str.into()); + } + + unsafe { + let len = CFStringGetLength(self); + let full_range = CFRange { + location: 0, + length: len, + }; + + let mut output_len = 0; + let read_chars_count = CFStringGetBytes( + self, + full_range, + CFStringBuiltInEncodings::UTF8 as u32, + 0, + false, + ptr::null_mut(), + 0, + Some(&mut output_len)); + assert!(output_len >= 0); + if read_chars_count != len { + return Err(()); + } + + let mut output = vec![0; usize::from_index(output_len)]; + let mut used_output_len = 0; + let write_chars_count = CFStringGetBytes( + self, + full_range, + CFStringBuiltInEncodings::UTF8 as u32, + 0, + false, + output.as_mut_ptr(), + output_len, + Some(&mut used_output_len)); + assert_eq!(used_output_len, output_len); + assert_eq!(write_chars_count, read_chars_count); + + Ok(String::from_utf8_unchecked(output).into()) + } + } + + /// Convenience method around `self.to_cow_str().map(Cow::into_owned)`. + #[inline] + pub fn to_string(&self) -> Result { + self.to_cow_str().map(Cow::into_owned) + } +} + +/// ## Comparing strings +impl CFString { + /// Compares this string with another. + /// + /// Also available as `::cmp`. + #[inline] + pub fn cmp_with_options( + &self, other: &Self, options: CFStringCompareFlags) + -> Ordering { + unsafe { + CFStringCompare(self, other, options).into() + } + } + + /// Compares a range of the WTF-16 code units in this string with another. + #[inline] + pub fn cmp_with_options_in_range( + &self, + other: &Self, + options: CFStringCompareFlags, + range: Range) + -> Ordering { + assert!(range.end <= self.len()); + let result = unsafe { + CFStringCompareWithOptions(self, other, range.into(), options) + }; + result.into() + } +} + +/// ## Searching strings +impl CFString { + /// Returns whether `needle` is contained in this string. + #[inline] + pub fn contains( + &self, needle: &Self, options: CFStringCompareFlags) + -> bool { + self.find(needle, options).is_some() + } -pub type CFStringCompareFlags = CFOptionFlags; -//static kCFCompareCaseInsensitive: CFStringCompareFlags = 1; -//static kCFCompareBackwards: CFStringCompareFlags = 4; -//static kCFCompareAnchored: CFStringCompareFlags = 8; -//static kCFCompareNonliteral: CFStringCompareFlags = 16; -//static kCFCompareLocalized: CFStringCompareFlags = 32; -//static kCFCompareNumerically: CFStringCompareFlags = 64; -//static kCFCompareDiacriticInsensitive: CFStringCompareFlags = 128; -//static kCFCompareWidthInsensitive: CFStringCompareFlags = 256; -//static kCFCompareForcedOrdering: CFStringCompareFlags = 512; + /// Returns whether `needle` is contained in as specific range. + #[inline] + pub fn contains_in_range( + &self, + needle: &Self, + options: CFStringCompareFlags, + range: Range) + -> bool { + assert!(range.end <= self.len()); + unsafe { + CFStringFindWithOptions(self, needle, range.into(), options, None) + } + } + + /// Finds `needle` in this string. + #[inline] + pub fn find( + &self, needle: &Self, options: CFStringCompareFlags) + -> Option> { + let result = unsafe { CFStringFind(self, needle, options) }; + if result.location >= 0 { + Some(result.into()) + } else { + None + } + } + + /// Finds `needle` in a specific range. + #[inline] + pub fn find_in_range( + &self, + needle: &CFString, + options: CFStringCompareFlags, + range: Range) + -> Option> { + assert!(range.end <= self.len()); + let mut result = CFRange::default(); + let found = unsafe { + CFStringFindWithOptions( + self, needle, range.into(), options, Some(&mut result)) + }; + if found { + Some(result.into()) + } else { + None + } + } + + /// Returns whether this string starts with `needle`. + #[inline] + pub fn starts_with(&self, needle: &CFString) -> bool { + unsafe { CFStringHasPrefix(self, needle) } + } + + /// Returns whether this string ends with `needle`. + #[inline] + pub fn ends_with(&self, needle: &CFString) -> bool { + unsafe { CFStringHasSuffix(self, needle) } + } +} + +/// ## Getting numeric values +impl CFString { + /// Converts this string as a `i32` value. + /// + /// This method just returns 0 on a conversion error. + #[inline] + pub fn to_i32(&self) -> i32 { + unsafe { CFStringGetIntValue(self) } + } + + /// Converts this string as a `f64` value. + /// + /// This method just returns 0.0 on a conversion error. + #[inline] + pub fn to_f64(&self) -> f64 { + unsafe { CFStringGetDoubleValue(self) } + } +} + +impl fmt::Debug for CFString { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + let mut tuple = formatter.debug_tuple("CFString"); + if let Some(str) = self.to_str() { + tuple.field(&str); + } else if let Some(slice) = self.to_slice() { + tuple.field(&slice); + } else { + tuple.field(&format_args!("[_; {}]", self.len())); + } + tuple.finish() + } +} + +impl<'a> From<&'a str> for CFStringRef { + #[inline] + fn from(input: &'a str) -> Self { + CFString::from_str(input) + } +} + +impl str::FromStr for CFStringRef { + type Err = ParseError; + + #[inline] + fn from_str(input: &str) -> Result { + Ok(CFString::from_str(input)) + } +} + +impl<'a> From<&'a [u16]> for CFStringRef { + #[inline] + fn from(input: &'a [u16]) -> Self { + CFString::from_slice(input) + } +} + +impl<'a> From<&'a CFString> for Cow<'a, [u16]> { + #[inline] + fn from(input: &'a CFString) -> Self { + input.to_cow() + } +} + +impl<'a> From<&'a CFString> for Vec { + #[inline] + fn from(input: &'a CFString) -> Self { + input.to_vec() + } +} + +impl Eq for CFString {} + +impl PartialEq for CFString { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.cmp(other) == Ordering::Equal + } +} + +impl Ord for CFString { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + unsafe { + CFStringCompare(self, other, COMPARE_FORCED_ORDERING).into() + } + } +} + +impl PartialOrd for CFString { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +bitflags! { + #[repr(C)] + pub flags CFStringCompareFlags: CFOptionFlags { + const COMPARE_CASE_INSENSITIVE = 1, + const COMPARE_BACKWARDS = 4, + const COMPARE_ANCHORED = 8, + const COMPARE_NON_LITERAL = 16, + const COMPARE_LOCALIZED = 32, + const COMPARE_NUMERICALLY = 64, + const COMPARE_DIACRITIC_INSENSITIVE = 128, + const COMPARE_WIDTH_INSENSITIVE = 256, + const COMPARE_FORCED_ORDERING = 512, + } +} pub type CFStringEncoding = u32; -// OS X built-in encodings. - -//static kCFStringEncodingMacRoman: CFStringEncoding = 0; -//static kCFStringEncodingWindowsLatin1: CFStringEncoding = 0x0500; -//static kCFStringEncodingISOLatin1: CFStringEncoding = 0x0201; -//static kCFStringEncodingNextStepLatin: CFStringEncoding = 0x0B01; -//static kCFStringEncodingASCII: CFStringEncoding = 0x0600; -//static kCFStringEncodingUnicode: CFStringEncoding = 0x0100; -pub static kCFStringEncodingUTF8: CFStringEncoding = 0x08000100; -//static kCFStringEncodingNonLossyASCII: CFStringEncoding = 0x0BFF; - -//static kCFStringEncodingUTF16: CFStringEncoding = 0x0100; -//static kCFStringEncodingUTF16BE: CFStringEncoding = 0x10000100; -//static kCFStringEncodingUTF16LE: CFStringEncoding = 0x14000100; -//static kCFStringEncodingUTF32: CFStringEncoding = 0x0c000100; -//static kCFStringEncodingUTF32BE: CFStringEncoding = 0x18000100; -//static kCFStringEncodingUTF32LE: CFStringEncoding = 0x1c000100; - - -// CFStringEncodingExt.h - -pub type CFStringEncodings = CFIndex; - -// External encodings, except those defined above. -// Defined above: kCFStringEncodingMacRoman = 0 -//static kCFStringEncodingMacJapanese: CFStringEncoding = 1; -//static kCFStringEncodingMacChineseTrad: CFStringEncoding = 2; -//static kCFStringEncodingMacKorean: CFStringEncoding = 3; -//static kCFStringEncodingMacArabic: CFStringEncoding = 4; -//static kCFStringEncodingMacHebrew: CFStringEncoding = 5; -//static kCFStringEncodingMacGreek: CFStringEncoding = 6; -//static kCFStringEncodingMacCyrillic: CFStringEncoding = 7; -//static kCFStringEncodingMacDevanagari: CFStringEncoding = 9; -//static kCFStringEncodingMacGurmukhi: CFStringEncoding = 10; -//static kCFStringEncodingMacGujarati: CFStringEncoding = 11; -//static kCFStringEncodingMacOriya: CFStringEncoding = 12; -//static kCFStringEncodingMacBengali: CFStringEncoding = 13; -//static kCFStringEncodingMacTamil: CFStringEncoding = 14; -//static kCFStringEncodingMacTelugu: CFStringEncoding = 15; -//static kCFStringEncodingMacKannada: CFStringEncoding = 16; -//static kCFStringEncodingMacMalayalam: CFStringEncoding = 17; -//static kCFStringEncodingMacSinhalese: CFStringEncoding = 18; -//static kCFStringEncodingMacBurmese: CFStringEncoding = 19; -//static kCFStringEncodingMacKhmer: CFStringEncoding = 20; -//static kCFStringEncodingMacThai: CFStringEncoding = 21; -//static kCFStringEncodingMacLaotian: CFStringEncoding = 22; -//static kCFStringEncodingMacGeorgian: CFStringEncoding = 23; -//static kCFStringEncodingMacArmenian: CFStringEncoding = 24; -//static kCFStringEncodingMacChineseSimp: CFStringEncoding = 25; -//static kCFStringEncodingMacTibetan: CFStringEncoding = 26; -//static kCFStringEncodingMacMongolian: CFStringEncoding = 27; -//static kCFStringEncodingMacEthiopic: CFStringEncoding = 28; -//static kCFStringEncodingMacCentralEurRoman: CFStringEncoding = 29; -//static kCFStringEncodingMacVietnamese: CFStringEncoding = 30; -//static kCFStringEncodingMacExtArabic: CFStringEncoding = 31; -//static kCFStringEncodingMacSymbol: CFStringEncoding = 33; -//static kCFStringEncodingMacDingbats: CFStringEncoding = 34; -//static kCFStringEncodingMacTurkish: CFStringEncoding = 35; -//static kCFStringEncodingMacCroatian: CFStringEncoding = 36; -//static kCFStringEncodingMacIcelandic: CFStringEncoding = 37; -//static kCFStringEncodingMacRomanian: CFStringEncoding = 38; -//static kCFStringEncodingMacCeltic: CFStringEncoding = 39; -//static kCFStringEncodingMacGaelic: CFStringEncoding = 40; -//static kCFStringEncodingMacFarsi: CFStringEncoding = 0x8C; -//static kCFStringEncodingMacUkrainian: CFStringEncoding = 0x98; -//static kCFStringEncodingMacInuit: CFStringEncoding = 0xEC; -//static kCFStringEncodingMacVT100: CFStringEncoding = 0xFC; -//static kCFStringEncodingMacHFS: CFStringEncoding = 0xFF; -// Defined above: kCFStringEncodingISOLatin1 = 0x0201 -//static kCFStringEncodingISOLatin2: CFStringEncoding = 0x0202; -//static kCFStringEncodingISOLatin3: CFStringEncoding = 0x0203; -//static kCFStringEncodingISOLatin4: CFStringEncoding = 0x0204; -//static kCFStringEncodingISOLatinCyrillic: CFStringEncoding = 0x0205; -//static kCFStringEncodingISOLatinArabic: CFStringEncoding = 0x0206; -//static kCFStringEncodingISOLatinGreek: CFStringEncoding = 0x0207; -//static kCFStringEncodingISOLatinHebrew: CFStringEncoding = 0x0208; -//static kCFStringEncodingISOLatin5: CFStringEncoding = 0x0209; -//static kCFStringEncodingISOLatin6: CFStringEncoding = 0x020A; -//static kCFStringEncodingISOLatinThai: CFStringEncoding = 0x020B; -//static kCFStringEncodingISOLatin7: CFStringEncoding = 0x020D; -//static kCFStringEncodingISOLatin8: CFStringEncoding = 0x020E; -//static kCFStringEncodingISOLatin9: CFStringEncoding = 0x020F; -//static kCFStringEncodingISOLatin10: CFStringEncoding = 0x0210; -//static kCFStringEncodingDOSLatinUS: CFStringEncoding = 0x0400; -//static kCFStringEncodingDOSGreek: CFStringEncoding = 0x0405; -//static kCFStringEncodingDOSBalticRim: CFStringEncoding = 0x0406; -//static kCFStringEncodingDOSLatin1: CFStringEncoding = 0x0410; -//static kCFStringEncodingDOSGreek1: CFStringEncoding = 0x0411; -//static kCFStringEncodingDOSLatin2: CFStringEncoding = 0x0412; -//static kCFStringEncodingDOSCyrillic: CFStringEncoding = 0x0413; -//static kCFStringEncodingDOSTurkish: CFStringEncoding = 0x0414; -//static kCFStringEncodingDOSPortuguese: CFStringEncoding = 0x0415; -//static kCFStringEncodingDOSIcelandic: CFStringEncoding = 0x0416; -//static kCFStringEncodingDOSHebrew: CFStringEncoding = 0x0417; -//static kCFStringEncodingDOSCanadianFrench: CFStringEncoding = 0x0418; -//static kCFStringEncodingDOSArabic: CFStringEncoding = 0x0419; -//static kCFStringEncodingDOSNordic: CFStringEncoding = 0x041A; -//static kCFStringEncodingDOSRussian: CFStringEncoding = 0x041B; -//static kCFStringEncodingDOSGreek2: CFStringEncoding = 0x041C; -//static kCFStringEncodingDOSThai: CFStringEncoding = 0x041D; -//static kCFStringEncodingDOSJapanese: CFStringEncoding = 0x0420; -//static kCFStringEncodingDOSChineseSimplif: CFStringEncoding = 0x0421; -//static kCFStringEncodingDOSKorean: CFStringEncoding = 0x0422; -//static kCFStringEncodingDOSChineseTrad: CFStringEncoding = 0x0423; -// Defined above: kCFStringEncodingWindowsLatin1 = 0x0500 -//static kCFStringEncodingWindowsLatin2: CFStringEncoding = 0x0501; -//static kCFStringEncodingWindowsCyrillic: CFStringEncoding = 0x0502; -//static kCFStringEncodingWindowsGreek: CFStringEncoding = 0x0503; -//static kCFStringEncodingWindowsLatin5: CFStringEncoding = 0x0504; -//static kCFStringEncodingWindowsHebrew: CFStringEncoding = 0x0505; -//static kCFStringEncodingWindowsArabic: CFStringEncoding = 0x0506; -//static kCFStringEncodingWindowsBalticRim: CFStringEncoding = 0x0507; -//static kCFStringEncodingWindowsVietnamese: CFStringEncoding = 0x0508; -//static kCFStringEncodingWindowsKoreanJohab: CFStringEncoding = 0x0510; -// Defined above: kCFStringEncodingASCII = 0x0600 -//static kCFStringEncodingANSEL: CFStringEncoding = 0x0601; -//static kCFStringEncodingJIS_X0201_76: CFStringEncoding = 0x0620; -//static kCFStringEncodingJIS_X0208_83: CFStringEncoding = 0x0621; -//static kCFStringEncodingJIS_X0208_90: CFStringEncoding = 0x0622; -//static kCFStringEncodingJIS_X0212_90: CFStringEncoding = 0x0623; -//static kCFStringEncodingJIS_C6226_78: CFStringEncoding = 0x0624; -//static kCFStringEncodingShiftJIS_X0213: CFStringEncoding = 0x0628; -//static kCFStringEncodingShiftJIS_X0213_MenKuTen: CFStringEncoding = 0x0629; -//static kCFStringEncodingGB_2312_80: CFStringEncoding = 0x0630; -//static kCFStringEncodingGBK_95: CFStringEncoding = 0x0631; -//static kCFStringEncodingGB_18030_2000: CFStringEncoding = 0x0632; -//static kCFStringEncodingKSC_5601_87: CFStringEncoding = 0x0640; -//static kCFStringEncodingKSC_5601_92_Johab: CFStringEncoding = 0x0641; -//static kCFStringEncodingCNS_11643_92_P1: CFStringEncoding = 0x0651; -//static kCFStringEncodingCNS_11643_92_P2: CFStringEncoding = 0x0652; -//static kCFStringEncodingCNS_11643_92_P3: CFStringEncoding = 0x0653; -//static kCFStringEncodingISO_2022_JP: CFStringEncoding = 0x0820; -//static kCFStringEncodingISO_2022_JP_2: CFStringEncoding = 0x0821; -//static kCFStringEncodingISO_2022_JP_1: CFStringEncoding = 0x0822; -//static kCFStringEncodingISO_2022_JP_3: CFStringEncoding = 0x0823; -//static kCFStringEncodingISO_2022_CN: CFStringEncoding = 0x0830; -//static kCFStringEncodingISO_2022_CN_EXT: CFStringEncoding = 0x0831; -//static kCFStringEncodingISO_2022_KR: CFStringEncoding = 0x0840; -//static kCFStringEncodingEUC_JP: CFStringEncoding = 0x0920; -//static kCFStringEncodingEUC_CN: CFStringEncoding = 0x0930; -//static kCFStringEncodingEUC_TW: CFStringEncoding = 0x0931; -//static kCFStringEncodingEUC_KR: CFStringEncoding = 0x0940; -//static kCFStringEncodingShiftJIS: CFStringEncoding = 0x0A01; -//static kCFStringEncodingKOI8_R: CFStringEncoding = 0x0A02; -//static kCFStringEncodingBig5: CFStringEncoding = 0x0A03; -//static kCFStringEncodingMacRomanLatin1: CFStringEncoding = 0x0A04; -//static kCFStringEncodingHZ_GB_2312: CFStringEncoding = 0x0A05; -//static kCFStringEncodingBig5_HKSCS_1999: CFStringEncoding = 0x0A06; -//static kCFStringEncodingVISCII: CFStringEncoding = 0x0A07; -//static kCFStringEncodingKOI8_U: CFStringEncoding = 0x0A08; -//static kCFStringEncodingBig5_E: CFStringEncoding = 0x0A09; -// Defined above: kCFStringEncodingNextStepLatin = 0x0B01 -//static kCFStringEncodingNextStepJapanese: CFStringEncoding = 0x0B02; -//static kCFStringEncodingEBCDIC_US: CFStringEncoding = 0x0C01; -//static kCFStringEncodingEBCDIC_CP037: CFStringEncoding = 0x0C02; -//static kCFStringEncodingUTF7: CFStringEncoding = 0x04000100; -//static kCFStringEncodingUTF7_IMAP: CFStringEncoding = 0x0A10; -//static kCFStringEncodingShiftJIS_X0213_00: CFStringEncoding = 0x0628; /* Deprecated */ +pub const kCFStringEncodingInvalidId: CFStringEncoding = 0xffffffff; -#[repr(C)] -pub struct __CFString(c_void); +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[repr(u32)] +pub enum CFStringBuiltInEncodings { + MacRoman = 0, + WindowsLatin1 = 0x0500, + ISOLatin1 = 0x0201, + NextStepLatin = 0x0B01, + ASCII = 0x0600, + UTF8 = 0x08000100, + NonLossyASCII = 0x0BFF, + UTF16 = 0x0100, + UTF16BE = 0x10000100, + UTF16LE = 0x14000100, + UTF32 = 0x0c000100, + UTF32BE = 0x18000100, + UTF32LE = 0x1c000100, +} + +#[test] +fn test_to_slice() { + let empty = CFString::from_slice(&[] as &[_]); + assert_eq!(empty.to_slice(), Some(&[] as &[_])); +} -pub type CFStringRef = *const __CFString; +#[test] +fn test_to_str() { + let empty = CFString::from_str(""); + assert_eq!(empty.to_str(), Some("")); + + let fromage = CFString::from_str("fromage"); + assert_eq!(fromage.to_str(), Some("fromage")); + + // We don't use CFStringGetCStringPtr so that works. + let nul = CFString::from_str("\0"); + assert_eq!(nul.to_str(), Some("\0")); + + // This doesn't fit a Pascal string with a byte length tag, so this is None. + let nul_256_times = CFString::from_str(str::from_utf8(&[0; 256]).unwrap()); + assert_eq!(nul_256_times.to_str(), None); +} + +#[test] +fn test_string_and_back() { + let original = "The quick brown fox jumped over the slow lazy dog."; + let cf = CFString::from_static_str(original); + assert_eq!(cf.to_string(), Ok(original.to_owned())); +} extern { - /* - * CFString.h - */ - - // N.B. organized according to "Functions by task" in docs - - /* Creating a CFString */ - //fn CFSTR - //fn CFStringCreateArrayBySeparatingStrings - //fn CFStringCreateByCombiningStrings - //fn CFStringCreateCopy - //fn CFStringCreateFromExternalRepresentation - pub fn CFStringCreateWithBytes(alloc: CFAllocatorRef, - bytes: *const u8, - numBytes: CFIndex, - encoding: CFStringEncoding, - isExternalRepresentation: Boolean, - contentsDeallocator: CFAllocatorRef) - -> CFStringRef; - pub fn CFStringCreateWithBytesNoCopy(alloc: CFAllocatorRef, - bytes: *const u8, - numBytes: CFIndex, - encoding: CFStringEncoding, - isExternalRepresentation: Boolean, - contentsDeallocator: CFAllocatorRef) - -> CFStringRef; - //fn CFStringCreateWithCharacters - //fn CFStringCreateWithCharactersNoCopy - //fn CFStringCreateWithCString - //fn CFStringCreateWithCStringNoCopy - //fn CFStringCreateWithFormat - //fn CFStringCreateWithFormatAndArguments - //fn CFStringCreateWithPascalString - //fn CFStringCreateWithPascalStringNoCopy - //fn CFStringCreateWithSubstring - - /* Searching Strings */ - //fn CFStringCreateArrayWithFindResults - //fn CFStringFind - //fn CFStringFindCharacterFromSet - //fn CFStringFindWithOptions - //fn CFStringFindWithOptionsAndLocale - //fn CFStringGetLineBounds - - /* Comparing Strings */ - //fn CFStringCompare - //fn CFStringCompareWithOptions - //fn CFStringCompareWithOptionsAndLocale - //fn CFStringHasPrefix - //fn CFStringHasSuffix - - /* Accessing Characters */ - //fn CFStringCreateExternalRepresentation - pub fn CFStringGetBytes(theString: CFStringRef, - range: CFRange, - encoding: CFStringEncoding, - lossByte: u8, - isExternalRepresentation: Boolean, - buffer: *mut u8, - maxBufLen: CFIndex, - usedBufLen: *mut CFIndex) - -> CFIndex; - //fn CFStringGetCharacterAtIndex - //fn CFStringGetCharacters - //fn CFStringGetCharactersPtr - //fn CFStringGetCharacterFromInlineBuffer - //fn CFStringGetCString - pub fn CFStringGetCStringPtr(theString: CFStringRef, - encoding: CFStringEncoding) - -> *const c_char; - pub fn CFStringGetLength(theString: CFStringRef) -> CFIndex; - //fn CFStringGetPascalString - //fn CFStringGetPascalStringPtr - //fn CFStringGetRangeOfComposedCharactersAtIndex - //fn CFStringInitInlineBuffer - - /* Working With Hyphenation */ - //fn CFStringGetHyphenationLocationBeforeIndex - //fn CFStringIsHyphenationAvailableForLocale - - /* Working With Encodings */ - //fn CFStringConvertEncodingToIANACharSetName - //fn CFStringConvertEncodingToNSStringEncoding - //fn CFStringConvertEncodingToWindowsCodepage - //fn CFStringConvertIANACharSetNameToEncoding - //fn CFStringConvertNSStringEncodingToEncoding - //fn CFStringConvertWindowsCodepageToEncoding - //fn CFStringGetFastestEncoding - //fn CFStringGetListOfAvailableEncodings - //fn CFStringGetMaximumSizeForEncoding - //fn CFStringGetMostCompatibleMacStringEncoding - //fn CFStringGetNameOfEncoding - //fn CFStringGetSmallestEncoding - //fn CFStringGetSystemEncoding - //fn CFStringIsEncodingAvailable - - /* Getting Numeric Values */ - //fn CFStringGetDoubleValue - //fn CFStringGetIntValue - - /* Getting String Properties */ - //fn CFShowStr pub fn CFStringGetTypeID() -> CFTypeID; - /* String File System Representations */ - //fn CFStringCreateWithFileSystemRepresentation - //fn CFStringGetFileSystemRepresentation - //fn CFStringGetMaximumSizeOfFileSystemRepresentation + pub fn CFStringCreateWithPascalString( + allocator: Option<&'static CFAllocator>, + pStr: *const u8, + encoding: CFStringEncoding) + -> *const CFShared; + + pub fn CFStringCreateWithCString( + allocator: Option<&'static CFAllocator>, + cStr: *const c_char, + encoding: CFStringEncoding) + -> *const CFShared; + + pub fn CFStringCreateWithBytes( + allocator: Option<&'static CFAllocator>, + bytes: *const u8, + numBytes: CFIndex, + encoding: CFStringEncoding, + isExternalRepresentation: bool) + -> *const CFShared; + + pub fn CFStringCreateWithCharacters( + allocator: Option<&'static CFAllocator>, + chars: *const u16, + numChars: CFIndex) + -> *const CFShared; + + pub fn CFStringCreateWithPascalStringNoCopy( + allocator: Option<&'static CFAllocator>, + pStr: *const u8, + encoding: CFStringEncoding, + contentsDeallocator: Option<&'static CFAllocator>) + -> *const CFShared; + + pub fn CFStringCreateWithCStringNoCopy( + allocator: Option<&'static CFAllocator>, + cStr: *const c_char, + encoding: CFStringEncoding, + contentsDeallocator: Option<&'static CFAllocator>) + -> *const CFShared; + + pub fn CFStringCreateWithBytesNoCopy( + allocator: Option<&'static CFAllocator>, + bytes: *const u8, + numBytes: CFIndex, + encoding: CFStringEncoding, + isExternalRepresentation: bool, + contentsDeallocator: Option<&'static CFAllocator>) + -> *const CFShared; + + pub fn CFStringCreateWithCharactersNoCopy( + allocator: Option<&'static CFAllocator>, + chars: *const u16, + numChars: CFIndex, + contentsDeallocator: Option<&'static CFAllocator>) + -> *const CFShared; + + pub fn CFStringCreateWithSubstring( + allocator: Option<&'static CFAllocator>, + str: &CFString, + range: CFRange) + -> *const CFShared; + + pub fn CFStringCreateCopy( + allocator: Option<&'static CFAllocator>, theString: &CFString) + -> *const CFShared; + + pub fn CFStringCreateWithFormat( + allocator: Option<&'static CFAllocator>, + formatOptions: &CFDictionary, + format: &CFString, + ...) + -> *const CFShared; + + pub fn CFStringGetLength(theString: &CFString) -> CFIndex; + + pub fn CFStringGetCharacterAtIndex( + theString: &CFString, idx: CFIndex) + -> u16; + + pub fn CFStringGetCharacters( + theString: &CFString, range: CFRange, buffer: *mut u16); + + pub fn CFStringGetPascalString( + theString: &CFString, + buffer: *mut u8, + bufferSize: CFIndex, + encoding: CFStringEncoding) + -> bool; + + pub fn CFStringGetCString( + theString: &CFString, + buffer: *mut c_char, + bufferSize: CFIndex, + encoding: CFStringEncoding) + -> bool; + + pub fn CFStringGetPascalStringPtr( + theString: &CFString, encoding: CFStringEncoding) + -> *const u8; + + pub fn CFStringGetCStringPtr( + theString: &CFString, encoding: CFStringEncoding) + -> *const c_char; + + pub fn CFStringGetCharactersPtr(theString: &CFString) -> *const u16; + + pub fn CFStringGetBytes( + theString: &CFString, + range: CFRange, + encoding: CFStringEncoding, + lossByte: u8, + isExternalRepresentation: bool, + buffer: *const u8, + maxBufLen: CFIndex, + usedBufLen: Option<&mut CFIndex>) + -> CFIndex; + + pub fn CFStringCreateFromExternalRepresentation( + alloc: Option<&'static CFAllocator>, + data: &CFData, + encoding: CFStringEncoding) + -> *const CFShared; + + pub fn CFStringCreateExternalRepresentation( + alloc: Option<&'static CFAllocator>, + theString: &CFString, + encoding: CFStringEncoding, + lossByte: u8) + -> *const CFShared; + + pub fn CFStringGetSmallestEncoding( + theString: &CFString) + -> CFStringEncoding; + + pub fn CFStringGetFastestEncoding(theString: &CFString) -> CFStringEncoding; + pub fn CFStringGetSystemEncoding() -> CFStringEncoding; + + pub fn CFStringGetMaximumSizeForEncoding( + length: CFIndex, encoding: CFStringEncoding) + -> CFIndex; + + pub fn CFStringGetFileSystemRepresentation( + string: &CFString, buffer: *mut c_char, maxBufLen: CFIndex) + -> bool; + + pub fn CFStringGetMaximumSizeOfFileSystemRepresentation( + string: &CFString) + -> CFIndex; + + pub fn CFStringCreateWithFileSystemRepresentation( + alloc: Option<&'static CFAllocator>, + buffer: *const c_char) + -> *const CFShared; + + pub fn CFStringCompareWithOptionsAndLocale( + theString1: &CFString, + theString2: &CFString, + rangeToCompare: CFRange, + compareOptions: CFStringCompareFlags, + locale: Option<&CFLocale>) + -> CFComparisonResult; + + pub fn CFStringCompareWithOptions( + theString1: &CFString, + theString2: &CFString, + rangeToCompare: CFRange, + compareOptions: CFStringCompareFlags) + -> CFComparisonResult; + + pub fn CFStringCompare( + theString1: &CFString, + theString2: &CFString, + compareOptions: CFStringCompareFlags) + -> CFComparisonResult; + + pub fn CFStringFindWithOptionsAndLocale( + theString: &CFString, + stringToFind: &CFString, + rangeToSearch: CFRange, + searchOptions: CFStringCompareFlags, + locale: &CFLocale, + result: Option<&mut CFRange>) + -> bool; + + pub fn CFStringFindWithOptions( + theString: &CFString, + stringToFind: &CFString, + rangeToSearch: CFRange, + searchOptions: CFStringCompareFlags, + result: Option<&mut CFRange>) + -> bool; + + pub fn CFStringCreateArrayWithFindResults( + allocator: Option<&'static CFAllocator>, + theString: &CFString, + stringToFind: &CFString, + rangeToSearch: CFRange, + compareOptions: CFStringCompareFlags) + -> *const CFShared; + + pub fn CFStringFind( + theString: &CFString, + stringToFind: &CFString, + compareOptions: CFStringCompareFlags) + -> CFRange; + + pub fn CFStringHasPrefix(theString: &CFString, prefix: &CFString) -> bool; + pub fn CFStringHasSuffix(theString: &CFString, suffix: &CFString) -> bool; + + pub fn CFStringGetRangeOfComposedCharactersAtIndex( + theString: &CFString, + theIndex: CFIndex) + -> CFRange; + + pub fn CFStringFindCharacterFromSet( + theString: &CFString, + theSet: &CFCharacterSet, + rangeToSearch: CFRange, + searchOptions: CFStringCompareFlags, + result: &mut CFRange) + -> bool; + + pub fn CFStringGetLineBounds( + theString: &CFString, + range: CFRange, + lineBeginIndex: &mut CFIndex, + lineEndIndex: &mut CFIndex, + contentsEndIndex: &mut CFIndex); + + pub fn CFStringGetParagraphBounds( + theString: &CFString, + range: CFRange, + parBeginIndex: &mut CFIndex, + parEndIndex: &mut CFIndex, + contentsEndIndex: &mut CFIndex); + + pub fn CFStringGetHyphenationLocationBeforeIndex( + string: &CFString, + location: CFIndex, + limitRange: CFRange, + options: CFOptionFlags, + locale: &CFLocale, + character: Option<&mut u32>) + -> CFIndex; + + pub fn CFStringIsHyphenationAvailableForLocale(locale: &CFLocale) -> bool; + + pub fn CFStringCreateByCombiningStrings( + alloc: Option<&'static CFAllocator>, + theArray: &CFArray, + separatorString: &CFString) + -> *const CFShared; + + pub fn CFStringCreateArrayBySeparatingStrings( + alloc: Option<&'static CFAllocator>, + theString: &CFString, + separatorString: &CFString) + -> *const CFShared; + + pub fn CFStringGetIntValue(str: &CFString) -> i32; + pub fn CFStringGetDoubleValue(str: &CFString) -> f64; + pub fn CFStringIsEncodingAvailable(encoding: CFStringEncoding) -> bool; + pub fn CFStringGetListOfAvailableEncodings() -> *const CFStringEncoding; + + pub fn CFStringGetNameOfEncoding( + encoding: CFStringEncoding) + -> *const CFShared; + + pub fn CFStringConvertEncodingToNSStringEncoding( + encoding: CFStringEncoding) + -> c_ulong; + + pub fn CFStringConvertNSStringEncodingToEncoding( + encoding: c_ulong) + -> CFStringEncoding; + + pub fn CFStringConvertEncodingToWindowsCodepage( + encoding: CFStringEncoding) + -> u32; + + pub fn CFStringConvertWindowsCodepageToEncoding( + codepage: u32) + -> CFStringEncoding; + + pub fn CFStringConvertIANACharSetNameToEncoding( + theString: &CFString) + -> CFStringEncoding; - /* Getting Paragraph Bounds */ - //fn CFStringGetParagraphBounds + pub fn CFStringConvertEncodingToIANACharSetName( + encoding: CFStringEncoding) + -> *const CFShared; - /* Managing Surrogates */ - //fn CFStringGetLongCharacterForSurrogatePair - //fn CFStringGetSurrogatePairForLongCharacter - //fn CFStringIsSurrogateHighCharacter - //fn CFStringIsSurrogateLowCharacter + pub fn CFStringGetMostCompatibleMacStringEncoding( + encoding: CFStringEncoding) + -> CFStringEncoding; } diff --git a/core-foundation-sys/src/sync.rs b/core-foundation-sys/src/sync.rs new file mode 100644 index 0000000..bf604c0 --- /dev/null +++ b/core-foundation-sys/src/sync.rs @@ -0,0 +1,157 @@ +// Copyright 2013-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Encodes the Core Foundation refcounting machinery with Rust types. + +use base::{CFRelease, CFRetain, CFType}; +use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::ops::Deref; + +#[repr(C)] +pub struct CFRef { ptr: *const CFShared } + +impl CFRef { + #[inline] + pub unsafe fn from_retained(retained: *const CFShared) -> Self { + assert!(!retained.is_null()); + CFRef { ptr: retained } + } + + #[inline] + pub unsafe fn try_from_retained( + retained: *const CFShared) + -> Result { + if !retained.is_null() { + Ok(CFRef { ptr: retained }) + } else { + Err(()) + } + } +} + +impl Clone for CFRef { + #[inline] + fn clone(&self) -> Self { + self.retain() + } +} + +impl Deref for CFRef { + type Target = CFShared; + + #[inline] + fn deref(&self) -> &CFShared { + unsafe { &*self.ptr } + } +} + +impl Drop for CFRef { + #[inline] + fn drop(&mut self) { + unsafe { CFRelease(self.as_object()) } + } +} + +impl fmt::Debug for CFRef { + #[inline] + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + (&**self).fmt(formatter) + } +} + +impl Hash for CFRef { + #[inline] + fn hash(&self, state: &mut H) { + self.as_object().hash(state) + } +} + +impl Eq for CFRef {} + +impl PartialEq for CFRef { + #[inline] + fn eq(&self, other: &Self) -> bool { + (&**self).eq(&**other) + } +} + +impl Ord for CFRef { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + (&**self).cmp(&**other) + } +} + +impl PartialOrd for CFRef { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + (&**self).partial_cmp(&**other) + } +} + +unsafe impl Send for CFRef {} +unsafe impl Sync for CFRef {} + +#[repr(C)] +pub struct CFShared { contents: T } + +impl CFShared { + #[inline] + pub fn retain(&self) -> CFRef { + unsafe { + let ptr = CFRetain(&*(self as *const _ as *const _)); + assert!(!ptr.is_null()); + CFRef { ptr: ptr as *const _ as *const _ } + } + } +} + +impl Deref for CFShared { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + &self.contents + } +} + +impl fmt::Debug for CFShared { + #[inline] + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + (&**self).fmt(formatter) + } +} + +impl Eq for CFShared {} + +impl PartialEq for CFShared { + #[inline] + fn eq(&self, other: &Self) -> bool { + (&**self).eq(&**other) + } +} + +impl Ord for CFShared { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + (&**self).cmp(&**other) + } +} + +impl PartialOrd for CFShared { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + (&**self).partial_cmp(&**other) + } +} + +unsafe impl Send for CFShared {} +unsafe impl Sync for CFShared {} diff --git a/core-foundation-sys/src/date.rs b/core-foundation-sys/src/time.rs similarity index 67% rename from core-foundation-sys/src/date.rs rename to core-foundation-sys/src/time.rs index c6cac2d..d781560 100644 --- a/core-foundation-sys/src/date.rs +++ b/core-foundation-sys/src/time.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 CFAbsoluteTime; } diff --git a/core-foundation-sys/src/url.rs b/core-foundation-sys/src/url.rs index 443f893..766fea0 100644 --- a/core-foundation-sys/src/url.rs +++ b/core-foundation-sys/src/url.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use libc::c_void; -use base::{CFOptionFlags, CFIndex, CFAllocatorRef, Boolean, CFTypeID}; -use string::CFStringRef; +use allocator::CFAllocator; +use array::CFArray; +use base::{CFDowncast, CFIndex, CFObject, CFOptionFlags, CFRange, CFType}; +use base::{CFTypeID, FromCFIndex, IntoCFIndex}; +use data::CFData; +use dictionary::CFDictionary; +use error::{CFError, CFErrorRef}; +use std::ops::Range; +use std::os::raw::c_void; +use std::ptr; +use string::{CFString, CFStringBuiltInEncodings, CFStringEncoding, CFStringRef}; +use sync::{CFShared, CFRef}; + +pub type CFURLRef = CFRef; #[repr(C)] -pub struct __CFURL(c_void); +pub struct CFURL { obj: CFObject } + +unsafe impl Send for CFURL {} +unsafe impl Sync for CFURL {} + +unsafe impl CFType for CFURL { + #[inline] + fn as_object(&self) -> &CFObject { + &self.obj + } +} + +unsafe impl CFDowncast for CFURL { + #[inline] + fn type_id() -> CFTypeID { + unsafe { CFURLGetTypeID() } + } +} + +impl CFURL { + #[inline] + pub fn from_str( + input: &str, base: Option<&CFURL>) + -> Result { + unsafe { + CFRef::try_from_retained( + CFURLCreateWithBytes( + None, + input.as_bytes().as_ptr(), + input.len().into_index(), + CFStringBuiltInEncodings::UTF8 as u32, + base)) + } + } + + #[inline] + pub fn from_string( + input: &CFString, base: Option<&CFURL>) + -> Result { + unsafe { + CFRef::try_from_retained(CFURLCreateWithString(None, input, base)) + } + } + + #[inline] + pub fn from_file_system_path( + path: &CFString, + path_style: CFURLPathStyle, + is_directory: bool) + -> Result { + unsafe { + CFRef::try_from_retained( + CFURLCreateWithFileSystemPath( + None, path, path_style, is_directory)) + } + } + + #[inline] + pub fn to_absolute(&self) -> Result { + unsafe { + CFRef::try_from_retained(CFURLCopyAbsoluteURL(self)) + } + } + + #[inline] + pub fn as_string(&self) -> &CFShared { + unsafe { CFURLGetString(self).unwrap() } + } + + #[inline] + pub fn base(&self) -> Option<&CFShared> { + unsafe { CFURLGetBaseURL(self) } + } + + #[inline] + pub fn can_be_decomposed(&self) -> bool { + unsafe { CFURLCanBeDecomposed(self) } + } + + #[inline] + pub fn scheme(&self) -> Option { + unsafe { CFRef::try_from_retained(CFURLCopyScheme(self)).ok() } + } + + #[inline] + pub fn net_location(&self) -> Option { + unsafe { CFRef::try_from_retained(CFURLCopyNetLocation(self)).ok() } + } + + #[inline] + pub fn path(&self) -> Option { + unsafe { CFRef::try_from_retained(CFURLCopyPath(self)).ok() } + } + + #[inline] + pub fn strict_path(&self) -> (bool, Option) { + unsafe { + let mut is_absolute = false; + let result = + CFRef::try_from_retained( + CFURLCopyStrictPath(self, Some(&mut is_absolute))); + (is_absolute, result.ok()) + } + } + + #[inline] + pub fn file_system_path( + &self, path_style: CFURLPathStyle) + -> Option { + unsafe { + let result = CFRef::try_from_retained( + CFURLCopyFileSystemPath(self, path_style)); + result.ok() + } + } + + #[inline] + pub fn has_directory_path(&self) -> bool { + unsafe { CFURLHasDirectoryPath(self) } + } + + #[inline] + pub fn resource_specifier(&self) -> Option { + unsafe { + CFRef::try_from_retained(CFURLCopyResourceSpecifier(self)).ok() + } + } + + #[inline] + pub fn host(&self) -> Option { + unsafe { CFRef::try_from_retained(CFURLCopyHostName(self)).ok() } + } + + #[inline] + pub fn port(&self) -> Option { + let result = unsafe { CFURLGetPortNumber(self) }; + if result >= 0 { + assert!(result <= u16::max_value() as i32); + Some(result as u16) + } else { + None + } + } + + #[inline] + pub fn username(&self) -> Option { + let result = unsafe { + CFRef::try_from_retained(CFURLCopyUserName(self)).ok() + }; + if result.as_ref().map_or(true, |str| str.is_empty()) { + return None; + } + result + } -pub type CFURLRef = *const __CFURL; + #[inline] + pub fn password(&self) -> Option { + let result = unsafe { + CFRef::try_from_retained(CFURLCopyPassword(self)).ok() + }; + if result.as_ref().map_or(true, |str| str.is_empty()) { + return None; + } + result + } -pub type CFURLBookmarkCreationOptions = CFOptionFlags; + #[inline] + pub fn parameters( + &self, characters_to_leave_escaped: Option<&CFString>) + -> Option { + unsafe { + let result = + CFURLCopyParameterString(self, characters_to_leave_escaped); + CFRef::try_from_retained(result).ok() + } + } -pub type CFURLPathStyle = CFIndex; + #[inline] + pub fn query( + &self, characters_to_leave_escaped: Option<&CFString>) + -> Option { + unsafe { + let result = + CFURLCopyQueryString(self, characters_to_leave_escaped); + CFRef::try_from_retained(result).ok() + } + } -/* typedef CF_ENUM(CFIndex, CFURLPathStyle) */ -pub const kCFURLPOSIXPathStyle: CFURLPathStyle = 0; -pub const kCFURLHFSPathStyle: CFURLPathStyle = 1; -pub const kCFURLWindowsPathStyle: CFURLPathStyle = 2; + #[inline] + pub fn fragment( + &self, characters_to_leave_escaped: Option<&CFString>) + -> Option { + unsafe { + let result = CFURLCopyFragment(self, characters_to_leave_escaped); + CFRef::try_from_retained(result).ok() + } + } -// static kCFURLBookmarkCreationPreferFileIDResolutionMask: CFURLBookmarkCreationOptions = -// (1 << 8) as u32; -// static kCFURLBookmarkCreationMinimalBookmarkMask: CFURLBookmarkCreationOptions = -// (1 << 9) as u32; -// static kCFURLBookmarkCreationSuitableForBookmarkFile: CFURLBookmarkCreationOptions = -// (1 << 10) as u32; -// static kCFURLBookmarkCreationWithSecurityScope: CFURLBookmarkCreationOptions = -// (1 << 11) as u32; -// static kCFURLBookmarkCreationSecurityScopeAllowOnlyReadAccess: CFURLBookmarkCreationOptions = -// (1 << 12) as u32; + #[inline] + pub fn last_path_component(&self) -> CFStringRef { + unsafe { CFRef::from_retained(CFURLCopyLastPathComponent(self)) } + } -// TODO: there are a lot of missing keys and constants. Add if you are bored or need them. + #[inline] + pub fn path_extension(&self) -> Option { + unsafe { CFRef::try_from_retained(CFURLCopyPathExtension(self)).ok() } + } + + #[inline] + pub fn with_path_component( + &self, path_component: &CFString, is_directory: bool) + -> Result { + unsafe { + CFRef::try_from_retained( + CFURLCreateCopyAppendingPathComponent( + None, self, path_component, is_directory)) + } + } + + #[inline] + pub fn without_last_path_component(&self) -> Result { + unsafe { + CFRef::try_from_retained( + CFURLCreateCopyDeletingLastPathComponent(None, self)) + } + } + + #[inline] + pub fn with_path_extension( + &self, extension: &CFString) -> + Result { + unsafe { + CFRef::try_from_retained( + CFURLCreateCopyAppendingPathExtension(None, self, extension)) + } + } + + #[inline] + pub fn without_path_extension(&self) -> Result { + unsafe { + CFRef::try_from_retained( + CFURLCreateCopyDeletingPathExtension(None, self)) + } + } + + pub fn to_vec(&self) -> Vec { + unsafe { + let output_len = CFURLGetBytes(self, ptr::null_mut(), 0); + let mut output = vec![0; usize::from_index(output_len)]; + let wrote = CFURLGetBytes(self, output.as_mut_ptr(), output_len); + assert_eq!(wrote, output_len); + output + } + } + + #[inline] + pub fn component_range( + &self, component: CFURLComponentType) + -> Result<(Range, Range), Range> { + let mut range_including_separators = CFRange::default(); + let range = unsafe { + CFURLGetByteRangeForComponent( + self, component, Some(&mut range_including_separators)) + }; + if range.location >= 0 { + Ok((range.into(), range_including_separators.into())) + } else { + Err(range_including_separators.into()) + } + } + + #[inline] + pub fn percent_decode( + input: &CFString, characters_to_leave_escaped: Option<&CFString>) + -> Result { + unsafe { + CFRef::try_from_retained( + CFURLCreateStringByReplacingPercentEscapes( + None, input, characters_to_leave_escaped)) + } + } + + #[inline] + pub fn to_file_reference_url( + &self) + -> Result { + unsafe { + let mut error = ptr::null(); + let result = + CFURLCreateFileReferenceURL(None, self, Some(&mut error)); + CFRef::try_from_retained(result) + .map_err(|()| CFRef::from_retained(error)) + } + } + + #[inline] + pub fn to_file_path_url(&self) -> Result { + unsafe { + let mut error = ptr::null(); + let result = + CFURLCreateFilePathURL(None, self, Some(&mut error)); + CFRef::try_from_retained(result) + .map_err(|()| CFRef::from_retained(error)) + } + } +} + +impl<'a> From<&'a CFURL> for Vec { + fn from(input: &'a CFURL) -> Self { + input.to_vec() + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[repr(i64)] +pub enum CFURLPathStyle { + POSIX = 0, + HFS = 1, + Windows = 2, +} + +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[repr(i64)] +pub enum CFURLComponentType { + Scheme = 1, + NetLocation = 2, + Path = 3, + ResourceSpecifier = 4, + User = 5, + Password = 6, + UserInfo = 7, + Host = 8, + Port = 9, + ParameterString = 10, + Query = 11, + Fragment = 12, +} + +bitflags! { + #[repr(C)] + pub flags CFURLBookmarkCreationOptions: CFOptionFlags { + const CREATE_MINIMAL_BOOKMARK_MASK = 1 << 9, + const CREATE_SUITABLE_FOR_BOOKMARK_FILE = 1 << 10, + const CREATE_WITH_SECURITY_SCOPE = 1 << 11, + const CREATE_SECURITY_SCOPE_ALLOW_ONLY_READ_ACCESS = 1 << 12, + } +} + +bitflags! { + #[repr(C)] + pub flags CFURLBookmarkResolutionOptions: CFOptionFlags { + const RESOLVE_WITHOUT_UI_MASK = 1 << 8, + const RESOLVE_WITHOUT_MOUNTING_MASK = 1 << 9, + const RESOLVE_WITH_SECURITY_SCOPE = 1 << 10, + } +} + +pub type CFURLBookmarkFileCreationOptions = CFOptionFlags; + +#[test] +fn test_file_url_from_path() { + let path = "/usr/local/foo/"; + let url = CFURL::from_file_system_path( + &CFString::from_static_str(path), CFURLPathStyle::POSIX, true); + assert_eq!( + url.unwrap().as_string().to_string(), + Ok("file:///usr/local/foo/".to_owned())); +} extern { - /* - * CFURL.h - */ - - /* Common File System Resource Keys */ - // static kCFURLAttributeModificationDateKey: CFStringRef; - // static kCFURLContentAccessDateKey: CFStringRef; - // static kCFURLContentModificationDateKey: CFStringRef; - // static kCFURLCreationDateKey: CFStringRef; - // static kCFURLCustomIconKey: CFStringRef; - // static kCFURLEffectiveIconKey: CFStringRef; - // static kCFURLFileResourceIdentifierKey: CFStringRef; - // static kCFURLFileSecurityKey: CFStringRef; - // static kCFURLHasHiddenExtensionKey: CFStringRef; - // static kCFURLIsDirectoryKey: CFStringRef; - // static kCFURLIsExecutableKey: CFStringRef; - // static kCFURLIsHiddenKey: CFStringRef; - // static kCFURLIsPackageKey: CFStringRef; - // static kCFURLIsReadableKey: CFStringRef; - // static kCFURLIsRegularFileKey: CFStringRef; - // static kCFURLIsSymbolicLinkKey: CFStringRef; - // static kCFURLIsSystemImmutableKey: CFStringRef; - // static kCFURLIsUserImmutableKey: CFStringRef; - // static kCFURLIsVolumeKey: CFStringRef; - // static kCFURLIsWritableKey: CFStringRef; - // static kCFURLLabelColorKey: CFStringRef; - // static kCFURLLabelNumberKey: CFStringRef; - // static kCFURLLinkCountKey: CFStringRef; - // static kCFURLLocalizedLabelKey: CFStringRef; - // static kCFURLLocalizedNameKey: CFStringRef; - // static kCFURLLocalizedTypeDescriptionKey: CFStringRef; - // static kCFURLNameKey: CFStringRef; - // static kCFURLParentDirectoryURLKey: CFStringRef; - // static kCFURLPreferredIOBlockSizeKey: CFStringRef; - // static kCFURLTypeIdentifierKey: CFStringRef; - // static kCFURLVolumeIdentifierKey: CFStringRef; - // static kCFURLVolumeURLKey: CFStringRef; - // static kCFURLIsExcludedFromBackupKey: CFStringRef; - // static kCFURLFileResourceTypeKey: CFStringRef; - - /* Creating a CFURL */ - //fn CFURLCopyAbsoluteURL - //fn CFURLCreateAbsoluteURLWithBytes - //fn CFURLCreateByResolvingBookmarkData - //fn CFURLCreateCopyAppendingPathComponent - //fn CFURLCreateCopyAppendingPathExtension - //fn CFURLCreateCopyDeletingLastPathComponent - //fn CFURLCreateCopyDeletingPathExtension - //fn CFURLCreateFilePathURL - //fn CFURLCreateFileReferenceURL - //fn CFURLCreateFromFileSystemRepresentation - //fn CFURLCreateFromFileSystemRepresentationRelativeToBase - //fn CFURLCreateFromFSRef - //fn CFURLCreateWithBytes - //fn CFURLCreateWithFileSystemPath - pub fn CFURLCreateWithFileSystemPath(allocator: CFAllocatorRef, filePath: CFStringRef, pathStyle: CFURLPathStyle, isDirectory: Boolean) -> CFURLRef; - //fn CFURLCreateWithFileSystemPathRelativeToBase - //fn CFURLCreateWithString(allocator: CFAllocatorRef, urlString: CFStringRef, - // baseURL: CFURLRef) -> CFURLRef; - - /* Accessing the Parts of a URL */ - //fn CFURLCanBeDecomposed - //fn CFURLCopyFileSystemPath - //fn CFURLCopyFragment - //fn CFURLCopyHostName - //fn CFURLCopyLastPathComponent - //fn CFURLCopyNetLocation - //fn CFURLCopyParameterString - //fn CFURLCopyPassword - //fn CFURLCopyPath - //fn CFURLCopyPathExtension - //fn CFURLCopyQueryString - //fn CFURLCopyResourceSpecifier - //fn CFURLCopyScheme - //fn CFURLCopyStrictPath - //fn CFURLCopyUserName - //fn CFURLGetPortNumber - //fn CFURLHasDirectoryPath - - /* Converting URLs to Other Representations */ - //fn CFURLCreateData(allocator: CFAllocatorRef, url: CFURLRef, - // encoding: CFStringEncoding, escapeWhitespace: bool) -> CFDataRef; - //fn CFURLCreateStringByAddingPercentEscapes - //fn CFURLCreateStringByReplacingPercentEscapes - //fn CFURLCreateStringByReplacingPercentEscapesUsingEncoding - //fn CFURLGetFileSystemRepresentation - //fn CFURLGetFSRef - pub fn CFURLGetString(anURL: CFURLRef) -> CFStringRef; - - /* Getting URL Properties */ - //fn CFURLGetBaseURL(anURL: CFURLRef) -> CFURLRef; - //fn CFURLGetBytes - //fn CFURLGetByteRangeForComponent pub fn CFURLGetTypeID() -> CFTypeID; - //fn CFURLResourceIsReachable - - /* Getting and Setting File System Resource Properties */ - //fn CFURLClearResourcePropertyCache - //fn CFURLClearResourcePropertyCacheForKey - //fn CFURLCopyResourcePropertiesForKeys - //fn CFURLCopyResourcePropertyForKey - //fn CFURLCreateResourcePropertiesForKeysFromBookmarkData - //fn CFURLCreateResourcePropertyForKeyFromBookmarkData - //fn CFURLSetResourcePropertiesForKeys - //fn CFURLSetResourcePropertyForKey - //fn CFURLSetTemporaryResourcePropertyForKey - - /* Working with Bookmark Data */ - //fn CFURLCreateBookmarkData - //fn CFURLCreateBookmarkDataFromAliasRecord - //fn CFURLCreateBookmarkDataFromFile - //fn CFURLWriteBookmarkDataToFile - //fn CFURLStartAccessingSecurityScopedResource - //fn CFURLStopAccessingSecurityScopedResource + + pub fn CFURLCreateWithBytes( + allocator: Option<&'static CFAllocator>, + URLBytes: *const u8, + length: CFIndex, + encoding: CFStringEncoding, + baseURL: Option<&CFURL>) + -> *const CFShared; + + pub fn CFURLCreateData( + allocator: Option<&'static CFAllocator>, + url: &CFURL, + encoding: CFStringEncoding, + escapeWhitespace: bool) + -> *const CFShared; + + pub fn CFURLCreateWithString( + allocator: Option<&'static CFAllocator>, + URLString: &CFString, + baseURL: Option<&CFURL>) + -> *const CFShared; + + pub fn CFURLCreateAbsoluteURLWithBytes( + alloc: Option<&'static CFAllocator>, + relativeURLBytes: *const u8, + length: CFIndex, + encoding: CFStringEncoding, + baseURL: Option<&CFURL>, + useCompatibilityMode: bool) + -> *const CFShared; + + pub fn CFURLCreateWithFileSystemPath( + allocator: Option<&'static CFAllocator>, + filePath: &CFString, + pathStyle: CFURLPathStyle, + isDirectory: bool) + -> *const CFShared; + + pub fn CFURLCreateFromFileSystemRepresentation( + allocator: Option<&'static CFAllocator>, + buffer: *const u8, + bufLen: CFIndex, + isDirectory: bool) + -> *const CFShared; + + pub fn CFURLCreateWithFileSystemPathRelativeToBase( + allocator: Option<&'static CFAllocator>, + filePath: &CFString, + pathStyle: CFURLPathStyle, + isDirectory: bool, + baseURL: Option<&CFURL>) + -> *const CFShared; + + pub fn CFURLCreateFromFileSystemRepresentationRelativeToBase( + allocator: Option<&'static CFAllocator>, + buffer: *const u8, + bufLen: CFIndex, + isDirectory: bool, + baseURL: Option<&CFURL>) + -> *const CFShared; + + pub fn CFURLGetFileSystemRepresentation( + url: &CFURL, + resolveAgainstBase: bool, + buffer: *mut u8, + maxBufLen: CFIndex) + -> bool; + + pub fn CFURLCopyAbsoluteURL(relativeURL: &CFURL) -> *const CFShared; + pub fn CFURLGetString(anURL: &CFURL) -> Option<&CFShared>; + pub fn CFURLGetBaseURL(anURL: &CFURL) -> Option<&CFShared>; + pub fn CFURLCanBeDecomposed(anURL: &CFURL) -> bool; + pub fn CFURLCopyScheme(anURL: &CFURL) -> *const CFShared; + pub fn CFURLCopyNetLocation(anURL: &CFURL) -> *const CFShared; + pub fn CFURLCopyPath(anURL: &CFURL) -> *const CFShared; + + pub fn CFURLCopyStrictPath( + anURL: &CFURL, isAbsolute: Option<&mut bool>) + -> *const CFShared; + + pub fn CFURLCopyFileSystemPath( + anURL: &CFURL, pathStyle: CFURLPathStyle) + -> *const CFShared; + + pub fn CFURLHasDirectoryPath(anURL: &CFURL) -> bool; + + pub fn CFURLCopyResourceSpecifier( + anURL: &CFURL) + -> *const CFShared; + + pub fn CFURLCopyHostName(anURL: &CFURL) -> *const CFShared; + pub fn CFURLGetPortNumber(anURL: &CFURL) -> i32; + pub fn CFURLCopyUserName(anURL: &CFURL) -> *const CFShared; + pub fn CFURLCopyPassword(anURL: &CFURL) -> *const CFShared; + + pub fn CFURLCopyParameterString( + anURL: &CFURL, charactersToLeaveEscaped: Option<&CFString>) + -> *const CFShared; + + pub fn CFURLCopyQueryString( + anURL: &CFURL, charactersToLeaveEscaped: Option<&CFString>) + -> *const CFShared; + + pub fn CFURLCopyFragment( + anURL: &CFURL, charactersToLeaveEscaped: Option<&CFString>) + -> *const CFShared; + + pub fn CFURLCopyLastPathComponent( + anURL: &CFURL) + -> *const CFShared; + + pub fn CFURLCopyPathExtension(anURL: &CFURL) -> *const CFShared; + + pub fn CFURLCreateCopyAppendingPathComponent( + allocator: Option<&'static CFAllocator>, + url: &CFURL, + pathComponent: &CFString, + isDirectory: bool) + -> *const CFShared; + + pub fn CFURLCreateCopyDeletingLastPathComponent( + allocator: Option<&'static CFAllocator>, url: &CFURL) + -> *const CFShared; + + pub fn CFURLCreateCopyAppendingPathExtension( + allocator: Option<&'static CFAllocator>, + url: &CFURL, + extension: &CFString) + -> *const CFShared; + + pub fn CFURLCreateCopyDeletingPathExtension( + allocator: Option<&'static CFAllocator>, url: &CFURL) + -> *const CFShared; + + pub fn CFURLGetBytes( + url: &CFURL, buffer: *const u8, bufferLength: CFIndex) + -> CFIndex; + + pub fn CFURLGetByteRangeForComponent( + url: &CFURL, + component: CFURLComponentType, + rangeIncludingSeparators: Option<&mut CFRange>) + -> CFRange; + + pub fn CFURLCreateStringByReplacingPercentEscapes( + allocator: Option<&'static CFAllocator>, + originalString: &CFString, + charactersToLeaveEscaped: Option<&CFString>) + -> *const CFShared; + + pub fn CFURLCreateFileReferenceURL( + allocator: Option<&'static CFAllocator>, + url: &CFURL, + error: Option<&mut *const CFShared>) + -> *const CFShared; + + pub fn CFURLCreateFilePathURL( + allocator: Option<&'static CFAllocator>, + url: &CFURL, + error: Option<&mut *const CFShared>) + -> *const CFShared; + + pub fn CFURLCopyResourcePropertyForKey( + url: &CFURL, + key: &CFString, + propertyValueTypeRefPtr: *mut c_void, + error: Option<&mut *const CFShared>) + -> *const CFShared; + + pub fn CFURLCopyResourcePropertiesForKeys( + url: &CFURL, + keys: &CFArray, + error: Option<&mut *const CFShared>) + -> *const CFShared; + + pub fn CFURLSetResourcePropertyForKey( + url: &CFURL, + key: &CFString, + propertyValue: &CFShared, + error: Option<&mut *const CFShared>) + -> bool; + + pub fn CFURLSetResourcePropertiesForKeys( + url: &CFURL, + keyedPropertyValues: &CFDictionary, + error: Option<&mut *const CFShared>) + -> bool; + + pub static kCFURLKeysOfUnsetValuesKey: Option<&'static CFShared>; + + pub fn CFURLClearResourcePropertyCacheForKey(url: &CFURL, key: &CFString); + pub fn CFURLClearResourcePropertyCache(url: &CFURL); + + pub fn CFURLSetTemporaryResourcePropertyForKey( + url: &CFURL, key: &CFString, propertyValue: &CFShared); + + pub fn CFURLResourceIsReachable( + url: &CFURL, error: Option<&mut *const CFShared>) + -> bool; + + pub fn CFURLCreateBookmarkData( + allocator: Option<&'static CFAllocator>, + url: &CFURL, + options: CFURLBookmarkCreationOptions, + resourcePropertiesToInclude: &CFArray, + relativeToURL: Option<&CFURL>, + error: Option<&mut *const CFShared>) + -> *const CFShared; + + pub fn CFURLCreateByResolvingBookmarkData( + allocator: Option<&'static CFAllocator>, + bookmark: &CFData, + options: CFURLBookmarkResolutionOptions, + relativeToURL: Option<&CFURL>, + resourcePropertiesToInclude: Option<&CFArray>, + isStale: &mut bool, + error: Option<&mut *const CFShared>) + -> *const CFShared; + + pub fn CFURLCreateResourcePropertiesForKeysFromBookmarkData( + allocator: Option<&'static CFAllocator>, + resourcePropertiesToReturn: &CFArray, + bookmark: &CFData) + -> *const CFShared; + + pub fn CFURLCreateResourcePropertyForKeyFromBookmarkData( + allocator: Option<&'static CFAllocator>, + resourcePropertyKey: &CFString, + bookmark: &CFData) + -> *const CFShared; + + pub fn CFURLCreateBookmarkDataFromFile( + allocator: Option<&'static CFAllocator>, + fileURL: &CFURL, + error: Option<&mut *const CFShared>) + -> *const CFShared; + + pub fn CFURLWriteBookmarkDataToFile( + bookmarkRef: &CFData, + fileURL: &CFURL, + options: CFURLBookmarkFileCreationOptions, + error: Option<&mut *const CFShared>) + -> bool; + + pub fn CFURLCreateBookmarkDataFromAliasRecord( + allocatorRef: Option<&'static CFAllocator>, + aliasRecordDataRef: &CFData) + -> *const CFShared; + + pub fn CFURLStartAccessingSecurityScopedResource(url: &CFURL) -> bool; + pub fn CFURLStopAccessingSecurityScopedResource(url: &CFURL); } diff --git a/core-foundation-sys/src/version.rs b/core-foundation-sys/src/version.rs new file mode 100644 index 0000000..8f8282f --- /dev/null +++ b/core-foundation-sys/src/version.rs @@ -0,0 +1,58 @@ +// Copyright 2013-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Structures for the various versioned types throughout CF. + +use base::CFIndex; + +/// Represents version 0. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[repr(C)] +pub struct CFVersion0 { version: CFIndex } + +impl CFVersion0 { + /// Creates a new `CFVersion0`. + #[inline] + pub fn new() -> Self { + CF_VERSION_0 + } +} + +impl Default for CFVersion0 { + #[inline] + fn default() -> Self { + CF_VERSION_0 + } +} + +/// Constant for version 0, to be used in constant expressions. +pub const CF_VERSION_0: CFVersion0 = CFVersion0 { version: 0 }; + +/// Represents version 1. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[repr(C)] +pub struct CFVersion1 { version: CFIndex } + +impl CFVersion1 { + /// Creates a new `CFVersion1`. + #[inline] + pub fn new() -> Self { + CF_VERSION_1 + } +} + +/// Constant for version 1, to be used in constant expressions. +pub const CF_VERSION_1: CFVersion1 = CFVersion1 { version: 1 }; + +impl Default for CFVersion1 { + #[inline] + fn default() -> Self { + CF_VERSION_1 + } +} diff --git a/core-foundation/Cargo.toml b/core-foundation/Cargo.toml index 95b96d4..8fc7978 100644 --- a/core-foundation/Cargo.toml +++ b/core-foundation/Cargo.toml @@ -9,7 +9,4 @@ license = "MIT / Apache-2.0" [dependencies.core-foundation-sys] path = "../core-foundation-sys" -version = "0.2.2" - -[dependencies] -libc = "0.2" +version = "0.3.0" diff --git a/core-foundation/src/array.rs b/core-foundation/src/array.rs index cb9016d..e15bf61 100644 --- a/core-foundation/src/array.rs +++ b/core-foundation/src/array.rs @@ -9,124 +9,4 @@ //! Heterogeneous immutable arrays. -pub use core_foundation_sys::array::*; -pub use core_foundation_sys::base::{CFIndex, CFRelease}; -use core_foundation_sys::base::{CFTypeRef, kCFAllocatorDefault}; -use libc::c_void; -use std::mem; - -use base::{CFIndexConvertible, TCFType}; - -/// A heterogeneous immutable array. -pub struct CFArray(CFArrayRef); - -impl Drop for CFArray { - fn drop(&mut self) { - unsafe { - CFRelease(self.as_CFTypeRef()) - } - } -} - -pub struct CFArrayIterator<'a> { - array: &'a CFArray, - index: CFIndex, -} - -impl<'a> Iterator for CFArrayIterator<'a> { - type Item = *const c_void; - - fn next(&mut self) -> Option<*const c_void> { - if self.index >= self.array.len() { - None - } else { - let value = self.array.get(self.index); - self.index += 1; - Some(value) - } - } -} - -impl_TCFType!(CFArray, CFArrayRef, CFArrayGetTypeID); - -impl CFArray { - /// Creates a new `CFArray` with the given elements, which must be `CFType` objects. - pub fn from_CFTypes(elems: &[T]) -> CFArray where T: TCFType { - unsafe { - let elems: Vec = elems.iter().map(|elem| elem.as_CFTypeRef()).collect(); - let array_ref = CFArrayCreate(kCFAllocatorDefault, - mem::transmute(elems.as_ptr()), - elems.len().to_CFIndex(), - &kCFTypeArrayCallBacks); - TCFType::wrap_under_create_rule(array_ref) - } - } - - /// 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> { - CFArrayIterator { - array: self, - index: 0 - } - } - - #[inline] - pub fn len(&self) -> CFIndex { - unsafe { - CFArrayGetCount(self.0) - } - } - - #[inline] - pub fn get(&self, index: CFIndex) -> *const c_void { - assert!(index < self.len()); - unsafe { - CFArrayGetValueAtIndex(self.0, index) - } - } -} - -impl<'a> IntoIterator for &'a CFArray { - type Item = *const c_void; - type IntoIter = CFArrayIterator<'a>; - - fn into_iter(self) -> CFArrayIterator<'a> { - self.iter() - } -} - -#[test] -fn should_box_and_unbox() { - use number::{CFNumber, number}; - - let arr = CFArray::from_CFTypes(&[ - number(1).as_CFType(), - number(2).as_CFType(), - number(3).as_CFType(), - number(4).as_CFType(), - number(5).as_CFType(), - ]); - - unsafe { - let mut sum = 0; - - for elem in arr.iter() { - let number: CFNumber = TCFType::wrap_under_get_rule(mem::transmute(elem)); - sum += number.to_i64().unwrap() - } - - assert!(sum == 15); - - for elem in arr.iter() { - let number: CFNumber = TCFType::wrap_under_get_rule(mem::transmute(elem)); - sum += number.to_i64().unwrap() - } - - assert!(sum == 30); - } -} +pub use core_foundation_sys::array::{CFArray, CFArrayRef}; diff --git a/core-foundation/src/base.rs b/core-foundation/src/base.rs index 3f4bcea..7a21be0 100644 --- a/core-foundation/src/base.rs +++ b/core-foundation/src/base.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 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 - } -} - -/// Superclass of all Core Foundation objects. -pub struct CFType(CFTypeRef); - -impl Clone for CFType { - #[inline] - fn clone(&self) -> CFType { - unsafe { - TCFType::wrap_under_get_rule(self.0) - } - } -} - -impl Drop for CFType { - fn drop(&mut self) { - unsafe { - CFRelease(self.0) - } - } -} - -/// All Core Foundation types implement this trait. The type parameter `TypeRef` specifies the -/// associated Core Foundation type: e.g. for `CFType` this is `CFTypeRef`; for `CFArray` this is -/// `CFArrayRef`. -pub trait TCFType { - /// Returns the object as its concrete TypeRef. - fn as_concrete_TypeRef(&self) -> ConcreteTypeRef; - - /// 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: ConcreteTypeRef) -> 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 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: ConcreteTypeRef) -> 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>(&self) -> bool { - self.type_of() == >::type_id() - } -} - -impl TCFType for CFType { - #[inline] - fn as_concrete_TypeRef(&self) -> CFTypeRef { - self.0 - } - - #[inline] - unsafe fn wrap_under_get_rule(reference: CFTypeRef) -> CFType { - 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 { - CFType(obj) - } - - #[inline] - fn type_id() -> CFTypeID { - // FIXME(pcwalton): Is this right? - 0 - } - - #[inline] - fn instance_of>(&self) -> bool { - // Since this is the root of the type hierarchy, we always answer yes. - true - } -} +pub use core_foundation_sys::base::{CFDowncast, CFObject, CFObjectRef, CFType}; diff --git a/core-foundation/src/boolean.rs b/core-foundation/src/boolean.rs index 8e6ca3b..dbea9fd 100644 --- a/core-foundation/src/boolean.rs +++ b/core-foundation/src/boolean.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 CFBoolean { - unsafe { - TCFType::wrap_under_get_rule(kCFBooleanTrue) - } - } - - pub fn false_value() -> CFBoolean { - unsafe { - TCFType::wrap_under_get_rule(kCFBooleanFalse) - } - } -} +pub use core_foundation_sys::boolean::{CFBoolean, CFBooleanRef}; diff --git a/core-foundation/src/bundle.rs b/core-foundation/src/bundle.rs index 8344225..1265e40 100644 --- a/core-foundation/src/bundle.rs +++ b/core-foundation/src/bundle.rs @@ -9,38 +9,4 @@ //! Core Foundation Bundle Type -pub use core_foundation_sys::bundle::*; -use core_foundation_sys::base::CFRelease; - -use base::{TCFType}; -use dictionary::CFDictionary; - -/// A Bundle type. -pub struct CFBundle(CFBundleRef); - -impl Drop for CFBundle { - fn drop(&mut self) { - unsafe { - CFRelease(self.as_CFTypeRef()) - } - } -} - -impl CFBundle { - pub fn main_bundle() -> CFBundle { - unsafe { - let bundle_ref = CFBundleGetMainBundle(); - TCFType::wrap_under_get_rule(bundle_ref) - } - } - - pub fn info_dictionary(&self) -> CFDictionary { - unsafe { - let info_dictionary = CFBundleGetInfoDictionary(self.0); - TCFType::wrap_under_get_rule(info_dictionary) - } - } -} - -impl_TCFType!(CFBundle, CFBundleRef, CFBundleGetTypeID); - +pub use core_foundation_sys::bundle::{CFBundle, CFBundleRef}; diff --git a/core-foundation/src/data.rs b/core-foundation/src/data.rs index 7d83a61..620b4fc 100644 --- a/core-foundation/src/data.rs +++ b/core-foundation/src/data.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 CFData { - unsafe { - let data_ref = CFDataCreate(kCFAllocatorDefault, - buffer.as_ptr(), - buffer.len().to_CFIndex()); - 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() - } -} +pub use core_foundation_sys::data::{CFData, CFDataRef, CFDataSearchFlags}; diff --git a/core-foundation/src/dictionary.rs b/core-foundation/src/dictionary.rs index e27ed4a..98a7d71 100644 --- a/core-foundation/src/dictionary.rs +++ b/core-foundation/src/dictionary.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 (pairs: &[(K, V)]) -> CFDictionary - where K: TCFType, V: TCFType { - let (keys, values): (Vec,Vec) = - pairs.iter() - .map(|&(ref key, ref value)| (key.as_CFTypeRef(), value.as_CFTypeRef())) - .unzip(); - - unsafe { - let dictionary_ref = CFDictionaryCreate(kCFAllocatorDefault, - mem::transmute(keys.as_ptr()), - mem::transmute(values.as_ptr()), - keys.len().to_CFIndex(), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - TCFType::wrap_under_create_rule(dictionary_ref) - } - } - - #[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(&self, key: *const c_void) -> Option<*const c_void> { - unsafe { - let mut value: *const c_void = ptr::null(); - if CFDictionaryGetValueIfPresent(self.0, key, &mut value) != 0 { - Some(value) - } else { - None - } - } - } - - #[inline] - pub fn get(&self, key: *const c_void) -> *const c_void { - let value = self.find(key); - if value.is_none() { - panic!("No entry found for key {:p}", key); - } - value.unwrap() - } - - /// A convenience function to retrieve `CFType` instances. - #[inline] - pub unsafe fn get_CFType(&self, key: *const c_void) -> CFType { - let value: CFTypeRef = mem::transmute(self.get(key)); - TCFType::wrap_under_get_rule(value) - } - - #[inline] - pub unsafe fn set_value(&self, key: *const c_void, value: *const c_void) { - CFDictionarySetValue(self.0, key, value) - } -} +pub use core_foundation_sys::dictionary::{CFDictionary, CFDictionaryRef}; diff --git a/core-foundation/src/error.rs b/core-foundation/src/error.rs index af9b26f..070ab76 100644 --- a/core-foundation/src/error.rs +++ b/core-foundation/src/error.rs @@ -9,69 +9,4 @@ //! Core Foundation errors. -use core_foundation_sys::error::*; -use core_foundation_sys::base::CFRelease; -use std::error::Error; -use std::fmt; - -use base::{CFIndex, TCFType}; -use string::CFString; - -/// An error value. -pub struct CFError(CFErrorRef); - -impl Drop for CFError { - fn drop(&mut self) { - unsafe { - CFRelease(self.as_CFTypeRef()) - } - } -} - -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) - } - } -} +pub use core_foundation_sys::error::{CFError, CFErrorRef}; diff --git a/core-foundation/src/lib.rs b/core-foundation/src/lib.rs index 345b123..04a1b6d 100644 --- a/core-foundation/src/lib.rs +++ b/core-foundation/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + #![allow(non_snake_case)] extern crate core_foundation_sys; -extern crate libc; - -#[macro_export] -macro_rules! impl_TCFType { - ($ty:ident, $raw:ident, $ty_id:ident) => { - impl $crate::base::TCFType<$raw> for $ty { - #[inline] - fn as_concrete_TypeRef(&self) -> $raw { - self.0 - } - - #[inline] - unsafe fn wrap_under_get_rule(reference: $raw) -> $ty { - let reference = ::std::mem::transmute(::core_foundation_sys::base::CFRetain(::std::mem::transmute(reference))); - $crate::base::TCFType::wrap_under_create_rule(reference) - } - - #[inline] - fn as_CFTypeRef(&self) -> ::core_foundation_sys::base::CFTypeRef { - unsafe { - ::std::mem::transmute(self.as_concrete_TypeRef()) - } - } - - #[inline] - unsafe fn wrap_under_create_rule(obj: $raw) -> $ty { - $ty(obj) - } - - #[inline] - fn type_id() -> ::core_foundation_sys::base::CFTypeID { - unsafe { - $ty_id() - } - } - } - } -} pub mod array; pub mod base; pub mod boolean; +pub mod bundle; pub mod data; -pub use core_foundation_sys::date; // back compat pub mod dictionary; pub mod error; pub mod number; +pub mod runloop; pub mod set; pub mod string; +pub mod time; pub mod url; -pub mod bundle; -pub mod runloop; - -#[cfg(test)] -pub mod test { - #[test] - fn test_stuff() { - use base::TCFType; - use boolean::CFBoolean; - use number::number; - use dictionary::CFDictionary; - use string::CFString; - - /*let n = CFNumber::new_number(42 as i32); - io::println(format!("%d", (&n).retain_count() as int)); - (&n).show();*/ - - 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 = number(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()), - ]); - } -} diff --git a/core-foundation/src/number.rs b/core-foundation/src/number.rs index 771c75e..176e1d4 100644 --- a/core-foundation/src/number.rs +++ b/core-foundation/src/number.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 CFNumber { - unsafe { - let number_ref = CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt32Type, - mem::transmute(&value)); - TCFType::wrap_under_create_rule(number_ref) - } - } - - #[inline] - pub fn to_i64(&self) -> Option { - unsafe { - let mut value: i64 = 0; - let ok = CFNumberGetValue(self.0, kCFNumberSInt64Type, mem::transmute(&mut value)); - if ok { Some(value) } else { None } - } - } - - #[inline] - pub fn to_f64(&self) -> Option { - unsafe { - let mut value: f64 = 0.0; - let ok = CFNumberGetValue(self.0, kCFNumberFloat64Type, mem::transmute(&mut value)); - if ok { Some(value) } else { None } - } - } - - #[inline] - pub fn from_i64(value: i64) -> CFNumber { - unsafe { - let number_ref = CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt64Type, - mem::transmute(&value)); - TCFType::wrap_under_create_rule(number_ref) - } - } - - #[inline] - pub fn from_f64(value: f64) -> CFNumber { - unsafe { - let number_ref = CFNumberCreate(kCFAllocatorDefault, - kCFNumberFloat64Type, - mem::transmute(&value)); - TCFType::wrap_under_create_rule(number_ref) - } - } -} - -/// A convenience function to create CFNumbers. -pub fn number(value: i64) -> CFNumber { - CFNumber::from_i64(value) -} +pub use core_foundation_sys::number::{CFNumber, CFNumberRef}; +pub use core_foundation_sys::number::{CFNumberType, FromCFNumber}; diff --git a/core-foundation/src/runloop.rs b/core-foundation/src/runloop.rs index 5655535..3e636c1 100644 --- a/core-foundation/src/runloop.rs +++ b/core-foundation/src/runloop.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 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 stop(&self) { - unsafe { - CFRunLoopStop(self.0); - } - } - - pub fn current_mode(&self) -> Option { - 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: CFStringRef) -> bool { - unsafe { - CFRunLoopContainsTimer(self.0, timer.0, mode) != 0 - } - } - - pub fn add_timer(&self, timer: &CFRunLoopTimer, mode: CFStringRef) { - unsafe { - CFRunLoopAddTimer(self.0, timer.0, mode); - } - } - -} - -pub struct CFRunLoopTimer(CFRunLoopTimerRef); - -impl Drop for CFRunLoopTimer { - fn drop(&mut self) { - unsafe { - CFRelease(self.as_CFTypeRef()) - } - } -} - -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) - } - } -} - -#[cfg(test)] -mod test { - use super::*; - use core_foundation_sys::date::{CFAbsoluteTime, CFAbsoluteTimeGetCurrent}; - use std::mem; - use libc::c_void; - - #[test] - fn wait_200_milliseconds() { - let run_loop = CFRunLoop::get_current(); - let mut now = unsafe { CFAbsoluteTimeGetCurrent() }; - let mut context = unsafe { CFRunLoopTimerContext { - version: 0, - info: mem::transmute(&mut now), - retain: mem::zeroed(), - release: mem::zeroed(), - copyDescription: mem::zeroed(), - } }; - - - let run_loop_timer = CFRunLoopTimer::new(now + 0.20f64, 0f64, 0, 0, timer_popped, &mut context); - run_loop.add_timer(&run_loop_timer, kCFRunLoopDefaultMode); - - CFRunLoop::run_current(); - } - - extern "C" fn timer_popped(_timer: CFRunLoopTimerRef, _info: *mut c_void) { - let previous_now_ptr: *const CFAbsoluteTime = unsafe { mem::transmute(_info) }; - let previous_now = unsafe { *previous_now_ptr }; - let now = unsafe { CFAbsoluteTimeGetCurrent() }; - assert!(now - previous_now > 0.19 && now - previous_now < 0.21); - CFRunLoop::get_current().stop(); - } -} +pub use core_foundation_sys::runloop::{CFRunLoop, CFRunLoopRef, CFRunLoopRunResult}; +pub use core_foundation_sys::runloop::{CFRunLoopTimer, CFRunLoopTimerRef}; diff --git a/core-foundation/src/set.rs b/core-foundation/src/set.rs index 8224a20..14239bc 100644 --- a/core-foundation/src/set.rs +++ b/core-foundation/src/set.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 (elems: &[T]) -> CFSet where T: TCFType { - unsafe { - let elems: Vec = elems.iter().map(|elem| elem.as_CFTypeRef()).collect(); - let set_ref = CFSetCreate(kCFAllocatorDefault, - mem::transmute(elems.as_ptr()), - elems.len().to_CFIndex(), - &kCFTypeSetCallBacks); - TCFType::wrap_under_create_rule(set_ref) - } - } -} +pub use core_foundation_sys::set::{CFSet, CFSetRef}; diff --git a/core-foundation/src/string.rs b/core-foundation/src/string.rs index 051ca9a..d77e9da 100644 --- a/core-foundation/src/string.rs +++ b/core-foundation/src/string.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 CFString { - unsafe { - TCFType::wrap_under_get_rule(self.0) - } - } -} - -impl Drop for CFString { - fn drop(&mut self) { - unsafe { - CFRelease(self.as_CFTypeRef()) - } - } -} - -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 { - Ok(CFString::new(string)) - } -} - -impl fmt::Display for CFString { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - unsafe { - // Do this without allocating if we can get away with it - let c_string = CFStringGetCStringPtr(self.0, kCFStringEncodingUTF8); - if c_string != ptr::null() { - let c_str = CStr::from_ptr(c_string); - fmt.write_str(str::from_utf8_unchecked(c_str.to_bytes())) - } else { - let char_len = self.char_len(); - - // First, ask how big the buffer ought to be. - let mut bytes_required: CFIndex = 0; - CFStringGetBytes(self.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(self.0, - CFRange { location: 0, length: char_len }, - kCFStringEncodingUTF8, - 0, - false as Boolean, - buffer.as_mut_ptr(), - buffer.len().to_CFIndex(), - &mut bytes_used) as usize; - assert!(chars_written.to_CFIndex() == char_len); - - // This is dangerous; we over-allocate and null-terminate the string (during - // initialization). - assert!(bytes_used == buffer.len().to_CFIndex()); - fmt.write_str(str::from_utf8_unchecked(&buffer)) - } - } - } -} - -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, - kCFAllocatorNull); - 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) - } - } -} - -#[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!(converted == original); -} +pub use core_foundation_sys::string::{CFString, CFStringRef, CFStringCompareFlags}; diff --git a/core-foundation/src/time.rs b/core-foundation/src/time.rs new file mode 100644 index 0000000..a36d7b7 --- /dev/null +++ b/core-foundation/src/time.rs @@ -0,0 +1,10 @@ +// Copyright 2013-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use core_foundation_sys::time::{CFAbsoluteTime, CFTimeInterval}; diff --git a/core-foundation/src/url.rs b/core-foundation/src/url.rs index bf2bc1e..ef67f2d 100644 --- a/core-foundation/src/url.rs +++ b/core-foundation/src/url.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// Copyright 2013-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 fmt::Result { - unsafe { - let string: CFString = TCFType::wrap_under_get_rule(CFURLGetString(self.0)); - write!(f, "{}", string.to_string()) - } - } -} - -impl CFURL { - 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) - } - } - - pub fn get_string(&self) -> CFString { - unsafe { - TCFType::wrap_under_get_rule(CFURLGetString(self.0)) - } - } -} - -#[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!(cfurl.get_string().to_string() == "file:///usr/local/foo/"); -} +pub use core_foundation_sys::url::{CFURL, CFURLRef}; From f077c50dcf5293e79e84c53ecaced6ed0ecf5ba1 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Wed, 12 Oct 2016 11:17:36 +0200 Subject: [PATCH 2/2] Add CFMut This type provides DerefMut access to the underlying Core Foundation type. Will be used for CFMutableString and friends. --- core-foundation-sys/src/sync.rs | 94 ++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/core-foundation-sys/src/sync.rs b/core-foundation-sys/src/sync.rs index bf604c0..b266203 100644 --- a/core-foundation-sys/src/sync.rs +++ b/core-foundation-sys/src/sync.rs @@ -13,7 +13,8 @@ use base::{CFRelease, CFRetain, CFType}; use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; use std::fmt; use std::hash::{Hash, Hasher}; -use std::ops::Deref; +use std::mem; +use std::ops::{Deref, DerefMut}; #[repr(C)] pub struct CFRef { ptr: *const CFShared } @@ -35,6 +36,16 @@ impl CFRef { Err(()) } } + + fn into_mut(self) -> Result, Self> { + if self.as_object().retain_count() == 1 { + let result = CFMut { ptr: self.ptr as *const _ as *mut _ }; + mem::forget(self); + Ok(result) + } else { + Err(self) + } + } } impl Clone for CFRef { @@ -155,3 +166,84 @@ impl PartialOrd for CFShared { unsafe impl Send for CFShared {} unsafe impl Sync for CFShared {} + +#[repr(C)] +pub struct CFMut { ptr: *mut T } + +impl CFMut { + #[inline] + pub unsafe fn from_retained(retained: *const CFShared) -> Self { + assert!(!retained.is_null()); + assert!((&*retained).as_object().retain_count() == 1); + CFMut { ptr: retained as *const _ as *mut _ } + } + + fn into_ref(self) -> CFRef { + let result = CFRef { ptr: self.ptr as *const _ as *const _ }; + mem::forget(self); + result + } +} + +impl Deref for CFMut { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.ptr } + } +} + +impl DerefMut for CFMut { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.ptr } + } +} + +impl Drop for CFMut { + #[inline] + fn drop(&mut self) { + unsafe { CFRelease(self.as_object()) } + } +} + +impl fmt::Debug for CFMut { + #[inline] + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + (&**self).fmt(formatter) + } +} + +impl Hash for CFMut { + #[inline] + fn hash(&self, state: &mut H) { + self.as_object().hash(state) + } +} + +impl Eq for CFMut {} + +impl PartialEq for CFMut { + #[inline] + fn eq(&self, other: &Self) -> bool { + (&**self).eq(&**other) + } +} + +impl Ord for CFMut { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + (&**self).cmp(&**other) + } +} + +impl PartialOrd for CFMut { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + (&**self).partial_cmp(&**other) + } +} + +unsafe impl Send for CFMut {} +unsafe impl Sync for CFMut {}