Skip to content

Add support for UniFFI 0.31.2 #287 - #289

Open
colintheshots wants to merge 8 commits into
gobley:mainfrom
colintheshots:main
Open

Add support for UniFFI 0.31.2 #287#289
colintheshots wants to merge 8 commits into
gobley:mainfrom
colintheshots:main

Conversation

@colintheshots

@colintheshots colintheshots commented Jul 7, 2026

Copy link
Copy Markdown

Changes

  • Upgrade UniFFI from 0.29.5 to 0.31.2
  • Update Kotlin binding generation for the 0.30/0.31 API changes
  • Fail fast when a bare #[uniffi(default)] can't be default-constructed
  • Add snapshot tests for generated bindings

Testing

Unit tests (cargo test -p gobley-uniffi-bindgen):

  • gen_kotlin_multiplatform::record::tests::bare_default_allowed_when_all_fields_have_defaults
  • gen_kotlin_multiplatform::record::tests::bare_default_rejected_when_a_field_is_required
  • gen_kotlin_multiplatform::object::tests::bare_default_rejected_for_objects
  • snapshot_tests::snapshot_simple_functions
  • snapshot_tests::snapshot_records_with_defaults
  • snapshot_tests::snapshot_enums
  • snapshot_tests::snapshot_interface_with_methods
  • snapshot_tests::snapshot_error_types
  • snapshot_tests::snapshot_callback_interface
  • snapshot_tests::snapshot_trait_interface
  • snapshot_tests::snapshot_async_functions

Integration: ran the UniFFI Gradle test matrix (JVM + host native) for the coverall, futures, callbacks, and type-limits fixtures.

Notes

As a long-time Kotlin dev, I went over the changes by hand and got a human Rust reviewer to review the changes and identify issues I'd missed:
colintheshots#1

Colin Lee and others added 4 commits June 26, 2026 13:26
Rework gobley-uniffi-bindgen against the breaking external-binding-author
API changes in UniFFI 0.30/0.31 and bump the bindgen/Gradle plugin to 0.4.0.

- Migrate the object ABI to opaque 64-bit handles (Kotlin Long) instead of
  pointers, with Rust-vs-foreign handle disambiguation via the lowest bit.
- Reorder the callback-interface VTable to (free, clone, methods...) and add
  the new clone entry; use the odd-handle scheme in UniffiHandleMap.
- Migrate the async foreign-future drop model to UniffiForeignFutureDroppedCallback.
- Adapt the bindgen to the new APIs: vendor backend::filters/to_askama_error,
  FfiType::Handle, DefaultValue, self_type(), and ObjectTraitImplMetadata.
- Add #[uniffi::trait_interface] to UDL-declared foreign traits in fixtures and
  update the coverall strong-count expectation to the 0.31 handle-clone semantics.
- Add insta snapshot tests over representative UDL fixtures.
- Update the bindgen/UniFFI version mapping, tutorials, and CHANGELOG.

Co-authored-by: Cursor <cursoragent@cursor.com>
Widen JNA direct-mapped u8/u16 FFI return values to Int at the boundary
and lift them back to UByte/UShort, matching upstream UniFFI 0.31, and
update generated-code snapshots accordingly.

Enable the wasm-unstable-single-threaded feature for the coverall
fixture (UniFFI 0.31's wasm32 futures require it), and update the
coverall JVM/Android nodeTrait strong-count assertions to reflect 0.31
handle-clone semantics.

Co-authored-by: Cursor <cursoragent@cursor.com>
…erage

A bare `#[uniffi(default)]` (DefaultValue::Default) previously emitted
`TypeName()` for any named type, silently producing Kotlin that fails to
compile for objects, custom types, callbacks, and records with required
fields. Restore a clear generation-time error for those cases while still
allowing records whose fields all have defaults.

Add callback, trait (WithForeign), and async snapshot fixtures plus unit
tests covering the bare-default codegen behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
@colintheshots colintheshots changed the title Add support for UniFFI 0.31.2 Add support for UniFFI 0.31.2 #287 Jul 7, 2026
Colin Lee and others added 2 commits July 16, 2026 19:26
Mask widened 16-bit checksum returns so undefined upper register bits cannot cause false API mismatch failures.

Co-authored-by: Cursor <cursoragent@cursor.com>
@yukibtc

yukibtc commented Aug 3, 2026

Copy link
Copy Markdown

Hi @colintheshots, while testing this PR with UniFFI 0.31.2, I noticed that types declared in submodules of the same crate are treated as external. This generates references that do not exist.

Since UniFFI 0.31, module_path contains the full module path rather than only the crate name (changelog). Comparing crate_name() instead seems to fix the issue:

diff --git a/crates/gobley-uniffi-bindgen/src/gen_kotlin_multiplatform/mod.rs b/crates/gobley-uniffi-bindgen/src/gen_kotlin_multiplatform/mod.rs
--- a/crates/gobley-uniffi-bindgen/src/gen_kotlin_multiplatform/mod.rs
+++ b/crates/gobley-uniffi-bindgen/src/gen_kotlin_multiplatform/mod.rs
@@ -855,7 +855,7 @@ impl KotlinCodeOracle {
             FfiType::Handle => "Long".to_string(),
             FfiType::RustBuffer(maybe_external) => match maybe_external {
-                Some(external_meta) if external_meta.module_path != ci.crate_name() => {
+                Some(external_meta) if external_meta.crate_name() != ci.crate_name() => {
                     format!("RustBuffer{}", external_meta.name)
                 }
@@ -883,7 +883,7 @@ impl KotlinCodeOracle {
             FfiType::Handle => "int64_t".to_string(),
             FfiType::RustBuffer(maybe_external) => match maybe_external {
-                Some(external_meta) if external_meta.module_path != ci.crate_name() => {
+                Some(external_meta) if external_meta.crate_name() != ci.crate_name() => {
                     format!("RustBuffer{}", external_meta.name)
                 }
@@ -1298,7 +1298,7 @@ mod filters {
-        if metadata.module_path == ci.crate_name() {
+        if metadata.crate_name() == ci.crate_name() {
             return Ok(String::new());
         }
@@ -1312,7 +1312,7 @@ mod filters {
-        if metadata.module_path == ci.crate_name() {
+        if metadata.crate_name() == ci.crate_name() {
             return Ok(String::new());
         }

With this patch, the generated bindings no longer reference nonexistent per-type RustBuffer symbols.

Colin Lee and others added 2 commits August 4, 2026 17:56
Since UniFFI 0.31, ExternalFfiMetadata.module_path holds the full module
path rather than only the crate name, so types declared in submodules of
the same crate were misclassified as external and generated references to
nonexistent per-type RustBuffer symbols. Compare crate_name() instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
Fix external RustBuffer detection for same-crate submodule types
@colintheshots

Copy link
Copy Markdown
Author

I made that update and verified the changes.

@Psycarlo

Copy link
Copy Markdown

Merging this would be awesome

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants