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