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 std::{
13 ffi::c_void,
14 ptr::{NonNull, addr_of},
15 time::Duration,
16};
17
18/// All items in the generated file are marked as pub, so we're gonna wrap it in a separate mod to prevent
19/// these pub items from leaking into public API.
20pub(crate) mod dispatch_sys {
21 include!(concat!(env!("OUT_DIR"), "/dispatch_sys.rs"));
22}
23
24use dispatch_sys::*;
25pub(crate) fn dispatch_get_main_queue() -> dispatch_queue_t {
26 addr_of!(_dispatch_main_q) as *const _ as dispatch_queue_t
27}
28
29pub(crate) struct MacDispatcher;
30
31impl PlatformDispatcher for MacDispatcher {
32 fn is_main_thread(&self) -> bool {
33 let is_main_thread: BOOL = unsafe { msg_send![class!(NSThread), isMainThread] };
34 is_main_thread == YES
35 }
36
37 fn dispatch(&self, runnable: Runnable, _: Option<TaskLabel>) {
38 unsafe {
39 dispatch_async_f(
40 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH.try_into().unwrap(), 0),
41 runnable.into_raw().as_ptr() as *mut c_void,
42 Some(trampoline),
43 );
44 }
45 }
46
47 fn dispatch_on_main_thread(&self, runnable: Runnable) {
48 unsafe {
49 dispatch_async_f(
50 dispatch_get_main_queue(),
51 runnable.into_raw().as_ptr() as *mut c_void,
52 Some(trampoline),
53 );
54 }
55 }
56
57 fn dispatch_after(&self, duration: Duration, runnable: Runnable) {
58 unsafe {
59 let queue =
60 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH.try_into().unwrap(), 0);
61 let when = dispatch_time(DISPATCH_TIME_NOW as u64, duration.as_nanos() as i64);
62 dispatch_after_f(
63 when,
64 queue,
65 runnable.into_raw().as_ptr() as *mut c_void,
66 Some(trampoline),
67 );
68 }
69 }
70}
71
72extern "C" fn trampoline(runnable: *mut c_void) {
73 let task = unsafe { Runnable::<()>::from_raw(NonNull::new_unchecked(runnable as *mut ())) };
74 task.run();
75}