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}