diff --git a/src/array.rs b/src/array.rs index 987a44c..0a47a2c 100644 --- a/src/array.rs +++ b/src/array.rs @@ -9,8 +9,8 @@ //! Heterogeneous immutable arrays. -use base::{CFAllocatorRef, CFIndex, CFIndexConvertible, CFRelease, CFRetain}; -use base::{CFType, CFTypeID, CFTypeRef, TCFType}; +use base::{CFAllocatorRef, CFIndex, CFIndexConvertible, CFRelease}; +use base::{CFTypeID, CFTypeRef, TCFType}; use base::{kCFAllocatorDefault}; use libc::c_void; use std::mem; @@ -44,11 +44,7 @@ struct __CFArray; pub type CFArrayRef = *const __CFArray; /// A heterogeneous immutable array. -/// -/// FIXME(pcwalton): Should be a newtype struct, but that fails due to a Rust compiler bug. -pub struct CFArray { - obj: CFArrayRef, -} +pub struct CFArray(CFArrayRef); impl Drop for CFArray { fn drop(&mut self) { @@ -77,43 +73,11 @@ impl<'a> Iterator for CFArrayIterator<'a> { } } -impl TCFType for CFArray { - #[inline] - fn as_concrete_TypeRef(&self) -> CFArrayRef { - self.obj - } - - #[inline] - unsafe fn wrap_under_get_rule(reference: CFArrayRef) -> CFArray { - let reference: CFArrayRef = mem::transmute(CFRetain(mem::transmute(reference))); - TCFType::wrap_under_create_rule(reference) - } - - #[inline] - fn as_CFTypeRef(&self) -> CFTypeRef { - unsafe { - mem::transmute(self.as_concrete_TypeRef()) - } - } - - #[inline] - unsafe fn wrap_under_create_rule(obj: CFArrayRef) -> CFArray { - CFArray { - obj: obj, - } - } - - #[inline] - fn type_id() -> CFTypeID { - unsafe { - CFArrayGetTypeID() - } - } -} +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: &[CFType]) -> CFArray { + 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, @@ -128,7 +92,7 @@ impl 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()`. The safer `iter_CFTypes` method will do this for you. + /// `TCFType::wrap_under_get_rule()`. #[inline] pub fn iter<'a>(&'a self) -> CFArrayIterator<'a> { CFArrayIterator { @@ -140,7 +104,7 @@ impl CFArray { #[inline] pub fn len(&self) -> CFIndex { unsafe { - CFArrayGetCount(self.obj) + CFArrayGetCount(self.0) } } @@ -148,11 +112,20 @@ impl CFArray { pub fn get(&self, index: CFIndex) -> *const c_void { assert!(index < self.len()); unsafe { - CFArrayGetValueAtIndex(self.obj, index) + 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() + } +} + #[link(name = "CoreFoundation", kind = "framework")] extern { /* diff --git a/src/base.rs b/src/base.rs index 81f3523..fb1dadf 100644 --- a/src/base.rs +++ b/src/base.rs @@ -72,15 +72,13 @@ struct __CFType; pub type CFTypeRef = *const __CFType; /// Superclass of all Core Foundation objects. -pub struct CFType { - obj: CFTypeRef, -} +pub struct CFType(CFTypeRef); impl Clone for CFType { #[inline] fn clone(&self) -> CFType { unsafe { - TCFType::wrap_under_get_rule(self.obj) + TCFType::wrap_under_get_rule(self.0) } } } @@ -88,7 +86,7 @@ impl Clone for CFType { impl Drop for CFType { fn drop(&mut self) { unsafe { - CFRelease(self.obj) + CFRelease(self.0) } } } @@ -156,7 +154,7 @@ pub trait TCFType { impl TCFType for CFType { #[inline] fn as_concrete_TypeRef(&self) -> CFTypeRef { - self.obj + self.0 } #[inline] @@ -172,9 +170,7 @@ impl TCFType for CFType { #[inline] unsafe fn wrap_under_create_rule(obj: CFTypeRef) -> CFType { - CFType { - obj: obj, - } + CFType(obj) } #[inline] diff --git a/src/boolean.rs b/src/boolean.rs index 7f29ae4..9ededa8 100644 --- a/src/boolean.rs +++ b/src/boolean.rs @@ -9,7 +9,7 @@ //! A Boolean type. -use base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType}; +use base::{CFRelease, CFTypeID, TCFType}; use std::mem; pub type Boolean = u32; @@ -22,9 +22,7 @@ pub type CFBooleanRef = *const __CFBoolean; /// A Boolean type. /// /// FIXME(pcwalton): Should be a newtype struct, but that fails due to a Rust compiler bug. -pub struct CFBoolean { - obj: CFBooleanRef, -} +pub struct CFBoolean(CFBooleanRef); impl Drop for CFBoolean { fn drop(&mut self) { @@ -34,38 +32,7 @@ impl Drop for CFBoolean { } } -impl TCFType for CFBoolean { - #[inline] - fn as_concrete_TypeRef(&self) -> CFBooleanRef { - self.obj - } - - #[inline] - unsafe fn wrap_under_get_rule(reference: CFBooleanRef) -> CFBoolean { - let reference: CFBooleanRef = mem::transmute(CFRetain(mem::transmute(reference))); - TCFType::wrap_under_create_rule(reference) - } - - #[inline] - fn as_CFTypeRef(&self) -> CFTypeRef { - unsafe { - mem::transmute(self.as_concrete_TypeRef()) - } - } - - unsafe fn wrap_under_create_rule(obj: CFBooleanRef) -> CFBoolean { - CFBoolean { - obj: obj, - } - } - - #[inline] - fn type_id() -> CFTypeID { - unsafe { - CFBooleanGetTypeID() - } - } -} +impl_TCFType!(CFBoolean, CFBooleanRef, CFBooleanGetTypeID); impl CFBoolean { pub fn true_value() -> CFBoolean { diff --git a/src/bundle.rs b/src/bundle.rs index 42edf88..76edb33 100644 --- a/src/bundle.rs +++ b/src/bundle.rs @@ -9,7 +9,7 @@ //! Core Foundation Bundle Type -use base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType}; +use base::{CFRelease, CFTypeID, TCFType}; use std::mem; use string::CFStringRef; @@ -21,11 +21,7 @@ struct __CFBundle; pub type CFBundleRef = *const __CFBundle; /// A Bundle type. -/// -/// FIXME(pcwalton): Should be a newtype struct, but that fails due to a Rust compiler bug. -pub struct CFBundle { - obj: CFBundleRef, -} +pub struct CFBundle(CFBundleRef); impl Drop for CFBundle { fn drop(&mut self) { @@ -35,38 +31,7 @@ impl Drop for CFBundle { } } -impl TCFType for CFBundle { - #[inline] - fn as_concrete_TypeRef(&self) -> CFBundleRef { - self.obj - } - - #[inline] - unsafe fn wrap_under_get_rule(reference: CFBundleRef) -> CFBundle { - let reference: CFBundleRef = mem::transmute(CFRetain(mem::transmute(reference))); - TCFType::wrap_under_create_rule(reference) - } - - #[inline] - fn as_CFTypeRef(&self) -> CFTypeRef { - unsafe { - mem::transmute(self.as_concrete_TypeRef()) - } - } - - unsafe fn wrap_under_create_rule(obj: CFBundleRef) -> CFBundle { - CFBundle { - obj: obj, - } - } - - #[inline] - fn type_id() -> CFTypeID { - unsafe { - CFBundleGetTypeID() - } - } -} +impl_TCFType!(CFBundle, CFBundleRef, CFBundleGetTypeID); #[link(name = "CoreFoundation", kind = "framework")] extern { diff --git a/src/data.rs b/src/data.rs index 55be5f1..9c8ace9 100644 --- a/src/data.rs +++ b/src/data.rs @@ -9,10 +9,12 @@ //! Core Foundation byte buffers. -use base::{CFAllocatorRef, CFIndex, CFIndexConvertible, CFRelease, CFRetain}; -use base::{CFTypeID, CFTypeRef, TCFType, kCFAllocatorDefault}; +use base::{CFAllocatorRef, CFIndex, CFIndexConvertible, CFRelease}; +use base::{CFTypeID, TCFType, kCFAllocatorDefault}; use std::mem; +use std::ops::Deref; +use std::slice; #[repr(C)] struct __CFData; @@ -20,11 +22,7 @@ struct __CFData; pub type CFDataRef = *const __CFData; /// A byte buffer. -/// -/// FIXME(pcwalton): Should be a newtype struct, but that fails due to a Rust compiler bug. -pub struct CFData { - obj: CFDataRef, -} +pub struct CFData(CFDataRef); impl Drop for CFData { fn drop(&mut self) { @@ -34,38 +32,7 @@ impl Drop for CFData { } } -impl TCFType for CFData { - #[inline] - fn as_concrete_TypeRef(&self) -> CFDataRef { - self.obj - } - - #[inline] - unsafe fn wrap_under_get_rule(reference: CFDataRef) -> CFData { - let reference: CFDataRef = mem::transmute(CFRetain(mem::transmute(reference))); - TCFType::wrap_under_create_rule(reference) - } - - #[inline] - fn as_CFTypeRef(&self) -> CFTypeRef { - unsafe { - mem::transmute(self.as_concrete_TypeRef()) - } - } - - unsafe fn wrap_under_create_rule(obj: CFDataRef) -> CFData { - CFData { - obj: obj, - } - } - - #[inline] - fn type_id() -> CFTypeID { - unsafe { - CFDataGetTypeID() - } - } -} +impl_TCFType!(CFData, CFDataRef, CFDataGetTypeID); impl CFData { pub fn from_buffer(buffer: &[u8]) -> CFData { @@ -82,7 +49,7 @@ impl CFData { #[inline] pub fn bytes<'a>(&'a self) -> &'a [u8] { unsafe { - mem::transmute((CFDataGetBytePtr(self.obj), self.len() as usize)) + slice::from_raw_parts(CFDataGetBytePtr(self.0), self.len() as usize) } } @@ -90,11 +57,20 @@ impl CFData { #[inline] pub fn len(&self) -> CFIndex { unsafe { - CFDataGetLength(self.obj) + CFDataGetLength(self.0) } } } +impl Deref for CFData { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + self.bytes() + } +} + #[link(name = "CoreFoundation", kind = "framework")] extern { /* diff --git a/src/dictionary.rs b/src/dictionary.rs index 3817bfe..e2fbd7c 100644 --- a/src/dictionary.rs +++ b/src/dictionary.rs @@ -9,7 +9,7 @@ //! Dictionaries of key-value pairs. -use base::{Boolean, CFAllocatorRef, CFIndex, CFIndexConvertible, CFRelease, CFRetain}; +use base::{Boolean, CFAllocatorRef, CFIndex, CFIndexConvertible, CFRelease}; use base::{CFType, CFTypeID, CFTypeRef, TCFType, kCFAllocatorDefault}; use libc::c_void; @@ -52,11 +52,7 @@ struct __CFDictionary; pub type CFDictionaryRef = *const __CFDictionary; /// An immutable dictionary of key-value pairs. -/// -/// FIXME(pcwalton): Should be a newtype struct, but that panics due to a Rust compiler bug. -pub struct CFDictionary { - obj: CFDictionaryRef, -} +pub struct CFDictionary(CFDictionaryRef); impl Drop for CFDictionary { fn drop(&mut self) { @@ -66,41 +62,11 @@ impl Drop for CFDictionary { } } -impl TCFType for CFDictionary { - #[inline] - fn as_concrete_TypeRef(&self) -> CFDictionaryRef { - self.obj - } - - #[inline] - unsafe fn wrap_under_get_rule(reference: CFDictionaryRef) -> CFDictionary { - let reference: CFDictionaryRef = mem::transmute(CFRetain(mem::transmute(reference))); - TCFType::wrap_under_create_rule(reference) - } - - #[inline] - fn as_CFTypeRef(&self) -> CFTypeRef { - unsafe { - mem::transmute(self.as_concrete_TypeRef()) - } - } - - unsafe fn wrap_under_create_rule(obj: CFDictionaryRef) -> CFDictionary { - CFDictionary { - obj: obj, - } - } - - #[inline] - fn type_id() -> CFTypeID { - unsafe { - CFDictionaryGetTypeID() - } - } -} +impl_TCFType!(CFDictionary, CFDictionaryRef, CFDictionaryGetTypeID); impl CFDictionary { - pub fn from_CFType_pairs(pairs: &[(CFType, CFType)]) -> CFDictionary { + pub fn from_CFType_pairs(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())) @@ -120,7 +86,7 @@ impl CFDictionary { #[inline] pub fn len(&self) -> usize { unsafe { - CFDictionaryGetCount(self.obj) as usize + CFDictionaryGetCount(self.0) as usize } } @@ -132,7 +98,7 @@ impl CFDictionary { #[inline] pub fn contains_key(&self, key: *const c_void) -> bool { unsafe { - CFDictionaryContainsKey(self.obj, key) != 0 + CFDictionaryContainsKey(self.0, key) != 0 } } @@ -140,7 +106,7 @@ impl CFDictionary { pub fn find(&self, key: *const c_void) -> Option<*const c_void> { unsafe { let mut value: *const c_void = ptr::null(); - if CFDictionaryGetValueIfPresent(self.obj, key, &mut value) != 0 { + if CFDictionaryGetValueIfPresent(self.0, key, &mut value) != 0 { Some(value) } else { None diff --git a/src/lib.rs b/src/lib.rs index 66d0958..569a2e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,43 @@ 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 = mem::transmute($crate::base::CFRetain(mem::transmute(reference))); + $crate::base::TCFType::wrap_under_create_rule(reference) + } + + #[inline] + fn as_CFTypeRef(&self) -> $crate::base::CFTypeRef { + unsafe { + mem::transmute(self.as_concrete_TypeRef()) + } + } + + #[inline] + unsafe fn wrap_under_create_rule(obj: $raw) -> $ty { + $ty(obj) + } + + #[inline] + fn type_id() -> $crate::base::CFTypeID { + unsafe { + $ty_id() + } + } + } + } +} + pub mod array; pub mod base; pub mod boolean; diff --git a/src/number.rs b/src/number.rs index beb1499..198dbad 100644 --- a/src/number.rs +++ b/src/number.rs @@ -11,7 +11,7 @@ #![allow(non_upper_case_globals)] -use base::{CFAllocatorRef, CFRelease, CFRetain, CFTypeID, CFTypeRef}; +use base::{CFAllocatorRef, CFRelease, CFTypeID}; use base::{TCFType, kCFAllocatorDefault}; use libc::c_void; @@ -44,11 +44,7 @@ struct __CFNumber; pub type CFNumberRef = *const __CFNumber; /// An immutable numeric value. -/// -/// FIXME(pcwalton): Should be a newtype struct, but that fails due to a Rust compiler bug. -pub struct CFNumber { - obj: CFNumberRef, -} +pub struct CFNumber(CFNumberRef); impl Drop for CFNumber { fn drop(&mut self) { @@ -58,38 +54,7 @@ impl Drop for CFNumber { } } -impl TCFType for CFNumber { - #[inline] - fn as_concrete_TypeRef(&self) -> CFNumberRef { - self.obj - } - - #[inline] - unsafe fn wrap_under_get_rule(reference: CFNumberRef) -> CFNumber { - let reference: CFNumberRef = mem::transmute(CFRetain(mem::transmute(reference))); - TCFType::wrap_under_create_rule(reference) - } - - #[inline] - fn as_CFTypeRef(&self) -> CFTypeRef { - unsafe { - mem::transmute(self.as_concrete_TypeRef()) - } - } - - unsafe fn wrap_under_create_rule(obj: CFNumberRef) -> CFNumber { - CFNumber { - obj: obj, - } - } - - #[inline] - fn type_id() -> CFTypeID { - unsafe { - CFNumberGetTypeID() - } - } -} +impl_TCFType!(CFNumber, CFNumberRef, CFNumberGetTypeID); // TODO(pcwalton): Floating point. impl CFNumber { @@ -107,7 +72,7 @@ impl CFNumber { pub fn to_i64(&self) -> Option { unsafe { let mut value: i64 = 0; - let ok = CFNumberGetValue(self.obj, kCFNumberSInt64Type, mem::transmute(&mut value)); + let ok = CFNumberGetValue(self.0, kCFNumberSInt64Type, mem::transmute(&mut value)); if ok { Some(value) } else { None } } } @@ -116,7 +81,7 @@ impl CFNumber { pub fn to_f64(&self) -> Option { unsafe { let mut value: f64 = 0.0; - let ok = CFNumberGetValue(self.obj, kCFNumberFloat64Type, mem::transmute(&mut value)); + let ok = CFNumberGetValue(self.0, kCFNumberFloat64Type, mem::transmute(&mut value)); if ok { Some(value) } else { None } } } diff --git a/src/runloop.rs b/src/runloop.rs index 067df84..b0782a2 100644 --- a/src/runloop.rs +++ b/src/runloop.rs @@ -9,8 +9,8 @@ #![allow(non_upper_case_globals)] -use base::{CFAllocatorRef, CFIndex, CFOptionFlags, CFRelease, CFRetain}; -use base::{CFTypeID, CFTypeRef, TCFType, CFHashCode, mach_port_t}; +use base::{CFAllocatorRef, CFIndex, CFOptionFlags, CFRelease}; +use base::{CFTypeID, TCFType, CFHashCode, mach_port_t}; use base::{kCFAllocatorDefault}; use base::{Boolean}; use array::{CFArrayRef}; @@ -19,10 +19,7 @@ use date::{CFAbsoluteTime, CFTimeInterval}; use libc::c_void; use std::mem; -/// FIXME(pcwalton): Should be a newtype struct, but that fails due to a Rust compiler bug. -pub struct CFRunLoop { - obj: CFRunLoopRef, -} +pub struct CFRunLoop(CFRunLoopRef); impl Drop for CFRunLoop { fn drop(&mut self) { @@ -32,39 +29,7 @@ impl Drop for CFRunLoop { } } -impl TCFType for CFRunLoop { - #[inline] - fn as_concrete_TypeRef(&self) -> CFRunLoopRef { - self.obj - } - - #[inline] - unsafe fn wrap_under_get_rule(reference: CFRunLoopRef) -> CFRunLoop { - let reference: CFRunLoopRef = mem::transmute(CFRetain(mem::transmute(reference))); - TCFType::wrap_under_create_rule(reference) - } - - #[inline] - fn as_CFTypeRef(&self) -> CFTypeRef { - unsafe { - mem::transmute(self.as_concrete_TypeRef()) - } - } - - #[inline] - unsafe fn wrap_under_create_rule(obj: CFRunLoopRef) -> CFRunLoop { - CFRunLoop { - obj: obj, - } - } - - #[inline] - fn type_id() -> CFTypeID { - unsafe { - CFRunLoopGetTypeID() - } - } -} +impl_TCFType!(CFRunLoop, CFRunLoopRef, CFRunLoopGetTypeID); impl CFRunLoop { pub fn get_current() -> CFRunLoop { @@ -89,13 +54,13 @@ impl CFRunLoop { pub fn stop(&self) { unsafe { - CFRunLoopStop(self.obj); + CFRunLoopStop(self.0); } } pub fn current_mode(&self) -> Option { unsafe { - let string_ref = CFRunLoopCopyCurrentMode(self.obj); + let string_ref = CFRunLoopCopyCurrentMode(self.0); if string_ref.is_null() { return None; } @@ -107,13 +72,13 @@ impl CFRunLoop { pub fn contains_timer(&self, timer: &CFRunLoopTimer, mode: CFStringRef) -> bool { unsafe { - CFRunLoopContainsTimer(self.obj, timer.obj, mode) != 0 + CFRunLoopContainsTimer(self.0, timer.0, mode) != 0 } } pub fn add_timer(&self, timer: &CFRunLoopTimer, mode: CFStringRef) { unsafe { - CFRunLoopAddTimer(self.obj, timer.obj, mode); + CFRunLoopAddTimer(self.0, timer.0, mode); } } @@ -206,10 +171,7 @@ struct __CFRunLoopTimer; pub type CFRunLoopTimerRef = *const __CFRunLoopTimer; -/// FIXME(pcwalton): Should be a newtype struct, but that fails due to a Rust compiler bug. -pub struct CFRunLoopTimer { - obj: CFRunLoopTimerRef, -} +pub struct CFRunLoopTimer(CFRunLoopTimerRef); impl Drop for CFRunLoopTimer { fn drop(&mut self) { @@ -219,39 +181,7 @@ impl Drop for CFRunLoopTimer { } } -impl TCFType for CFRunLoopTimer { - #[inline] - fn as_concrete_TypeRef(&self) -> CFRunLoopTimerRef { - self.obj - } - - #[inline] - unsafe fn wrap_under_get_rule(reference: CFRunLoopTimerRef) -> CFRunLoopTimer { - let reference: CFRunLoopTimerRef = mem::transmute(CFRetain(mem::transmute(reference))); - TCFType::wrap_under_create_rule(reference) - } - - #[inline] - fn as_CFTypeRef(&self) -> CFTypeRef { - unsafe { - mem::transmute(self.as_concrete_TypeRef()) - } - } - - #[inline] - unsafe fn wrap_under_create_rule(obj: CFRunLoopTimerRef) -> CFRunLoopTimer { - CFRunLoopTimer { - obj: obj, - } - } - - #[inline] - fn type_id() -> CFTypeID { - unsafe { - CFRunLoopTimerGetTypeID() - } - } -} +impl_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef, CFRunLoopTimerGetTypeID); impl CFRunLoopTimer { pub fn new(fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext) -> CFRunLoopTimer { diff --git a/src/set.rs b/src/set.rs index 4432e06..b5e26b8 100644 --- a/src/set.rs +++ b/src/set.rs @@ -9,8 +9,8 @@ //! An immutable bag of elements. -use base::{CFAllocatorRef, CFIndex, CFIndexConvertible, CFRelease, CFRetain}; -use base::{CFType, CFTypeID, CFTypeRef, TCFType, kCFAllocatorDefault}; +use base::{CFAllocatorRef, CFIndex, CFIndexConvertible, CFRelease}; +use base::{CFTypeID, CFTypeRef, TCFType, kCFAllocatorDefault}; use libc::c_void; use std::mem; @@ -39,11 +39,7 @@ struct __CFSet; pub type CFSetRef = *const __CFSet; /// An immutable bag of elements. -/// -/// FIXME(pcwalton): Should be a newtype struct, but that fails due to a Rust compiler bug. -pub struct CFSet { - obj: CFSetRef, -} +pub struct CFSet(CFSetRef); impl Drop for CFSet { fn drop(&mut self) { @@ -53,42 +49,11 @@ impl Drop for CFSet { } } -impl TCFType for CFSet { - #[inline] - fn as_concrete_TypeRef(&self) -> CFSetRef { - self.obj - } - - #[inline] - unsafe fn wrap_under_get_rule(reference: CFSetRef) -> CFSet { - let reference: CFSetRef = mem::transmute(CFRetain(mem::transmute(reference))); - TCFType::wrap_under_create_rule(reference) - } - - #[inline] - fn as_CFTypeRef(&self) -> CFTypeRef { - unsafe { - mem::transmute(self.as_concrete_TypeRef()) - } - } - - unsafe fn wrap_under_create_rule(obj: CFSetRef) -> CFSet { - CFSet { - obj: obj, - } - } - - #[inline] - fn type_id() -> CFTypeID { - unsafe { - CFSetGetTypeID() - } - } -} +impl_TCFType!(CFSet, CFSetRef, CFSetGetTypeID); impl CFSet { /// Creates a new set from a list of `CFType` instances. - pub fn from_slice(elems: &[CFType]) -> CFSet { + pub fn from_slice(elems: &[T]) -> CFSet where T: TCFType { unsafe { let elems: Vec = elems.iter().map(|elem| elem.as_CFTypeRef()).collect(); let set_ref = CFSetCreate(kCFAllocatorDefault, diff --git a/src/string.rs b/src/string.rs index 302c1a8..99bb397 100644 --- a/src/string.rs +++ b/src/string.rs @@ -12,13 +12,13 @@ #![allow(non_upper_case_globals)] use base::{Boolean, CFAllocatorRef, CFIndex, CFIndexConvertible, CFOptionFlags, CFRange}; -use base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType}; +use base::{CFRelease, CFTypeID, TCFType}; use base::{kCFAllocatorDefault, kCFAllocatorNull}; use libc; +use std::ffi::CStr; use std::fmt; -use std::str::FromStr; -use std::string::ToString; +use std::str::{self, FromStr}; use std::mem; use std::ptr; use std::vec::Vec; @@ -205,17 +205,13 @@ struct __CFString; pub type CFStringRef = *const __CFString; /// An immutable string in one of a variety of encodings. -/// -/// FIXME(pcwalton): Should be a newtype struct, but that fails due to a Rust compiler bug. -pub struct CFString { - obj: CFStringRef, -} +pub struct CFString(CFStringRef); impl Clone for CFString { #[inline] fn clone(&self) -> CFString { unsafe { - TCFType::wrap_under_get_rule(self.obj) + TCFType::wrap_under_get_rule(self.0) } } } @@ -228,46 +224,75 @@ impl Drop for CFString { } } +impl_TCFType!(CFString, CFStringRef, CFStringGetTypeID); -impl TCFType for CFString { - #[inline] - fn as_concrete_TypeRef(&self) -> CFStringRef { - self.obj - } +impl FromStr for CFString { + type Err = (); + /// See also CFString::new for a variant of this which does not return a Result #[inline] - unsafe fn wrap_under_get_rule(reference: CFStringRef) -> CFString { - let reference: CFStringRef = mem::transmute(CFRetain(mem::transmute(reference))); - TCFType::wrap_under_create_rule(reference) + fn from_str(string: &str) -> Result { + Ok(CFString::new(string)) } +} - #[inline] - fn as_CFTypeRef(&self) -> CFTypeRef { +impl fmt::Display for CFString { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { unsafe { - mem::transmute(self.as_concrete_TypeRef()) - } - } - - unsafe fn wrap_under_create_rule(obj: CFStringRef) -> CFString { - CFString { - obj: obj, + // 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::init(0, 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::with_capacity(bytes_required as usize); + for _ in (0..bytes_required) { buffer.push('\x00' as u8) } + + let mut bytes_used: CFIndex = 0; + let chars_written = CFStringGetBytes(self.0, + CFRange::init(0, 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)) + } } } +} - #[inline] - fn type_id() -> CFTypeID { - unsafe { - CFStringGetTypeID() - } +impl fmt::Debug for CFString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "\"{}\"", self) } } -impl FromStr for CFString { - type Err = (); +impl CFString { /// Creates a new `CFString` instance from a Rust string. #[inline] - fn from_str(string: &str) -> Result { + pub fn new(string: &str) -> CFString { unsafe { let string_ref = CFStringCreateWithBytes(kCFAllocatorDefault, string.as_ptr(), @@ -275,59 +300,11 @@ impl FromStr for CFString { kCFStringEncodingUTF8, false as Boolean, kCFAllocatorNull); - Some(TCFType::wrap_under_create_rule(string_ref)).ok_or(()) - } - } -} - -impl ToString for CFString { - fn to_string(&self) -> String { - unsafe { - let char_len = self.char_len(); - - // First, ask how big the buffer ought to be. - let mut bytes_required: CFIndex = 0; - CFStringGetBytes(self.obj, - CFRange::init(0, 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::with_capacity(bytes_required as usize); - for _ in (0..bytes_required) { buffer.push('\x00' as u8) } - - let mut bytes_used: CFIndex = 0; - let chars_written = CFStringGetBytes(self.obj, - CFRange::init(0, 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()); - String::from_utf8(buffer).unwrap() + CFString::wrap_under_create_rule(string_ref) } } -} -impl fmt::Debug for CFString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.to_string()) - } -} - - -impl CFString { - /// Like `CFString::from_string`, but references a string that can be used as a backing store + /// 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 { @@ -346,7 +323,7 @@ impl CFString { #[inline] pub fn char_len(&self) -> CFIndex { unsafe { - CFStringGetLength(self.obj) + CFStringGetLength(self.0) } } } @@ -420,7 +397,9 @@ extern { //fn CFStringGetCharactersPtr //fn CFStringGetCharacterFromInlineBuffer //fn CFStringGetCString - //fn CFStringGetCStringPtr + fn CFStringGetCStringPtr(theString: CFStringRef, + encoding: CFStringEncoding) + -> *const libc::c_char; fn CFStringGetLength(theString: CFStringRef) -> CFIndex; //fn CFStringGetPascalString //fn CFStringGetPascalStringPtr diff --git a/src/url.rs b/src/url.rs index fd95479..c6c5708 100644 --- a/src/url.rs +++ b/src/url.rs @@ -11,8 +11,8 @@ #![allow(non_upper_case_globals)] -use base::{CFAllocatorRef, CFIndex, CFOptionFlags, CFRelease, CFRetain}; -use base::{Boolean, CFTypeID, CFTypeRef, TCFType}; +use base::{CFAllocatorRef, CFIndex, CFOptionFlags, CFRelease}; +use base::{Boolean, CFTypeID, TCFType}; use base::{kCFAllocatorDefault}; use string::{CFString, CFStringRef}; @@ -24,9 +24,7 @@ struct __CFURL; pub type CFURLRef = *const __CFURL; -pub struct CFURL { - obj: CFURLRef, -} +pub struct CFURL(CFURLRef); impl Drop for CFURL { fn drop(&mut self) { @@ -36,44 +34,13 @@ impl Drop for CFURL { } } -impl TCFType for CFURL { - #[inline] - fn as_concrete_TypeRef(&self) -> CFURLRef { - self.obj - } - - #[inline] - unsafe fn wrap_under_get_rule(reference: CFURLRef) -> CFURL { - let reference: CFURLRef = mem::transmute(CFRetain(mem::transmute(reference))); - TCFType::wrap_under_create_rule(reference) - } - - #[inline] - fn as_CFTypeRef(&self) -> CFTypeRef { - unsafe { - mem::transmute(self.as_concrete_TypeRef()) - } - } - - unsafe fn wrap_under_create_rule(obj: CFURLRef) -> CFURL { - CFURL { - obj: obj, - } - } - - #[inline] - fn type_id() -> CFTypeID { - unsafe { - CFURLGetTypeID() - } - } -} +impl_TCFType!(CFURL, CFURLRef, CFURLGetTypeID); impl fmt::Debug for CFURL { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unsafe { - let string: CFString = TCFType::wrap_under_get_rule(CFURLGetString(self.obj)); + let string: CFString = TCFType::wrap_under_get_rule(CFURLGetString(self.0)); write!(f, "{}", string.to_string()) } } @@ -89,7 +56,7 @@ impl CFURL { pub fn get_string(&self) -> CFString { unsafe { - TCFType::wrap_under_get_rule(CFURLGetString(self.obj)) + TCFType::wrap_under_get_rule(CFURLGetString(self.0)) } } }