Support receiving Dart closures as arguments
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.
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.
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
Some observations:
-
Pointer.fromFunctionautomatically (un)marshalls arguments and return values, but lacking a way to access APIs surroundingDart_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 modifyHandlerto take into account the sync-ness of the arguments, e.g.execute_syncmay accept!Sendarguments, 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.
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.
Related: https://github.com/fzyzcjy/flutter_rust_bridge/pull/853
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.
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.