#![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};
use libc::c_void;
use std::mem;
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() -> 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;
pub const kCFRunLoopRunFinished: i32 = 1;
pub const kCFRunLoopRunStopped: i32 = 2;
pub const kCFRunLoopRunTimedOut: i32 = 3;
pub const kCFRunLoopRunHandledSource: i32 = 4;
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,
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;
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() -> 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 {
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 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 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 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);
}
#[cfg(test)]
mod test {
use super::*;
use 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();
}
}