1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
//! Executor of [`Future`]s for the Dart environment.
mod task;
use std::{future::Future, ptr, rc::Rc};
use dart_sys::{
Dart_CObject, Dart_CObject_Type_Dart_CObject_kInt64, Dart_Port,
_Dart_CObject__bindgen_ty_1,
};
use crate::{api::propagate_panic, platform::utils::dart_api};
pub use self::task::Task;
/// Runs a Rust [`Future`] on the current thread.
pub fn spawn(fut: impl Future<Output = ()> + 'static) {
Task::spawn(Box::pin(fut));
}
/// A [`Dart_Port`] used to send [`Task`]'s poll commands so Dart will poll Rust
/// [`Future`]s.
///
/// Must be initialized with the [`rust_executor_init()`] function during FFI
/// initialization.
static mut WAKE_PORT: Option<Dart_Port> = None;
/// Initializes Dart-driven async [`Task`] executor.
///
/// On a Dart side you should continuously read channel to get [`Task`]s
/// addresses for polling.
///
/// # Safety
///
/// Must ONLY be called by Dart during FFI initialization.
#[no_mangle]
pub unsafe extern "C" fn rust_executor_init(wake_port: Dart_Port) {
WAKE_PORT = Some(wake_port);
}
/// Polls the provided [`Task`].
///
/// # Safety
///
/// Valid [`Task`] pointer must be provided.
#[no_mangle]
pub unsafe extern "C" fn rust_executor_poll_task(task: ptr::NonNull<Task>) {
propagate_panic(move || {
_ = Rc::from_raw(task.as_ptr()).poll();
});
}
/// Commands an external Dart executor to poll the provided [`Task`].
///
/// Sends command that contains the provided [`Task`] to the configured
/// [`WAKE_PORT`]. When received, Dart must poll it by calling the
/// [`rust_executor_poll_task()`] function.
fn task_wake(task: Rc<Task>) {
let wake_port = unsafe { WAKE_PORT }.unwrap();
let task = Rc::into_raw(task);
let mut task_addr = Dart_CObject {
type_: Dart_CObject_Type_Dart_CObject_kInt64,
value: _Dart_CObject__bindgen_ty_1 {
as_int64: task as i64,
},
};
let enqueued =
unsafe { dart_api::post_c_object(wake_port, &mut task_addr) };
if !enqueued {
log::warn!("Could not send message to Dart's native port");
unsafe {
drop(Rc::from_raw(task));
}
}
}