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}