dispatcher.rs

 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}