dispatcher.rs

 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 std::{
13    ffi::c_void,
14    time::{Duration, SystemTime},
15};
16
17include!(concat!(env!("OUT_DIR"), "/dispatch_sys.rs"));
18
19pub fn dispatch_get_main_queue() -> dispatch_queue_t {
20    unsafe { &_dispatch_main_q as *const _ as dispatch_queue_t }
21}
22
23pub struct MacDispatcher;
24
25impl PlatformDispatcher for MacDispatcher {
26    fn is_main_thread(&self) -> bool {
27        let is_main_thread: BOOL = unsafe { msg_send![class!(NSThread), isMainThread] };
28        is_main_thread == YES
29    }
30
31    fn dispatch(&self, runnable: Runnable) {
32        unsafe {
33            dispatch_async_f(
34                dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.try_into().unwrap(), 0),
35                runnable.into_raw() as *mut c_void,
36                Some(trampoline),
37            );
38        }
39    }
40
41    fn dispatch_on_main_thread(&self, runnable: Runnable) {
42        unsafe {
43            dispatch_async_f(
44                dispatch_get_main_queue(),
45                runnable.into_raw() as *mut c_void,
46                Some(trampoline),
47            );
48        }
49    }
50
51    fn dispatch_after(&self, duration: Duration, runnable: Runnable) {
52        let now = SystemTime::now();
53        let after_duration = now
54            .duration_since(SystemTime::UNIX_EPOCH)
55            .unwrap()
56            .as_nanos() as u64
57            + duration.as_nanos() as u64;
58        unsafe {
59            let queue =
60                dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.try_into().unwrap(), 0);
61            let when = dispatch_time(0, after_duration as i64);
62            dispatch_after_f(
63                when,
64                queue,
65                runnable.into_raw() 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(runnable as *mut ()) };
74    task.run();
75}
76
77// #include <dispatch/dispatch.h>
78
79// int main(void) {
80
81//     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
82//         // Do some lengthy background work here...
83//         printf("Background Work\n");
84
85//         dispatch_async(dispatch_get_main_queue(), ^{
86//             // Once done, update your UI on the main queue here.
87//             printf("UI Updated\n");
88
89//         });
90//     });
91
92//     sleep(3);  // prevent the program from terminating immediately
93
94//     return 0;
95// }
96// ```