All changes in [[UnreleasedUniFFIVersion]].
- Fixed a memory leak in callback interface handling.
- The callback interface code was reworked to use vtables rather than a single callback method. See mozilla#1818 for details and how the other bindings were updated.
- Removed
FfiType::RustFutureContinuationData
.RustFutureContinuation
callbacks now take au64
handle.
- The
rust_future_continuation_callback_set
FFI function was removed.rust_future_poll
now inputs the callback pointer. External bindings authors will need to update their code.
- Rust traits
Display
,Hash
andEq
exposed to Kotlin and Swift #1817 - Foreign types can now implement trait interfaces #1791 and
the documentation
- UDL: use the
[WithForeign]
attribute - proc-macros: use the
#[uniffi::export(with_foreign)]
attribute
- UDL: use the
- Generated Python code is able to specify a package name for the module #1784
- UDL can describe async function #1834
- UDL files can reference types defined in procmacros in this crate - see the external types docs and also external trait interfaces #1831
- Add support for docstrings via procmacros #1862 and in UDL
- Objects can now be returned from functions/constructors/methods without wrapping them in an
Arc<>
.
- Switched to a patched version of
oneshot
so that consumers who usecargo vendor
don't vendorloom
and it's sub-dependencies likewindows
- Fixed regression in the name of error enums in Kotlin #1842
- Fix regression when error types are in dicts etc #1847
- Fixed several bugs with async functions were defined in multiple crates that get built together.
-
Proc-macros can now expose standard Rust traits (eg,
Display
,Eq
, etc) -
Fixed issues when trying to combine UDL and procmacros in the same crate when the "namespace" is different from the crate name. This meant that the "ffi namespace" has changed to consistently be the crate name, rather than either the crate name or the namespace name depending on whether the item was declared via a procmacro or UDL. This should be invisible in most cases, but custom build environments might require some changes. Specifically:
uniffi::generate_scaffolding(udl_path)
now uses the udl_path to locate the correspondingCargo.toml
, which is parsed to determine the crate name (ie, the name under the[lib]
entry). If your environment is such that Cargo.toml can't be located or parsed, you should instead useuniffi::generate_scaffolding_for_crate(udl_path, crate_name)
.- Similarly, when executing
uniffi_bindgen
from the command-line to generate bindings and when not using "library mode",Cargo.toml
will be located and parsed to determine the crate name. Specifying--crate-name
on the command-line can be used to avoid this and use the specified value.
-
Crates can now use proc-macros without UDL files to export their interface. See the "Procedural Macros: Attributes and Derives" manual section for details.
-
Custom Types are now supported for proc-macros, including a very low-friction way of exposing types implementing the new-type idiom.
-
Proc-macros: Added support for ByRef arguments
-
Proc-macros: Implemented custom type conversion error handling (https://mozilla.github.io/uniffi-rs/udl/custom_types.html#error-handling-during-conversion)
-
Error types must now implement
Error + Send + Sync + 'static
. -
Proc-macros: The
handle_unknown_callback_error
attribute is no longer needed for callback interface errors
- Updated the async functionality to correctly handle cancellation (#1669)
- Kotlin: Fixed low-level issue with exported async APIs
- Kotlin: Fixed empty records being exported as empty data classes in Kotlin. A class with a proper
equals
function should be used instead.
- Implementing
From<uniffi::UnexpectedUniFFICallbackError
is now optional for callback interface error types. If the error type implements that, things will continue to work as before. If not, then any unexpected callback error will result in a Rust panic.
uniffi_macros
: Force-include the Cargo.toml to read (#1683)
- Inline the metadata module in
uniffi_meta
to avoid a dependency ofuniffi_core
to avoid hitting an upstream bug during link time (#1666)
- Python: remove unused import (and unbreak Python 3.6 compatibility) (#1618)
- Python: Delay contract checks until after all functions are defined to avoid wrong ABI use (#1619)
- Kotlin: Fix error handling in async functions (#1614)
- ABI: Implemented a new callback-interface ABI that significantly improves performance on Python and Kotlin.
- UniFFI users will automatically get the benefits of this without any code changes.
- External bindings authors will need to update their bindings code. Please see Guidance for external bindings below for details.
- ABI: Changed API checksum handling. This affects external bindings authors who will need to update their code to work with the new system. See PR #1469 for details.
- Removed the long deprecated
ThreadSafe
attribute. External
types now require a valid crate name. Before the docs said it must be a crate name, but any string could be used as long as it was consistent with the external type map inuniffi.toml
.External
types must be available in the Rust crate root.- External bindings: The
ExternalBindingsConfig
trait was replaced withBindingsConfig
. External bindings implementations will need to make minor changes to implement the new trait instead. - Removed support for the
--config
flag when running thescaffolding
command. This flag has never an effect, because there was no scaffolding configuration options. - Python bindings are now more strict with their types. You can no longer pass strings to methods taking integers or floats, or floats to methods taking integers.
- Added "library mode" bindings generation using
generate --library [path-to-cdylib]
. This mode simplifies bindings generation, especially when you have dependencies between multiple UniFFIed crates. See the tutorial for a description. - The
include_scaffolding!()
macro must now either be called from your crate root or you must haveuse the_mod_that_calls_include_scaffolding::*
in your crate root. This was always the expectation, but wasn't required before. This will now start failing with errors that saycrate::UniFfiTag
does not exist. - proc-macros now work with many more types including type aliases, type paths, etc.
- The
uniffi_types
module is no longer needed when using proc-macros. - Traits can be exposed as a UniFFI
interface
by using a[Trait]
attribute in the UDL. See the documentation. - The
bytes
primitive type was added, it represents an array of bytes. It maps toByteArray
in Kotlin,bytes
in Python,String
withEncoding::BINARY
in Ruby andData
in Swift. (#1543) - Shortened
str()
representations of errors in Python to align with other exceptions in Python. Userepr()
or the{!r}
format to get the old representation back (#1556) - Methods implemented by standard Rust traits, such as
Debug
,Display
,Eq
andHash
can now be exposed over the FFI and bindings may implement special methods for them. See the documentation. - Added support for async/futures (#1409, #1515)
- Added constructor support to proc-macro frontend (#1518)
- Added support for field defaults to proc-macro frontend (#1560)
- Implemented proc-macro callback interface support (#1573)
- Python bindings now generate type stubs for all functions and types (#1506)
- Enforced checks for integer overflows in Python bindings (#1546)
- No more implicit conversion to integers/floats in Python (#1554)
- Enforced checks for integer overflows in Ruby bindings (#1572)
- Only UTF-8 valid strings are passed from Ruby to Rust (#1595)
- No more implicit conversion to integers/floats in Ruby (#1596)
- Updated Rust dependencies (#1495, #1583, #1569)
- Added type checking to strings/bytes for Python/Ruby (#1597)
- Implemented proc-macro external type support. This allows proc-macros to use types defined in UDL files from other crates, #1600
There are many breaking changes for external bindings - we hope there will be fewer in later releases, but we are laying the groundwork for some nice improvements. Significant patches to UniFFI's builtin bindings which you will need to port include:
- https://github.com/mozilla/uniffi-rs/commit/b9821439876c4fda05910313dec20906563b9909
- https://github.com/mozilla/uniffi-rs/commit/748f671bb1e88267522119ef6b9d98a8bcca1cc0
- https://github.com/mozilla/uniffi-rs/commit/07dcf3fe218d61e72073da72ba60ccbcd990bfb8
- https://github.com/mozilla/uniffi-rs/commit/45d572def4fd84120e9a8cdfcc75ff1eead00e81
- https://github.com/mozilla/uniffi-rs/commit/5e3dea51f17ae59a695a40e23479d57262968bb6
- https://github.com/mozilla/uniffi-rs/commit/2eb39753e060a28ee43eae90b996ff55f9b5e0bd
- https://github.com/mozilla/uniffi-rs/commit/323a4976992aff207db7946fc1f1cea614838f46
- mozilla#1497
- Update your
Cargo.toml
file to only depend on theuniffi
crate. Follow the directions from the Prerequisites section of the manual - Create a
uniffi-bindgen
binary for your project. Follow the directions from the Foreign language bindings section of the manual. - Uninstall the system-wide
uniffi_bindgen
:cargo uninstall uniffi_bindgen
. (Not strictly necessary, but you won't be using it anymore).
uniffi_bindgen
no longer provides a standalone binary. Having a standalone binary resulted in version mismatches when theuniffi
version specified inCargo.toml
didn't match theuniffi_bindgen
version installed on the system. Read The foreign language bindings section of the manual for how to set up auniffi-bindgen
binary that's local to your workspace.uniffi_bindgen
: Removed therun_main
function. It's moved touniffi::uniffi_bindgen_main
and now unconditionally succeeds rather than return aResult<()>
.
- The UniFFI crate organization has been significantly reworked:
- Projects that use UniFFI for binding/scaffolding generation now only need to depend on the
uniffi
crate and no longer need to depend onuniffi_bindgen
,uniffi_build
, etc. - The version numbers for each crate will no longer by kept in sync after this release. In particular
uniffi
will have breaking changes less often thanuniffi_bindgen
and other crates. This means that UniFFI consumers that specify their versions likeuniffi = "0.23"
will not need to bump theiruniffi
version as often as before.
- Projects that use UniFFI for binding/scaffolding generation now only need to depend on the
- Callback interface method calls are no longer logged (#1439)
uniffi_bindgen
: RenamedFFIArgument
,FFIFunction
andFFIType
toFfiArgument
,FfiFunction
andFfiType
- Added support for Swift external types
- Fix whitespace issues in scaffolding code breaking some versions of
rustfmt
- Fix ruby time support
- proc-macro
- Document (experimental) proc-macro support
- Support fallible functions
- Add Enum derive macro
- Add Error derive macro
- Replace checksum mechanism for function naming to give consistent results, independent of the target's endianness and bit width. This should have no visible effect on the outside.
uniffi_bindgen
: Renamed thethrows()
method ofFunction
,Method
, andConstructor
tothrows_str()
. Added a newthrows()
method that returns a boolean.
- Added support for exceptions in callback interface methods.
- Improved error stringifying on Kotlin and Ruby (the
message
andto_s
methods respectively).
- Renamed the
uniffi_bindgen
cydlib
argument tolib_file
, since it can also accept static libraries
- The
guess_crate_root
function is now public
- The UDL can contain identifiers which are also keywords in Swift, except in namespace functions.
- Fix callback interface init signature in Rust scaffolding
- Drop unused dependencies
- Update to MSRV 1.61.0
- Fixed a small bug in the 0.19.4 release, where the extraneous
r#
was present in the HashMap generated scaffolding.
- Implement Timestamp and Duration types in Ruby backend.
- Fixed in a bug where callback interfaces with arguments that include underscores do not get converted to camelCase on Swift.
- Fixed sccache issue with the
askama.toml
config file.
- Fixed the dependency from
uniffi_build
->uniffi_bindgen
- breaking for external binding generators, the
FFIType::RustArcPtr
now includes an innerString
. The string represents the name of the object theRustArcPtr
was derived from. - Kotlin exception names are now formatted as strict UpperCamelCase. Most names shouldn't change, but names that use one word with all caps will be affected (for example
URL
->Url
,JSONException
->JsonException
)
- The UDL can contain identifiers which are also keywords in Rust, Python or Kotlin.
- When custom types are used in function/method signatures UniFFI will now use
the UDL name for that type and create a typealias to the concrete type. In the
URL example,
this means the type will be now appear on Kotlin as
Url
rather thanURL
. Any existing code should continue to work because of the typealias, but this might affect your generated documentation and/or code completion. - For Python libraries the native library is now loaded from an absolute path. The shared library (
*.dll
on Windows,*.dylib
on macOS and.so
on other platforms) must be placed next to the Python wrapper code.
- Allow record types with arbitrary key types
- Record types can now contain any hashable type as its key. This is implemented for Kotlin, Python and Swift
- Python
- Added support for default values in dictionaries
- Generated Python code is now annotated to avoid mypy type checking
- Kotlin
- Added external type support
- Swift
- Fix test helper code to work with Swift 5.6
- Wrapped types have been renamed custom types.
- The UDL attribute is now
[Custom]
instead of[Wrapped]
- The trait name has been renamed to
UniffiCustomTypeConverter
fromUniffiCustomTypeWrapper
- The method names of that trait have been renamed to
into_custom()
/from_custom()
instead ofwrap()
andunwrap()
- The associated type has been renamed to
Builtin
instead ofWrapped
- The UDL attribute is now
- Custom types (formerly wrapped) now can be configured on the bindings side as well as the scaffolding side. See the "Custom Types" section of the manual for details.
- Kotlin now prefixes more local UniFFI variables with the
_
char to avoid conflicts with user-defined names. - Updated Kotlin to use the
FfiConverter
pattern (#1144) - Documentation updates: Added a doc comparing UniFFI to Diplomat. Added a README note describing the foreign languages we currently support.
- Fixed
RustCallStatus.__str__
implementation on Python - Fixed the version numbers in the CHANGELOG compare links.
- Error handling when converting custom types has been updated. If your
wrap()
function returns anErr
, in some cases it now may not panic but instead return the error declared by the function.
- Python: Added Callback Interface support
- Swift bindings can now omit argument labels in generated functions using
omit_argument_labels = true
in the configuration.
- Kotlin now generates valid code for optional timestamps/durations.
(Note that v0.15.0 was accidentally published, then yanked. v0.15.1 should be used instead)
- Previously, an interface which didn't declare a constructor got a default one anyway, making it impossible to decline to provide one. This is no longer true, so if your interface wants a constructor, you must add one explicitly.
-
Kotlin and Swift, like Python, now support simple "wrapped" types.
-
The Python backend has been refactored to more closely match the other backends, but this should be invisible to consumers.
-
The Swift and Kotlin backends have had minor tweaks.
-
The kotlin backend now explicitly checks for a null pointer in cases where it should be impossible to help us diagnose issues seen in the wild. See #1108.
- The
build_foreign_language_testcases!
macro now takes an array of UDL files as the first argument.
- Swift: Added Callback Interface support
- Swift: Refactored codegen to better match Kotlin / Unit of Code
- Kotlin: Added some defensive programming around
RustBufferBuilder.discard()
-
The Rust implementations of all
dictionary
,enum
orerror
types defined in UDL must be public. If you see errors like:private type <type-name> in public interface
or similar, please declare the types aspub
in your Rust code. -
Errors declared using the
[Error] enum
syntax will now expose the error string from Rust to the foreign language bindings. This reverts an unintended change in behaviour from the v0.13 release which made the error message inaccessible.
-
You can now use external types of various flavours - see the fine manual
-
An environment variable
UNIFFI_TESTS_DISABLE_EXTENSIONS
can disable foreign language bindings when running tests. See the contributing guide for more.
- Fixed an accidental regression in v0.13.0 where errors were no longer being coerced
to the correct type via
Into
. If the UDL declares a[Throws=ExampleError]
function or method, the underlying implementation can now return anything that isInto<ExampleError>
, matching the implicitInto
behavior of Rust's?
operator. - Fixed an accidental regression in v0.13.0 where the generated Rust scaffolding assumed
that the
HashMap
type would be in scope. It now uses fully-qualified type names in order to be more robust.
- UniFFI no longer has ffi-support as a dependency. This means it handles
panic logging on its own. If you previously enabled the
log_panics
feature forffi-support
, now you should enable it foruniffi
. - The Swift bindings now explicitly generate two separate Swift modules, one for
the high-level Swift code and one for the low-level C FFI. This change is intended
to simplify distribution of the bindings via Swift packages, but brings with it
some changes to the generated file layout.
- For an interface namespace "example", we now generate:
- A bridged C module named "exampleFFI" containing the low-level C FFI,
consisting of an
exampleFFI.h
file and matchingexampleFFI.modulemap
file. The name can be customized using theffi_module_name
config option. - A Swift module named "example" containing the high-level Swift bindings,
which imports and uses the low-level C FFI. The name can be customized using
the
module_name
config option.
- A bridged C module named "exampleFFI" containing the low-level C FFI,
consisting of an
- For an interface namespace "example", we now generate:
- Python timestamps will now be in UTC and timezone-aware rather than naive.
- Kotlin exceptions names will now replace a trailing "Error" with "Exception" rather than appending the string (FooException instead of FooErrorException)
- JNA 5.7 or greater is required for Kotlin consumers
- Both python and ruby backends now handle U16 correctly.
- Error variants can now contain named fields, similar to Enum variants
- Replaced the
ViaFfi
trait with theFfiConverter
trait.FfiConverter
is a more flexible version ofViaFfi
because it can convert any Rust type to/from an Ffi type, rather than only Self. This allows for using UniFFI with a type defined in an external crate.
- It is now possible to use Object instances as fields in Records or Enums, to pass them as arguments,
and to return them from function and method calls. They should for the most part behave just like
a host language object, and their lifecycle is managed transparently using Rust's
Arc<T>
type.- Reference cycles that include Rust objects will not be garbage collected; if you cannot avoid
creating reference cycles you may need to use Rust's
Weak<T>
type to help break them. - In the Kotlin bindings, Object instances must be manually freed by calling their
destroy()
method or by using their.use
block helper method. Records or Enums that contain an Object instance now also have adestroy()
method and must be similarly disposed of after use.
- Reference cycles that include Rust objects will not be garbage collected; if you cannot avoid
creating reference cycles you may need to use Rust's
- Kotlin objects now implement
AutoCloseable
by default; closing an object instance is equivalent to calling itsdestroy()
method.
- All interface implementations must now be
Sync + Send
, and Rust will give a compile-time error if they are not. This makes the[Threadsafe]
annotation redundant, so it is now deprecated and will be removed in a future release. More details on the motivation for this change can be found in ADR-0004.
- Swift structs and Kotlin data classes generated from
dictionary
are now mutable by default:- Swift now uses
var
instead oflet
- Kotlin now uses
var
instead ofval
- Swift now uses
- Kotlin objects can now safely have their
destroy()
method or.use
block execute concurrently with other method calls. It's recommended that you not do this, but if you accidentally do so, it will now work correctly rather than triggering a panic in the underlying Rust code.
- Two new built-in datatypes have been added: the
timestamp
type for representing moments in time, and theduration
type for representing a difference between two timestamps. These mirror thestd::time::{SystemTime, Duration}
types from Rust. Thanks to @npars for contributing this feature!- This is a breaking change as it may conflict with user-declared
timestamp
orduration
types in existing.udl
files.
- This is a breaking change as it may conflict with user-declared
- A new Ruby codegen backend has been added. You can now call
uniffi-bindgen -l ruby
to generate a Ruby module that wraps a UniFFI Rust component. Thanks to @saks for contributing this backend!- When running
cargo test
locally, you will need a recent version of Ruby and theffi
gem in order to successfully execute the Ruby backend tests.
- When running
- Threadsafe Object methods can now use
self: Arc<Self>
as the method receiver in the underlying Rust code, in addition to the defaultself: &Self
. To do so, annotate the method with[Self=ByArc]
in the.udl
file and update the corresponding Rust method signature to match. This will not change the generated foreign-language bindings in any way but may be useful for more explicit management of Object references in the Rust code.
- Kotlin: Fixed buggy codegen for optional primitive types like
i32?
; on earlier versions this would generate invalid Kotlin code which would fail to compile.
- Support for non-
[Threadsafe]
interfaces has been deprecated. A future release will require that all interface implementations beSync + Send
, making the[Threadsafe]
annotation redundant.
- Errors when parsing a
.udl
file are now marginally more useful (they're still not great, but they're better). - Generated code should now be deterministic between runs with the same input file and version of UniFFI. Previously, the generated code could depend on the iteration order of an internal hash table.
- Swift: Generated Swift Enums now conform to
Hashable
by default. - Swift: There are now additional docs on how to consume the generated Swift bindings via XCode.
We did not maintain a changelog for previous releases.