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, ptr::NonNull, sync::Arc, time::Duration};
15
16/// All items in the generated file are marked as pub, so we're gonna wrap it in a separate mod to prevent
17/// these pub items from leaking into public API.
18pub(crate) mod dispatch_sys {
19 include!(concat!(env!("OUT_DIR"), "/dispatch_sys.rs"));
20}
21
22use dispatch_sys::*;
23pub(crate) fn dispatch_get_main_queue() -> dispatch_queue_t {
24 unsafe { &_dispatch_main_q as *const _ as dispatch_queue_t }
25}
26
27pub(crate) struct MacDispatcher {
28 parker: Arc<Mutex<Parker>>,
29}
30
31impl Default for MacDispatcher {
32 fn default() -> Self {
33 Self::new()
34 }
35}
36
37impl MacDispatcher {
38 pub fn new() -> Self {
39 MacDispatcher {
40 parker: Arc::new(Mutex::new(Parker::new())),
41 }
42 }
43}
44
45impl PlatformDispatcher for MacDispatcher {
46 fn is_main_thread(&self) -> bool {
47 let is_main_thread: BOOL = unsafe { msg_send![class!(NSThread), isMainThread] };
48 is_main_thread == YES
49 }
50
51 fn dispatch(&self, runnable: Runnable, _: Option<TaskLabel>) {
52 unsafe {
53 dispatch_async_f(
54 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.try_into().unwrap(), 0),
55 runnable.into_raw().as_ptr() as *mut c_void,
56 Some(trampoline),
57 );
58 }
59 }
60
61 fn dispatch_on_main_thread(&self, runnable: Runnable) {
62 unsafe {
63 dispatch_async_f(
64 dispatch_get_main_queue(),
65 runnable.into_raw().as_ptr() as *mut c_void,
66 Some(trampoline),
67 );
68 }
69 }
70
71 fn dispatch_after(&self, duration: Duration, runnable: Runnable) {
72 unsafe {
73 let queue =
74 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.try_into().unwrap(), 0);
75 let when = dispatch_time(DISPATCH_TIME_NOW as u64, duration.as_nanos() as i64);
76 dispatch_after_f(
77 when,
78 queue,
79 runnable.into_raw().as_ptr() as *mut c_void,
80 Some(trampoline),
81 );
82 }
83 }
84
85 fn tick(&self, _background_only: bool) -> bool {
86 false
87 }
88
89 fn park(&self) {
90 self.parker.lock().park()
91 }
92
93 fn unparker(&self) -> Unparker {
94 self.parker.lock().unparker()
95 }
96}
97
98extern "C" fn trampoline(runnable: *mut c_void) {
99 let task = unsafe { Runnable::<()>::from_raw(NonNull::new_unchecked(runnable as *mut ())) };
100 task.run();
101}