diff options
Diffstat (limited to 'third_party/rust/core-foundation/src/runloop.rs')
-rw-r--r-- | third_party/rust/core-foundation/src/runloop.rs | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/third_party/rust/core-foundation/src/runloop.rs b/third_party/rust/core-foundation/src/runloop.rs new file mode 100644 index 0000000000..be06f4ec7f --- /dev/null +++ b/third_party/rust/core-foundation/src/runloop.rs @@ -0,0 +1,224 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_upper_case_globals)] + +pub use core_foundation_sys::runloop::*; +use core_foundation_sys::base::CFIndex; +use core_foundation_sys::base::{kCFAllocatorDefault, CFOptionFlags}; +use core_foundation_sys::string::CFStringRef; + +use base::{TCFType}; +use date::{CFAbsoluteTime, CFTimeInterval}; +use filedescriptor::CFFileDescriptor; +use string::{CFString}; + +pub type CFRunLoopMode = CFStringRef; + + +declare_TCFType!(CFRunLoop, CFRunLoopRef); +impl_TCFType!(CFRunLoop, CFRunLoopRef, CFRunLoopGetTypeID); +impl_CFTypeDescription!(CFRunLoop); + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum CFRunLoopRunResult { + Finished = 1, + Stopped = 2, + TimedOut = 3, + HandledSource = 4, +} + +impl CFRunLoop { + pub fn get_current() -> CFRunLoop { + unsafe { + let run_loop_ref = CFRunLoopGetCurrent(); + TCFType::wrap_under_get_rule(run_loop_ref) + } + } + + pub fn get_main() -> CFRunLoop { + unsafe { + let run_loop_ref = CFRunLoopGetMain(); + TCFType::wrap_under_get_rule(run_loop_ref) + } + } + + pub fn run_current() { + unsafe { + CFRunLoopRun(); + } + } + + pub fn run_in_mode( + mode: CFStringRef, + duration: std::time::Duration, + return_after_source_handled: bool, + ) -> CFRunLoopRunResult { + let seconds = duration.as_secs_f64(); + let return_after_source_handled = if return_after_source_handled { 1 } else { 0 }; + + unsafe { + match CFRunLoopRunInMode(mode, seconds, return_after_source_handled) { + 2 => CFRunLoopRunResult::Stopped, + 3 => CFRunLoopRunResult::TimedOut, + 4 => CFRunLoopRunResult::HandledSource, + _ => CFRunLoopRunResult::Finished, + } + } + } + + pub fn stop(&self) { + unsafe { + CFRunLoopStop(self.0); + } + } + + pub fn current_mode(&self) -> Option<String> { + unsafe { + let string_ref = CFRunLoopCopyCurrentMode(self.0); + if string_ref.is_null() { + return None; + } + + let cf_string: CFString = TCFType::wrap_under_create_rule(string_ref); + Some(cf_string.to_string()) + } + } + + pub fn contains_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) -> bool { + unsafe { + CFRunLoopContainsTimer(self.0, timer.0, mode) != 0 + } + } + + pub fn add_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) { + unsafe { + CFRunLoopAddTimer(self.0, timer.0, mode); + } + } + + pub fn remove_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) { + unsafe { + CFRunLoopRemoveTimer(self.0, timer.0, mode); + } + } + + pub fn contains_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) -> bool { + unsafe { + CFRunLoopContainsSource(self.0, source.0, mode) != 0 + } + } + + pub fn add_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) { + unsafe { + CFRunLoopAddSource(self.0, source.0, mode); + } + } + + pub fn remove_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) { + unsafe { + CFRunLoopRemoveSource(self.0, source.0, mode); + } + } + + pub fn contains_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) -> bool { + unsafe { + CFRunLoopContainsObserver(self.0, observer.0, mode) != 0 + } + } + + pub fn add_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) { + unsafe { + CFRunLoopAddObserver(self.0, observer.0, mode); + } + } + + pub fn remove_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) { + unsafe { + CFRunLoopRemoveObserver(self.0, observer.0, mode); + } + } + +} + + +declare_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef); +impl_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef, CFRunLoopTimerGetTypeID); + +impl CFRunLoopTimer { + pub fn new(fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext) -> CFRunLoopTimer { + unsafe { + let timer_ref = CFRunLoopTimerCreate(kCFAllocatorDefault, fireDate, interval, flags, order, callout, context); + TCFType::wrap_under_create_rule(timer_ref) + } + } +} + + +declare_TCFType!(CFRunLoopSource, CFRunLoopSourceRef); +impl_TCFType!(CFRunLoopSource, CFRunLoopSourceRef, CFRunLoopSourceGetTypeID); + +impl CFRunLoopSource { + pub fn from_file_descriptor(fd: &CFFileDescriptor, order: CFIndex) -> Option<CFRunLoopSource> { + fd.to_run_loop_source(order) + } +} + +declare_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef); +impl_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef, CFRunLoopObserverGetTypeID); + +#[cfg(test)] +mod test { + use super::*; + use date::{CFDate, CFAbsoluteTime}; + use std::mem; + use std::os::raw::c_void; + use std::sync::mpsc; + + #[test] + fn wait_200_milliseconds() { + let run_loop = CFRunLoop::get_current(); + + let now = CFDate::now().abs_time(); + let (elapsed_tx, elapsed_rx) = mpsc::channel(); + let mut info = Info { + start_time: now, + elapsed_tx, + }; + let mut context = CFRunLoopTimerContext { + version: 0, + info: &mut info as *mut _ as *mut c_void, + retain: None, + release: None, + copyDescription: None, + }; + + let run_loop_timer = CFRunLoopTimer::new(now + 0.20f64, 0f64, 0, 0, timer_popped, &mut context); + unsafe { + run_loop.add_timer(&run_loop_timer, kCFRunLoopDefaultMode); + } + CFRunLoop::run_current(); + let elapsed = elapsed_rx.try_recv().unwrap(); + println!("wait_200_milliseconds, elapsed: {}", elapsed); + assert!(elapsed > 0.19 && elapsed < 0.35); + } + + struct Info { + start_time: CFAbsoluteTime, + elapsed_tx: mpsc::Sender<f64>, + } + + extern "C" fn timer_popped(_timer: CFRunLoopTimerRef, raw_info: *mut c_void) { + let info: *mut Info = unsafe { mem::transmute(raw_info) }; + let now = CFDate::now().abs_time(); + let elapsed = now - unsafe { (*info).start_time }; + let _ = unsafe { (*info).elapsed_tx.send(elapsed) }; + CFRunLoop::get_current().stop(); + } +} |