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 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}