dispatch/
lib.rs

1/*!
2Rust wrapper for Apple's Grand Central Dispatch (GCD).
3
4GCD is an implementation of task parallelism that allows tasks to be submitted
5to queues where they are scheduled to execute.
6
7For more information, see Apple's [Grand Central Dispatch reference](
8https://developer.apple.com/library/mac/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html).
9
10# Serial Queues
11
12Serial queues execute tasks serially in FIFO order. The application's main
13queue is serial and can be accessed through the `Queue::main` function.
14
15```
16use dispatch::{Queue, QueueAttribute};
17
18let queue = Queue::create("com.example.rust", QueueAttribute::Serial);
19queue.exec_async(|| println!("Hello"));
20queue.exec_async(|| println!("World"));
21```
22
23# Concurrent Queues
24
25Concurrent dispatch queues execute tasks concurrently. GCD provides global
26concurrent queues that can be accessed through the `Queue::global` function.
27
28`Queue` has two methods that can simplify processing data in parallel, `foreach`
29and `map`:
30
31```
32use dispatch::{Queue, QueuePriority};
33
34let queue = Queue::global(QueuePriority::Default);
35
36let mut nums = vec![1, 2];
37queue.for_each(&mut nums, |x| *x += 1);
38assert!(nums == [2, 3]);
39
40let nums = queue.map(nums, |x| x.to_string());
41assert!(nums[0] == "2");
42```
43*/
44
45#![warn(missing_docs)]
46
47use std::error::Error;
48use std::fmt;
49use std::mem;
50use std::os::raw::c_void;
51use std::time::Duration;
52
53use crate::ffi::*;
54
55pub use crate::group::{Group, GroupGuard};
56pub use crate::once::Once;
57pub use crate::queue::{Queue, QueueAttribute, QueuePriority, SuspendGuard};
58pub use crate::sem::{Semaphore, SemaphoreGuard};
59
60/// Raw foreign function interface for libdispatch.
61pub mod ffi;
62mod group;
63mod queue;
64mod once;
65mod sem;
66
67/// An error indicating a wait timed out.
68#[derive(Clone, Debug)]
69pub struct WaitTimeout {
70    duration: Duration,
71}
72
73impl fmt::Display for WaitTimeout {
74    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75        write!(f, "Wait timed out after duration {:?}", self.duration)
76    }
77}
78
79impl Error for WaitTimeout { }
80
81fn time_after_delay(delay: Duration) -> dispatch_time_t {
82    delay.as_secs().checked_mul(1_000_000_000).and_then(|i| {
83        i.checked_add(delay.subsec_nanos() as u64)
84    }).and_then(|i| {
85        if i < (i64::max_value() as u64) { Some(i as i64) } else { None }
86    }).map_or(DISPATCH_TIME_FOREVER, |i| unsafe {
87        dispatch_time(DISPATCH_TIME_NOW, i)
88    })
89}
90
91fn context_and_function<F>(closure: F) -> (*mut c_void, dispatch_function_t)
92        where F: FnOnce() {
93    extern fn work_execute_closure<F>(context: Box<F>) where F: FnOnce() {
94        (*context)();
95    }
96
97    let closure = Box::new(closure);
98    let func: extern fn(Box<F>) = work_execute_closure::<F>;
99    unsafe {
100        (mem::transmute(closure), mem::transmute(func))
101    }
102}
103
104fn context_and_sync_function<F>(closure: &mut Option<F>) ->
105        (*mut c_void, dispatch_function_t)
106        where F: FnOnce() {
107    extern fn work_read_closure<F>(context: &mut Option<F>) where F: FnOnce() {
108        // This is always passed Some, so it's safe to unwrap
109        let closure = context.take().unwrap();
110        closure();
111    }
112
113    let context: *mut Option<F> = closure;
114    let func: extern fn(&mut Option<F>) = work_read_closure::<F>;
115    unsafe {
116        (context as *mut c_void, mem::transmute(func))
117    }
118}
119
120fn context_and_apply_function<F>(closure: &F) ->
121        (*mut c_void, extern fn(*mut c_void, usize))
122        where F: Fn(usize) {
123    extern fn work_apply_closure<F>(context: &F, iter: usize)
124            where F: Fn(usize) {
125        context(iter);
126    }
127
128    let context: *const F = closure;
129    let func: extern fn(&F, usize) = work_apply_closure::<F>;
130    unsafe {
131        (context as *mut c_void, mem::transmute(func))
132    }
133}