medea_jason/platform/dart/utils/
completer.rs

1//! Proxy for a Dart [Completer].
2//!
3//! Rust doesn't have a direct access to a Dart [Completer], but holds a
4//! [`Dart_PersistentHandle`] to the [Completer] instance. All manipulations
5//! happen on the Dart side.
6//!
7//! Dart side must register these function during the FFI initialization phase:
8//! after Dart DL API is initialized and before any other exported Rust function
9//! is called.
10//!
11//! [Completer]: https://api.dart.dev/dart-async/Completer-class.html
12
13use std::{marker::PhantomData, time::Duration};
14
15use dart_sys::{Dart_Handle, Dart_PersistentHandle};
16use medea_macro::dart_bridge;
17
18use crate::{
19    api::{DartValue, Error as DartError},
20    platform::dart::utils::{dart_api, dart_future::FutureFromDart},
21};
22
23#[dart_bridge("flutter/lib/src/native/ffi/completer.g.dart")]
24mod completer {
25    use dart_sys::Dart_Handle;
26
27    use crate::{
28        api::{DartValue, Error as DartError},
29        platform::Error,
30    };
31
32    extern "C" {
33        /// Returns a [`Dart_Handle`] to a new Dart [Completer].
34        ///
35        /// [Completer]: https://api.dart.dev/dart-async/Completer-class.html
36        pub fn init() -> Result<Dart_Handle, Error>;
37
38        /// Pointer to an extern function that invokes the [complete()] method
39        /// with the provided [`DartValue`] on the provided
40        /// [`Dart_Handle`] pointing to the Dart [Completer] object.
41        ///
42        /// [complete()]:
43        /// https://api.dart.dev/dart-async/Completer/complete.html
44        /// [Completer]: https://api.dart.dev/dart-async/Completer-class.html
45        pub fn complete(fut: Dart_Handle, val: DartValue) -> Result<(), Error>;
46
47        /// Invokes the [completeError()][1] method with the provided
48        /// [`DartError`] on the provided [`Dart_Handle`] pointing to the Dart
49        /// [Completer] object.
50        ///
51        /// [1]: https://api.dart.dev/dart-async/Completer/completeError.html
52        /// [Completer]: https://api.dart.dev/dart-async/Completer-class.html
53        pub fn complete_error(
54            fut: Dart_Handle,
55            val: DartError,
56        ) -> Result<(), Error>;
57
58        /// Calls the [future] getter on the provided [`Dart_Handle`] pointing
59        /// to the Dart [Completer] object.
60        ///
61        /// This function will return [`Dart_Handle`] to the Dart [Future] which
62        /// can be returned to the Dart side.
63        ///
64        /// [future]: https://api.dart.dev/dart-async/Completer/future.html
65        /// [Completer]: https://api.dart.dev/dart-async/Completer-class.html
66        /// [Future]: https://api.dart.dev/dart-async/Future-class.html
67        pub fn future(fut: Dart_Handle) -> Result<Dart_Handle, Error>;
68
69        /// Returns a [`Dart_Handle`] to the Dart `Future` waiting for the
70        /// provided amount of time.
71        pub fn delayed(delay_ms: i32) -> Result<Dart_Handle, Error>;
72    }
73}
74
75/// [`Future`] which resolves after the provided [`Duration`].
76///
77/// # Panics
78///
79/// Panics if the `DELAYED_FUTURE_FUNCTION` isn't set by the Dart side. This
80/// should be an impossible case.
81pub async fn delay_for(delay: Duration) {
82    #[expect( // overflow is unexpected
83        clippy::cast_possible_truncation,
84        reason = "overflow is unexpected",
85    )]
86    let delay = delay.as_millis() as i32;
87    let delayed = unsafe { completer::delayed(delay) }.unwrap();
88    let delayed_fut = unsafe { FutureFromDart::execute::<()>(delayed) };
89    delayed_fut.await.unwrap();
90}
91
92/// Dart [Future] which can be resolved from Rust.
93///
94/// [Future]: https://api.dart.dev/dart-async/Future-class.html
95#[derive(Debug)]
96pub struct Completer<T, E> {
97    /// [`Dart_PersistentHandle`] to the Dart [Completer][1] backing this
98    /// [`Completer`].
99    ///
100    /// [1]: https://api.dart.dev/dart-async/Completer-class.html
101    handle: Dart_PersistentHandle,
102
103    /// Type with which [Future] can be successfully resolved.
104    ///
105    /// [Future]: https://api.dart.dev/dart-async/Future-class.html
106    _success_kind: PhantomData<*const T>,
107
108    /// Type with which [Future] can be resolved on error.
109    ///
110    /// [Future]: https://api.dart.dev/dart-async/Future-class.html
111    _error_kind: PhantomData<*const E>,
112}
113
114impl<T, E> Completer<T, E> {
115    /// Creates a new [`Dart_PersistentHandle`] for the Dart [Completer][1].
116    ///
117    /// Persists the created [`Dart_Handle`] so it won't be moved by the Dart VM
118    /// GC.
119    ///
120    /// [1]: https://api.dart.dev/dart-async/Completer-class.html
121    #[must_use]
122    pub fn new() -> Self {
123        let completer = unsafe { completer::init() }.unwrap();
124        let handle = unsafe { dart_api::new_persistent_handle(completer) };
125        Self { handle, _success_kind: PhantomData, _error_kind: PhantomData }
126    }
127
128    /// Returns a [`Dart_Handle`] to the Dart [Future] controlled by this
129    /// [`Completer`].
130    ///
131    /// [Future]: https://api.dart.dev/dart-async/Future-class.html
132    #[must_use]
133    pub fn future(&self) -> Dart_Handle {
134        let handle = unsafe { dart_api::handle_from_persistent(self.handle) };
135        unsafe { completer::future(handle) }.unwrap()
136    }
137}
138
139impl<T, E> Default for Completer<T, E> {
140    fn default() -> Self {
141        Self::new()
142    }
143}
144
145impl<T: Into<DartValue>, E> Completer<T, E> {
146    /// Successfully completes the underlying Dart [Future] with the provided
147    /// argument.
148    ///
149    /// [Future]: https://api.dart.dev/dart-async/Future-class.html
150    pub fn complete(&self, arg: T) {
151        let handle = unsafe { dart_api::handle_from_persistent(self.handle) };
152        unsafe { completer::complete(handle, arg.into()) }.unwrap();
153    }
154}
155
156impl<T> Completer<T, DartError> {
157    /// Completes the underlying Dart [Future] with the provided [`DartError`].
158    ///
159    /// [Future]: https://api.dart.dev/dart-async/Future-class.html
160    pub fn complete_error(&self, e: DartError) {
161        let handle = unsafe { dart_api::handle_from_persistent(self.handle) };
162        unsafe { completer::complete_error(handle, e) }.unwrap();
163    }
164}