medea_jason/platform/dart/utils/
function.rs

1//! Functionality for calling Dart closures from Rust.
2//!
3//! Dart DL API doesn't allow calling Dart closures directly. So Dart registers
4//! a static function that accepts and invokes the provided Dart closures.
5//!
6//! Dart side must register these function during the FFI initialization phase:
7//! after Dart DL API is initialized and before any other exported Rust function
8//! is called.
9
10use std::marker::PhantomData;
11
12use dart_sys::Dart_PersistentHandle;
13use flutter_rust_bridge::DartOpaque;
14use medea_macro::dart_bridge;
15
16use crate::{
17    api::DartValue,
18    platform::{Callback, utils::dart_api},
19};
20
21#[dart_bridge("flutter/lib/src/native/ffi/function.g.dart")]
22mod function {
23    use dart_sys::Dart_Handle;
24
25    use crate::{api::DartValue, platform::Error};
26
27    /// Invokes other Dart closures that accept a [`DartValue`] argument.
28    extern "C" {
29        pub fn caller(f: Dart_Handle, val: DartValue) -> Result<(), Error>;
30    }
31}
32
33impl<A: Into<DartValue>> Callback<A> {
34    /// Invokes the underlying [`Function`] (if any) passing the single provided
35    /// argument to it.
36    pub fn call1<T: Into<A>>(&self, arg: T) {
37        if let Some(f) = self.0.borrow().as_ref() {
38            f.call1(arg.into());
39        }
40    }
41}
42
43/// Dart closure that can be called from Rust.
44#[derive(Debug)]
45pub struct Function<T> {
46    /// [`Dart_PersistentHandle`] to the Dart closure that should be called.
47    dart_fn: Dart_PersistentHandle,
48
49    /// Type of this closure argument.
50    _arg: PhantomData<*const T>,
51}
52
53impl<T> Function<T> {
54    /// Creates a new [`Function`] from the provided [`Dart_Handle`] to a Dart
55    /// closure, and persists the provided [`Dart_Handle`] so it won't be moved
56    /// by the Dart VM GC.
57    ///
58    /// [`Dart_Handle`]: dart_sys::Dart_Handle
59    #[must_use]
60    pub fn new(cb: DartOpaque) -> Self {
61        let opaque = cb.into_inner().unwrap();
62        let ptr = opaque.create_dart_handle();
63        let dart_fn = unsafe { dart_api::new_persistent_handle(ptr.cast()) };
64
65        Self { dart_fn, _arg: PhantomData }
66    }
67}
68
69impl Function<()> {
70    /// Calls the underlying Dart closure.
71    pub fn call0(&self) {
72        self.call1(());
73    }
74}
75
76impl<T: Into<DartValue>> Function<T> {
77    /// Calls the underlying Dart closure with the provided argument.
78    pub fn call1(&self, arg: T) {
79        let fn_handle =
80            unsafe { dart_api::handle_from_persistent(self.dart_fn) };
81        unsafe { function::caller(fn_handle, arg.into()) }.unwrap();
82    }
83}
84
85impl<T> Drop for Function<T> {
86    /// Manually deallocates saved [`Dart_PersistentHandle`] so it won't leak.
87    fn drop(&mut self) {
88        unsafe {
89            dart_api::delete_persistent_handle(self.dart_fn);
90        }
91    }
92}