Merge pull request #56 from kristiantakvam/master

Added some CFRunLoop support. Timers work. Also added CFURLCreateWithFileSystemPath.
This commit is contained in:
Jack Moffitt
2015-02-04 08:31:08 -07:00
5 changed files with 415 additions and 2 deletions
+3 -1
View File
@@ -7,13 +7,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use libc::{c_long, c_ulong};
use libc::{c_long, c_ulong, c_uint};
use std::num::Int;
pub type Boolean = u8;
pub type CFIndex = c_long;
pub type mach_port_t = c_uint;
pub trait CFIndexConvertible {
/// Always use this method to construct a `CFIndex` value. It performs bounds checking to
/// ensure the value is in range.
+16
View File
@@ -0,0 +1,16 @@
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub type CFTimeInterval = f64;
pub type CFAbsoluteTime = CFTimeInterval;
#[link(name = "CoreFoundation", kind = "framework")]
extern {
pub fn CFAbsoluteTimeGetCurrent() -> CFAbsoluteTime;
}
+4
View File
@@ -36,6 +36,10 @@ pub mod string;
pub mod url;
#[cfg(target_os="macos")]
pub mod bundle;
#[cfg(target_os="macos")]
pub mod date;
#[cfg(target_os="macos")]
pub mod runloop;
#[cfg(all(target_os="macos", test))]
pub mod test {
+357
View File
@@ -0,0 +1,357 @@
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(non_upper_case_globals)]
use base::{CFAllocatorRef, CFIndex, CFOptionFlags, CFRelease, CFRetain};
use base::{CFTypeID, CFTypeRef, TCFType, CFHashCode, mach_port_t};
use base::{kCFAllocatorDefault};
use base::{Boolean};
use array::{CFArrayRef};
use string::{CFString, CFStringRef};
use date::{CFAbsoluteTime, CFTimeInterval, CFAbsoluteTimeGetCurrent};
use libc::c_void;
use std::mem;
use std::ptr;
/// FIXME(pcwalton): Should be a newtype struct, but that fails due to a Rust compiler bug.
pub struct CFRunLoop {
obj: CFRunLoopRef,
}
impl Drop for CFRunLoop {
fn drop(&mut self) {
unsafe {
CFRelease(self.as_CFTypeRef())
}
}
}
impl TCFType<CFRunLoopRef> 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(_: Option<CFRunLoop>) -> CFTypeID {
unsafe {
CFRunLoopGetTypeID()
}
}
}
impl CFRunLoop {
pub fn get_current() -> CFRunLoop {
unsafe {
let run_loop_ref = CFRunLoopGetCurrent();
TCFType::wrap_under_get_rule(run_loop_ref)
}
}
pub fn get_main() -> CFRunLoop {
unsafe {
let run_loop_ref = CFRunLoopGetMain();
TCFType::wrap_under_get_rule(run_loop_ref)
}
}
pub fn run_current() {
unsafe {
CFRunLoopRun();
}
}
pub fn stop(&self) {
unsafe {
CFRunLoopStop(self.obj);
}
}
pub fn current_mode(&self) -> Option<String> {
unsafe {
let string_ref = CFRunLoopCopyCurrentMode(self.obj);
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.obj, timer.obj, mode) != 0
}
}
pub fn add_timer(&self, timer: &CFRunLoopTimer, mode: CFStringRef) {
unsafe {
CFRunLoopAddTimer(self.obj, timer.obj, mode);
}
}
}
#[repr(C)]
struct __CFRunLoop;
pub type CFRunLoopRef = *const __CFRunLoop;
#[repr(C)]
struct __CFRunLoopSource;
pub type CFRunLoopSourceRef = *const __CFRunLoopSource;
#[repr(C)]
struct __CFRunLoopObserver;
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;
#[repr(C)]
pub struct CFRunLoopSourceContext {
version: CFIndex,
info: *mut c_void,
retain: extern "C" fn (info: *const c_void) -> *const c_void,
release: extern "C" fn (info: *const c_void),
copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef,
equal: extern "C" fn (info1: *const c_void, info2: *const c_void) -> Boolean,
hash: extern "C" fn (info: *const c_void) -> CFHashCode,
schedule: extern "C" fn (info: *const c_void, rl: CFRunLoopRef, mode: CFStringRef),
cancel: extern "C" fn (info: *const c_void, rl: CFRunLoopRef, mode: CFStringRef),
perform: extern "C" fn (info: *const c_void),
}
#[repr(C)]
pub struct CFRunLoopSourceContext1 {
version: CFIndex,
info: *mut c_void,
retain: extern "C" fn (info: *const c_void) -> *const c_void,
release: extern "C" fn (info: *const c_void),
copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef,
equal: extern "C" fn (info1: *const c_void, info2: *const c_void) -> Boolean,
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
getPort: extern "C" fn (info: *mut c_void) -> mach_port_t,
perform: extern "C" fn (msg: *mut c_void, size: CFIndex, allocator: CFAllocatorRef, info: *mut c_void) -> *mut c_void,
}
#[repr(C)]
pub struct CFRunLoopObserverContext {
version: CFIndex,
info: *mut c_void,
retain: extern "C" fn (info: *const c_void) -> *const c_void,
release: extern "C" fn (info: *const c_void),
copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef,
}
pub type CFRunLoopObserverCallBack = extern "C" fn (observer: CFRunLoopObserverRef, activity: CFRunLoopActivity, info: *mut c_void);
#[repr(C)]
pub struct CFRunLoopTimerContext {
version: CFIndex,
info: *mut c_void,
retain: extern "C" fn (info: *const c_void) -> *const c_void,
release: extern "C" fn (info: *const c_void),
copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef,
}
pub type CFRunLoopTimerCallBack = extern "C" fn (timer: CFRunLoopTimerRef, info: *mut c_void);
#[repr(C)]
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,
}
impl Drop for CFRunLoopTimer {
fn drop(&mut self) {
unsafe {
CFRelease(self.as_CFTypeRef())
}
}
}
impl TCFType<CFRunLoopTimerRef> 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(_: Option<CFRunLoopTimer>) -> CFTypeID {
unsafe {
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)
}
}
}
#[allow(dead_code)]
#[link(name = "CoreFoundation", kind = "framework")]
extern {
/*
* CFRunLoop.h
*/
pub static kCFRunLoopDefaultMode: CFStringRef;
pub static kCFRunLoopCommonModes: CFStringRef;
fn CFRunLoopGetTypeID() -> CFTypeID;
fn CFRunLoopGetCurrent() -> CFRunLoopRef;
fn CFRunLoopGetMain() -> CFRunLoopRef;
fn CFRunLoopCopyCurrentMode(rl: CFRunLoopRef) -> CFStringRef;
fn CFRunLoopCopyAllModes(rl: CFRunLoopRef) -> CFArrayRef;
fn CFRunLoopAddCommonMode(rl: CFRunLoopRef, mode: CFStringRef);
fn CFRunLoopGetNextTimerFireDate(rl: CFRunLoopRef, mode: CFStringRef) -> CFAbsoluteTime;
fn CFRunLoopRun();
fn CFRunLoopRunInMode(mode: CFStringRef, seconds: CFTimeInterval, returnAfterSourceHandled: Boolean) -> i32;
fn CFRunLoopIsWaiting(rl: CFRunLoopRef) -> Boolean;
fn CFRunLoopWakeUp(rl: CFRunLoopRef);
fn CFRunLoopStop(rl: CFRunLoopRef);
// fn CFRunLoopPerformBlock(rl: CFRunLoopRef, mode: CFTypeRef, block: void (^)(void));
fn CFRunLoopContainsSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef) -> Boolean;
fn CFRunLoopAddSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef);
fn CFRunLoopRemoveSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef);
fn CFRunLoopContainsObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef) -> Boolean;
fn CFRunLoopAddObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef);
fn CFRunLoopRemoveObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef);
fn CFRunLoopContainsTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef) -> Boolean;
fn CFRunLoopAddTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef);
fn CFRunLoopRemoveTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef);
fn CFRunLoopSourceGetTypeID() -> CFTypeID;
fn CFRunLoopSourceCreate(allocator: CFAllocatorRef, order: CFIndex, context: *mut CFRunLoopSourceContext) -> CFRunLoopSourceRef;
fn CFRunLoopSourceGetOrder(source: CFRunLoopSourceRef) -> CFIndex;
fn CFRunLoopSourceInvalidate(source: CFRunLoopSourceRef);
fn CFRunLoopSourceIsValid(source: CFRunLoopSourceRef) -> Boolean;
fn CFRunLoopSourceGetContext(source: CFRunLoopSourceRef, context: *mut CFRunLoopSourceContext);
fn CFRunLoopSourceSignal(source: CFRunLoopSourceRef);
fn CFRunLoopObserverGetTypeID() -> CFTypeID;
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;
fn CFRunLoopObserverGetActivities(observer: CFRunLoopObserverRef) -> CFOptionFlags;
fn CFRunLoopObserverDoesRepeat(observer: CFRunLoopObserverRef) -> Boolean;
fn CFRunLoopObserverGetOrder(observer: CFRunLoopObserverRef) -> CFIndex;
fn CFRunLoopObserverInvalidate(observer: CFRunLoopObserverRef);
fn CFRunLoopObserverIsValid(observer: CFRunLoopObserverRef) -> Boolean;
fn CFRunLoopObserverGetContext(observer: CFRunLoopObserverRef, context: *mut CFRunLoopObserverContext);
fn CFRunLoopTimerGetTypeID() -> CFTypeID;
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;
fn CFRunLoopTimerGetNextFireDate(timer: CFRunLoopTimerRef) -> CFAbsoluteTime;
fn CFRunLoopTimerSetNextFireDate(timer: CFRunLoopTimerRef, fireDate: CFAbsoluteTime);
fn CFRunLoopTimerGetInterval(timer: CFRunLoopTimerRef) -> CFTimeInterval;
fn CFRunLoopTimerDoesRepeat(timer: CFRunLoopTimerRef) -> Boolean;
fn CFRunLoopTimerGetOrder(timer: CFRunLoopTimerRef) -> CFIndex;
fn CFRunLoopTimerInvalidate(timer: CFRunLoopTimerRef);
fn CFRunLoopTimerIsValid(timer: CFRunLoopTimerRef) -> Boolean;
fn CFRunLoopTimerGetContext(timer: CFRunLoopTimerRef, context: *mut CFRunLoopTimerContext);
fn CFRunLoopTimerGetTolerance(timer: CFRunLoopTimerRef) -> CFTimeInterval;
fn CFRunLoopTimerSetTolerance(timer: CFRunLoopTimerRef, tolerance: CFTimeInterval);
}
#[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();
}
+35 -1
View File
@@ -11,7 +11,9 @@
#![allow(non_upper_case_globals)]
use base::{CFOptionFlags, CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use base::{CFAllocatorRef, CFIndex, CFOptionFlags, CFRelease, CFRetain};
use base::{Boolean, CFTypeID, CFTypeRef, TCFType};
use base::{kCFAllocatorDefault};
use string::{CFString, CFStringRef};
use std::fmt;
@@ -77,8 +79,31 @@ impl fmt::Debug for CFURL {
}
}
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.obj))
}
}
}
type CFURLBookmarkCreationOptions = CFOptionFlags;
pub type CFURLPathStyle = CFIndex;
/* typedef CF_ENUM(CFIndex, CFURLPathStyle) */
pub const kCFURLPOSIXPathStyle: CFURLPathStyle = 0;
pub const kCFURLHFSPathStyle: CFURLPathStyle = 1;
pub const kCFURLWindowsPathStyle: CFURLPathStyle = 2;
// static kCFURLBookmarkCreationPreferFileIDResolutionMask: CFURLBookmarkCreationOptions =
// (1 << 8) as u32;
// static kCFURLBookmarkCreationMinimalBookmarkMask: CFURLBookmarkCreationOptions =
@@ -149,6 +174,7 @@ extern {
//fn CFURLCreateFromFSRef
//fn CFURLCreateWithBytes
//fn CFURLCreateWithFileSystemPath
fn CFURLCreateWithFileSystemPath(allocator: CFAllocatorRef, filePath: CFStringRef, pathStyle: CFURLPathStyle, isDirectory: Boolean) -> CFURLRef;
//fn CFURLCreateWithFileSystemPathRelativeToBase
//fn CFURLCreateWithString(allocator: CFAllocatorRef, urlString: CFStringRef,
// baseURL: CFURLRef) -> CFURLRef;
@@ -208,3 +234,11 @@ extern {
//fn CFURLStartAccessingSecurityScopedResource
//fn CFURLStopAccessingSecurityScopedResource
}
#[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!("file:///usr/local/foo/" == cfurl.get_string().to_string().as_slice());
}