dispatcher.rs

 1#![allow(non_upper_case_globals)]
 2#![allow(non_camel_case_types)]
 3#![allow(non_snake_case)]
 4
 5use crate::{PlatformDispatcher, TaskLabel};
 6use async_task::Runnable;
 7use objc::{
 8    class, msg_send,
 9    runtime::{BOOL, YES},
10    sel, sel_impl,
11};
12use parking::{Parker, Unparker};
13use parking_lot::Mutex;
14use std::{ffi::c_void, sync::Arc, time::Duration};
15
16include!(concat!(env!("OUT_DIR"), "/dispatch_sys.rs"));
17
18pub fn dispatch_get_main_queue() -> dispatch_queue_t {
19    unsafe { &_dispatch_main_q as *const _ as dispatch_queue_t }
20}
21
22pub struct MacDispatcher {
23    parker: Arc<Mutex<Parker>>,
24}
25
26impl Default for MacDispatcher {
27    fn default() -> Self {
28        Self::new()
29    }
30}
31
32impl MacDispatcher {
33    pub fn new() -> Self {
34        MacDispatcher {
35            parker: Arc::new(Mutex::new(Parker::new())),
36        }
37    }
38}
39
40impl PlatformDispatcher for MacDispatcher {
41    fn is_main_thread(&self) -> bool {
42        let is_main_thread: BOOL = unsafe { msg_send![class!(NSThread), isMainThread] };
43        is_main_thread == YES
44    }
45
46    fn dispatch(&self, runnable: Runnable, _: Option<TaskLabel>) {
47        unsafe {
48            dispatch_async_f(
49                dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.try_into().unwrap(), 0),
50                runnable.into_raw() as *mut c_void,
51                Some(trampoline),
52            );
53        }
54    }
55
56    fn dispatch_on_main_thread(&self, runnable: Runnable) {
57        unsafe {
58            dispatch_async_f(
59                dispatch_get_main_queue(),
60                runnable.into_raw() as *mut c_void,
61                Some(trampoline),
62            );
63        }
64    }
65
66    fn dispatch_after(&self, duration: Duration, runnable: Runnable) {
67        unsafe {
68            let queue =
69                dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.try_into().unwrap(), 0);
70            let when = dispatch_time(DISPATCH_TIME_NOW as u64, duration.as_nanos() as i64);
71            dispatch_after_f(
72                when,
73                queue,
74                runnable.into_raw() as *mut c_void,
75                Some(trampoline),
76            );
77        }
78    }
79
80    fn tick(&self, _background_only: bool) -> bool {
81        false
82    }
83
84    fn park(&self) {
85        self.parker.lock().park()
86    }
87
88    fn unparker(&self) -> Unparker {
89        self.parker.lock().unparker()
90    }
91}
92
93extern "C" fn trampoline(runnable: *mut c_void) {
94    let task = unsafe { Runnable::from_raw(runnable as *mut ()) };
95    task.run();
96}