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::{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 MacDispatcher {
27 pub fn new() -> Self {
28 MacDispatcher {
29 parker: Arc::new(Mutex::new(Parker::new())),
30 }
31 }
32}
33
34impl PlatformDispatcher for MacDispatcher {
35 fn is_main_thread(&self) -> bool {
36 let is_main_thread: BOOL = unsafe { msg_send![class!(NSThread), isMainThread] };
37 is_main_thread == YES
38 }
39
40 fn dispatch(&self, runnable: Runnable) {
41 unsafe {
42 dispatch_async_f(
43 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.try_into().unwrap(), 0),
44 runnable.into_raw() as *mut c_void,
45 Some(trampoline),
46 );
47 }
48 }
49
50 fn dispatch_on_main_thread(&self, runnable: Runnable) {
51 unsafe {
52 dispatch_async_f(
53 dispatch_get_main_queue(),
54 runnable.into_raw() as *mut c_void,
55 Some(trampoline),
56 );
57 }
58 }
59
60 fn dispatch_after(&self, duration: Duration, runnable: Runnable) {
61 unsafe {
62 let queue =
63 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.try_into().unwrap(), 0);
64 let when = dispatch_time(DISPATCH_TIME_NOW as u64, duration.as_nanos() as i64);
65 dispatch_after_f(
66 when,
67 queue,
68 runnable.into_raw() as *mut c_void,
69 Some(trampoline),
70 );
71 }
72 }
73
74 fn poll(&self, _background_only: bool) -> bool {
75 false
76 }
77
78 fn park(&self) {
79 self.parker.lock().park()
80 }
81
82 fn unparker(&self) -> Unparker {
83 self.parker.lock().unparker()
84 }
85}
86
87extern "C" fn trampoline(runnable: *mut c_void) {
88 let task = unsafe { Runnable::from_raw(runnable as *mut ()) };
89 task.run();
90}