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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
//! Proxy for a Dart [Completer].
//!
//! Rust doesn't have a direct access to a Dart [Completer], but holds a
//! [`Dart_PersistentHandle`] to the [Completer] instance. All manipulations
//! happen on the Dart side.
//!
//! Dart side must register these function during the FFI initialization phase:
//! after Dart DL API is initialized and before any other exported Rust function
//! is called.
//!
//! [Completer]: https://api.dart.dev/dart-async/Completer-class.html
use std::{marker::PhantomData, time::Duration};
use dart_sys::{Dart_Handle, Dart_PersistentHandle};
use medea_macro::dart_bridge;
use crate::{
api::{utils::DartError, DartValue},
platform::dart::utils::{dart_api, dart_future::FutureFromDart},
};
#[dart_bridge("flutter/lib/src/native/ffi/completer.g.dart")]
mod completer {
use dart_sys::Dart_Handle;
use crate::api::{utils::DartError, DartValue};
extern "C" {
/// Returns a [`Dart_Handle`] to a new Dart [Completer].
///
/// [Completer]: https://api.dart.dev/dart-async/Completer-class.html
pub fn init() -> Dart_Handle;
/// Pointer to an extern function that invokes the [complete()] method
/// with the provided [`DartValue`] on the provided
/// [`Dart_Handle`] pointing to the Dart [Completer] object.
///
/// [complete()]:
/// https://api.dart.dev/dart-async/Completer/complete.html
/// [Completer]: https://api.dart.dev/dart-async/Completer-class.html
pub fn complete(fut: Dart_Handle, val: DartValue);
/// Invokes the [completeError()][1] method with the provided
/// [`DartError`] on the provided [`Dart_Handle`] pointing to the Dart
/// [Completer] object.
///
/// [1]: https://api.dart.dev/dart-async/Completer/completeError.html
/// [Completer]: https://api.dart.dev/dart-async/Completer-class.html
pub fn complete_error(fut: Dart_Handle, val: DartError);
/// Calls the [future] getter on the provided [`Dart_Handle`] pointing
/// to the Dart [Completer] object.
///
/// This function will return [`Dart_Handle`] to the Dart [Future] which
/// can be returned to the Dart side.
///
/// [future]: https://api.dart.dev/dart-async/Completer/future.html
/// [Completer]: https://api.dart.dev/dart-async/Completer-class.html
/// [Future]: https://api.dart.dev/dart-async/Future-class.html
pub fn future(fut: Dart_Handle) -> Dart_Handle;
/// Returns a [`Dart_Handle`] to the Dart `Future` waiting for the
/// provided amount of time.
pub fn delayed(delay_ms: i32) -> Dart_Handle;
}
}
/// [`Future`] which resolves after the provided [`Duration`].
///
/// # Panics
///
/// Panics if the `DELAYED_FUTURE_FUNCTION` isn't set by the Dart side. This is
/// should be impossible case.
///
/// [`Future`]: std::future::Future
pub async fn delay_for(delay: Duration) {
#[allow(clippy::cast_possible_truncation)]
let delay = delay.as_millis() as i32;
let delayed = unsafe { completer::delayed(delay) };
let delayed_fut = unsafe { FutureFromDart::execute::<()>(delayed) };
delayed_fut.await.unwrap();
}
/// Dart [Future] which can be resolved from Rust.
///
/// [Future]: https://api.dart.dev/dart-async/Future-class.html
#[derive(Debug)]
pub struct Completer<T, E> {
/// [`Dart_PersistentHandle`] to the Dart [Completer][1] backing this
/// [`Completer`].
///
/// [1]: https://api.dart.dev/dart-async/Completer-class.html
handle: Dart_PersistentHandle,
/// Type with which [Future] can be successfully resolved.
///
/// [Future]: https://api.dart.dev/dart-async/Future-class.html
_success_kind: PhantomData<*const T>,
/// Type with which [Future] can be resolved on error.
///
/// [Future]: https://api.dart.dev/dart-async/Future-class.html
_error_kind: PhantomData<*const E>,
}
impl<T, E> Completer<T, E> {
/// Creates a new [`Dart_PersistentHandle`] for the Dart [Completer][1].
///
/// Persists the created [`Dart_Handle`] so it won't be moved by the Dart VM
/// GC.
///
/// [1]: https://api.dart.dev/dart-async/Completer-class.html
#[must_use]
pub fn new() -> Self {
let completer = unsafe { completer::init() };
let handle = unsafe { dart_api::new_persistent_handle(completer) };
Self {
handle,
_success_kind: PhantomData::default(),
_error_kind: PhantomData::default(),
}
}
/// Returns a [`Dart_Handle`] to the Dart [Future] controlled by this
/// [`Completer`].
///
/// [Future]: https://api.dart.dev/dart-async/Future-class.html
#[must_use]
pub fn future(&self) -> Dart_Handle {
let handle = unsafe { dart_api::handle_from_persistent(self.handle) };
unsafe { completer::future(handle) }
}
}
impl<T, E> Default for Completer<T, E> {
fn default() -> Self {
Self::new()
}
}
impl<T: Into<DartValue>, E> Completer<T, E> {
/// Successfully completes the underlying Dart [Future] with the provided
/// argument.
///
/// [Future]: https://api.dart.dev/dart-async/Future-class.html
pub fn complete(&self, arg: T) {
let handle = unsafe { dart_api::handle_from_persistent(self.handle) };
unsafe {
completer::complete(handle, arg.into());
}
}
}
impl<T> Completer<T, DartError> {
/// Completes the underlying Dart [Future] with the provided [`DartError`].
///
/// [Future]: https://api.dart.dev/dart-async/Future-class.html
pub fn complete_error(&self, e: DartError) {
let handle = unsafe { dart_api::handle_from_persistent(self.handle) };
unsafe {
completer::complete_error(handle, e);
}
}
}