flutter_rust_bridge icon indicating copy to clipboard operation
flutter_rust_bridge copied to clipboard

Support receiving Dart closures as arguments

Open Desdaemon opened this issue 3 years ago • 2 comments

Is your feature request related to a problem? Please describe. Some issues (#136, #443) have requested the ability to call Dart functions/closures from the Rust context. This might be possible through the use of Pointer.fromFunction and js_sys::Function.

Describe the solution you'd like

  • A Rusty syntax for Dart closures: fn([...args: ArgType]) [-> ReturnType] (to be debated)
  • Automatic (un)marshalling of arguments and return values

Describe alternatives you've considered None

Additional context js_sys::Function has always allowed Rust to call JS closures, while the API surrounding DartHandle (Dart's Object) has always been difficult to consume for non-C coders. The reverse scenario of calling Rust functions from Dart is also possible via NativeFunction and wasm_bindgen::Closure, but might be out of scope for this issue.

Desdaemon avatar Sep 19 '22 17:09 Desdaemon

Note: dart-lang/ffi#129 has noted that any Dart closure must be invoked by the main Dart thread, which could cause some friction/performance issues for calling closures.

Desdaemon avatar Sep 19 '22 19:09 Desdaemon

Looks interesting!

The returned function address can only be invoked on the mutator (main) thread of the current isolate. It will abort the process if invoked on any other thread.

Yes I am thinking about this "main thread" limitation... Especially we are by default running rust code on thread pool, i.e. non-main thread.

Btw, I was thinking about using existing infrastructure + a map of integers to callbacks: https://github.com/fzyzcjy/flutter_rust_bridge/issues/141#issuecomment-954441728

fzyzcjy avatar Sep 19 '22 23:09 fzyzcjy

Some observations:

  • Pointer.fromFunction automatically (un)marshalls arguments and return values, but lacking a way to access APIs surrounding Dart_Handles (part of the deprecated extension API) it would be difficult to accept anything more complex than a byte buffer. Furthermore, many of these helpers must also be executed on the main thread, limiting their utility.
  • Perhaps Rust's thread safety can be used to make calling Dart closures less error-prone. The most straightforward observation is that Dart closures are !Send[^1]: they point to "code" that is only valid in the current thread. With this, we can modify Handler to take into account the sync-ness of the arguments, e.g. execute_sync may accept !Send arguments, as it is invoked in the same thread.
  • Linking against the Dart executable is proving more difficult than expected, although it might just be my lack of experience.

[^1]: It's not clear why extern "C" fn is Send while *mut T is neither Send nor Sync, though it might be related with the desire to make FFI easier.

Desdaemon avatar Oct 04 '22 21:10 Desdaemon

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Dec 04 '22 04:12 stale[bot]

Related: https://github.com/fzyzcjy/flutter_rust_bridge/pull/853

fzyzcjy avatar Dec 04 '22 05:12 fzyzcjy

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Feb 02 '23 20:02 stale[bot]

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new issue.

github-actions[bot] avatar Feb 24 '23 00:02 github-actions[bot]