Skip to content

Commit

Permalink
Followup to using non-blocking calls more widely (#209)
Browse files Browse the repository at this point in the history
This is a followup to #208 to tidy up the `FfiCallbackFuncrtion`
extensions in `extensions.rs`.

Most notably, it generalizes the `is_blocking` function to callback
functions that do not have a return and are not expected to error, ever.
  • Loading branch information
jhugman authored Jan 23, 2025
1 parent 92f9394 commit cf200cc
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 24 deletions.
35 changes: 23 additions & 12 deletions crates/ubrn_bindgen/src/bindings/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,25 +370,22 @@ pub(crate) impl FfiCallbackFunction {
}

fn is_exported(&self) -> bool {
let name = self.name();
[
"RustFutureContinuationCallback",
"CallbackInterfaceFree",
"ForeignFutureFree",
]
.contains(&name)
|| !name.starts_with("CallbackInterface")
!self.is_user_callback() && !self.is_free_callback()
}

fn is_rust_calling_js(&self) -> bool {
!self.is_future_callback() || self.name() == "RustFutureContinuationCallback"
!self.is_future_callback() || self.is_continuation_callback()
}

fn returns_result(&self) -> bool {
self.is_rust_calling_js()
!self.is_future_callback()
&& !self.is_free_callback()
&& !self.has_rust_call_status_arg()
&& self.name() != "RustFutureContinuationCallback"
&& !self.is_continuation_callback()
}

fn is_continuation_callback(&self) -> bool {
is_continuation(self.name())
}

fn is_free_callback(&self) -> bool {
Expand All @@ -399,6 +396,10 @@ pub(crate) impl FfiCallbackFunction {
is_future(self.name())
}

fn is_user_callback(&self) -> bool {
self.name().starts_with("CallbackInterface")
}

fn arg_return_type(&self) -> Option<FfiType> {
self.arguments()
.into_iter()
Expand All @@ -414,14 +415,24 @@ pub(crate) impl FfiCallbackFunction {
}

fn is_blocking(&self) -> bool {
!self.is_free_callback() && self.name() != "RustFutureContinuationCallback"
// If the callback returns something, or there's any chance of an error
// (even unexpected errors), then we should block before returning
// control back to Rust.
// In practice this means that all user code is blocking, and uniffi internal
// code is non-blocking: Future continuation callbacks, and free callback and
// free future callbacks.
self.arg_return_type().is_some() || self.has_rust_call_status_arg()
}

fn arguments_no_return(&self) -> impl Iterator<Item = &FfiArgument> {
self.arguments().into_iter().filter(|a| !a.is_return())
}
}

fn is_continuation(nm: &str) -> bool {
nm == "RustFutureContinuationCallback"
}

fn is_future(nm: &str) -> bool {
nm.starts_with("ForeignFuture") || nm.starts_with("RustFuture")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,9 @@ const {{ trait_impl }}: { vtable: {{ vtable|ffi_type_name }}; register: () => vo
vtable: {
{%- for (ffi_callback, meth) in vtable_methods %}
{{ meth.name()|fn_name }}: (
{%- for arg in ffi_callback.arguments() %}
{%- for arg in ffi_callback.arguments_no_return() %}
{{ arg.name()|var_name }}: {{ arg.type_().borrow()|ffi_type_name }}{% if !loop.last || ffi_callback.has_rust_call_status_arg() %},{% endif %}
{%- endfor -%}
{%- if ffi_callback.has_rust_call_status_arg() %}
uniffiCallStatus: UniffiRustCallStatus
{%- endif %}
) => {
const uniffiMakeCall = {# space #}
{%- if meth.is_async() %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

import {
type StructuralEquality as UniffiStructuralEquality,
type UniffiReferenceHolder,
type UniffiRustArcPtr,
type UniffiForeignFuture as RuntimeUniffiForeignFuture,
type UniffiRustCallStatus,
type UniffiRustArcPtr,
type UniffiRustFutureContinuationCallback as RuntimeUniffiRustFutureContinuationCallback,
type UniffiResult,
} from 'uniffi-bindgen-react-native';
Expand Down Expand Up @@ -37,12 +37,9 @@ export default getter;
{%- match def %}
{%- when FfiDefinition::CallbackFunction(callback) %}
{% call exported(callback) %}type {{ callback.name()|ffi_callback_name }} = (
{%- for arg in callback.arguments() %}
{%- for arg in callback.arguments_no_return() %}
{{- arg.name()|var_name }}: {{ arg.type_().borrow()|ffi_type_name }}{% if !loop.last %}, {% endif %}
{%- endfor %}
{%- if callback.has_rust_call_status_arg() -%}
{% if callback.arguments().len() > 0 %}, {% endif %}callStatus: UniffiRustCallStatus
{%- endif %}) => {# space #}
{%- endfor %}) => {# space #}
{%- if callback.returns_result() %}
{%- match callback.arg_return_type() %}
{%- when Some(return_type) %}UniffiResult<{{ return_type|ffi_type_name }}>
Expand Down Expand Up @@ -89,5 +86,9 @@ const isRustFutureContinuationCallbackTypeCompatible: UniffiStructuralEquality<
RuntimeUniffiRustFutureContinuationCallback,
UniffiRustFutureContinuationCallback
> = true;
const isUniffiForeignFutureTypeCompatible: UniffiStructuralEquality<
RuntimeUniffiForeignFuture,
UniffiForeignFuture
> = true;

{%- import "macros.ts" as ts %}
2 changes: 1 addition & 1 deletion typescript/src/async-callbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function emptyLowerError<E>(e: E): UniffiByteArray {
}

// Callbacks passed into Rust.
export type UniffiForeignFutureFree = (handle: bigint) => void;
type UniffiForeignFutureFree = (handle: bigint) => void;

export type UniffiForeignFuture = {
handle: bigint;
Expand Down

0 comments on commit cf200cc

Please sign in to comment.