Remote types present an issue because we can't implement FFI traits like
`Lower` and `Lift` on them directly. The workaround is to only
implement the FFI trait for the current crate. If another crate
wants to use that impl, we need to implement it again by forwarding to
the initial implementation.
Historically, UDL and proc-macros have approached this differently which
has lead to a lot of extra complexity and confusion. This change aligns
them on a common system: By default, we implement traits for all crates
(a "blanket impl"). However, users can opt-in to only implementing it
for the current crate ("a local impl`)
See the doc changes for a description of the new system.
This required a bunch of changes:
- UDL now creates a blanket impl by default. The [Remote] attribute can
be used to switch to a local impl.
- Proc-macros get the `#[remote]` attribute macro, which allows users to
create a local impl.
- Custom types now create a blanket impl by default. The `remote`
parameter can be used to create a local impl.
- Added the `remote_type!` macro to which handles the case where you
want to use a remote type and another crate has already created a
local impl. This creates a local impl for your crate by forwarding to
the other impl. Removed the `use_udl_*` macros, which were a kludge
for doing the same thing.
Added a motivating example where `anyhow::Error` is used as an error
type. Changed the error type bound to `Display + Debug` rather than
`Error`. For some reason `anyhow::Error` doesn't actually implement
error.
One feature that we've lost in defining callback/trait interfaces using
traits defined in a remote crate. I think this is okay because I doubt
anyone is using that feature.
Instead we can use the `trace!` macro to log details about FFI calls. By
default, it's compiled out but the `ffi-trace` feature can be used to
enable it. These tracing printouts are only really useful for debugging
failures when writing scaffolding/bindings code.
Addresses #2224 - even disabled logging can have overhead depending with some backends, and
in very high frequency calls, generates unacceptable overhead and log-spam.
```
#[uniffi::export]
impl MyTrait for MyObject { ... }
```
Previously worked as it ignored `MyTrait`. This adds new metadata to record it,
allowing foreign bindings to implement things like inheritance.
Includes Python generating an inheritance chain to reflect this relationship.
This will not generate correct code if a struct declares more than 1 trait,
and there's some undesirable re-wrapping when traits from these objects gets
passed back and forward, but seems to work surprisingly well.
Fixes#2196.
Added the `uniffi:ffi-trace` feature. If enabled, UniFFI will printout
tracing-level logs for FFI calls. I hooked up the futures code to this,
in the future we could also log more stuff. Lowering/lifting/cloning
arcs is the first example that comes to mind.
To see tracing, use the `--features=ffi-trace` when running a tests, for example:
- `cd fixtures/futures/src`
- `cargo test --features=ffi-trace`
Here's an example of the tracing printouts when running tests from the
futures fixtures:
```
rust_future_new: Handle(94402427620656)
rust_future_poll: Handle(94402427620656)
RustFuture::wake called
rust_future_poll: Handle(94402427620656)
RustFuture::poll is ready (canceled: false)
rust_future_complete: Handle(94402427620656)
rust_future_free: Handle(94402427620656)
```
This avoids crashing for consumers that set panic=abort (Firefox).
- Updated the Err type for `rust_call`. The closure can now return an
internal error. The only way to signal an internal error before was
to panic.
- Reworked the `LowerReturn` trait and the future code to work with the
new system.
- Added a type for argument lift errors, this makes the rustfuture
signatures nicer.
`error_buf` is owned by the foreign side. Because we assume it has been initialized
we use `ManuallyDrop` instead of `MaybeUninit`, which clarifies ownership
and avoids unsafe code.
Fixes#2168
When a `#[derive(uniffi::Error)]` didn't appear in any function signatures,
the FfiConverter for the item was written to assume an error, but the
bindings FfiConverter treated the item as a plain-old Enum. This caused
runtime errors when trying to unpack the rustbuffers due to the
disagreement about the buffer format.
As part of fixing this, the `Option<bool>` to try and represent the
flatness of Enums/Errors was replaced with an `EnumShape` enum to
make these states clearer and so the ComponentInterface can better
understand the layout.
Fixes#2108
Implemented our own oneshot channel using a Mutex. It's not quite as
efficient as the `oneshot` one, but I think it should be fine for our
purposes. My gut feeling is that the loss of overhead is neglibable
compared the other existing overhead that UniFFI adds.
The API of the new oneshot is basically the same, except send/recv are
not failable.
This is needed because we haven't merged
https://github.com/mozilla/uniffi-rs/pull/2083 into the branch.
Also:
- Added a changelog entry.
- Added a `#[allow(unknown_lints)]`, since
`clippy::needless_borrows_for_generic_args` is not available on the
older Rust version used in this branch.
These are alternate versions of the current scaffolding functions that
use u64 buffers to handle their input/output.
The main use case is the gecko-js bindings used in Firefox. This allows
us to replace the generated C++ code with static code, since the
scaffolding functions now always have the exact same signature.
This commit generates FFI buffer versions for scaffolding functions
defined for user functions/methods. It does not generate them for
functions with known/static signatures like the rust buffer FFI
functions, or the object clone/delete functions. If the signature is
always the same, then there isn't a problem calling the normal
scaffolding functions.
Implemented our own oneshot channel using a Mutex. It's not quite as
efficient as the `oneshot` one, but I think it should be fine for our
purposes. My gut feeling is that the loss of overhead is neglibable
compared the other existing overhead that UniFFI adds.
The API of the new oneshot is basically the same, except send/recv are
not failable.
This specifies how types are lowered when they are the `E` side of
`Result<T, E>`. The main reason for the trait is that it lets us
specialize the handling for interfaces by auto-wrapping the value in an
Arc.
This makes using interfaces as errors much more ergonomic.
Also, replace the `Error` bound on the `E` types with `Display + Debug`.
I just found out that `anyhow::Error` doesn't actually implement `Error`
for some obscure reason.
These are alternate versions of the current scaffolding functions that
use u64 buffers to handle their input/output.
The main use case is the gecko-js bindings used in Firefox. This allows
us to replace the generated C++ code with static code, since the
scaffolding functions now always have the exact same signature.
This commit generates FFI buffer versions for scaffolding functions
defined for user functions/methods. It does not generate them for
functions with known/static signatures like the rust buffer FFI
functions, or the object clone/delete functions. If the signature is
always the same, then there isn't a problem calling the normal
scaffolding functions.
The metadata code now uses this trait to get the `TYPE_ID_METADATA`
rather than Lift/Lower. This feels cleaner, since it was often not
clear which trait to use before. This removes the hacky handling of type
id metadata for callback interfaces that I added in #1950
I implemented everything, except enum variants and also jplatte's
suggestion of a function-based default. I think those two can be done
later, especially since they semi-conflict. When you're parsing it's
hard to tell an variant ident from a function ident. I also think
function-based defaults might be better for enums anyways, since they
would work with associated data.
Updated the metadata to add the `SOME` code and make the optional types
expect that, rather than reading the literal for ther inner type. I
think that makes the code a bit cleaner.
Split up the compounds code in Kotlin. Now each type can only parse
their literals rather allowing any compound-like literal for any
compound type.
* Increase BUF_SIZE to 16384 (from 4096), allowing large errors (enums) to be used. Add fixture which unit tests fails even for BUF_SIZE of 8198, but works with 16k.
These methods input a completion function that they call when the async
function is complete. They return a ForeignFuture struct, which
represents the foreign task object and is used to drop/cancel futures.
Like Rust, dropping and cancelling are coupled together into one operation.
- Added `RustCallStatus` as an `FfiType` variant, since I wanted to use
it in the `ForeignFutureResult` structs. In theory, we could define
`RustCallStatus` a `FfiType::Struct`, but I didn't want to introduce
that change in this PR.
- Fixed the result mapping code to work with async functions. Before we
were executing the mapping call, then awaiting the result, but we need
to do that in the opposite order (`foo.into().await` vs `foo.await.into()`).
Also, specify the return type generics for `rust_future_new` so that
the Rust can figure out the into() generics.
This only updates the CHANGELOG and version numbers. All the functional
changes were already in main.
Whiile merging the changelog, I also removed a duplicate "What's new"
header and moved the "All changes" link to the bottom of the entry.
I added contributed a new feature for this one to convert between
`Sender` and a raw pointer. I want to use this to handle
foreign-implemented async trait methods.
FfiType::Handle is a opaque 64-bit handle that's used to pass objects
across the FFI. This PR changes the rustfuture code to use it and also
renames the type used to represent callback interfaces from `u64` to
handle. The plan is to use it for all object types, including
interfaces and trait interfaces, but that will be done in future PRs.
Accompianing that code is the `HandleAlloc` trait, which has a general
system for allocating/using/freeing handles for objects. It's
essentially the same system(s) we're currently using, but now the code
is all in one place.
On the bindings side, switched the code to using the `u64` type rather
than having a `UniffiHandle` type alias. I don't think the type alias
is very useful since handles are only used internally. Also, I remember
running into Swift issues with the type alias and multiple crates.
Most of this code was copied from the handles PR (#1823).
I'm trying to get #1823 merged now that 0.26.0 is out, but I'll break it
up a bit to make it easier. The first step is consolidating the foreign
handle map code.
Foreign now languages define 1 handle map and use it for all object
types. I tried to simplify the handle map implementations, the had a lot
of features that we weren't using at all and seemed to be only
half-implemented to me, like the right map and counter map.
Handles are always `u64` values. This allows us to remove some code
like the `USize` handling on Kotlin and the
`FfiType::RustFutureContinuationData` variant.
Instead of registering a single method to implement a callback
interface, foreign code now registers a VTable. VTable sounds fancy,
but it's just a repr(C) struct where each field is a callback function.
This gives us some more flexibility with the method signatures.
Before, all arguments were passed using a RustBuffer, but not all FFI
types can be written to a RustBuffer. In particular, I want to be able
to pass callback function pointers.
This also makes the callback interface FFI closer to the Rust one. I
wanted to make it match exactly, but it didn't work out. Unfortunately,
we can't directly return the return value on Python because of an old
ctypes bug (https://bugs.python.org/issue5710). Instead, input an out
param for the return type. The other main possibility would be to
change `RustBuffer` to be a simple `*mut u8` (#1779), which would then
be returnable by Python. However, it seems bad to restrict ourselves
from ever returning a struct in the future. Eventually, we want to stop
using `RustBuffer` for all complex data types and that probably means
using a struct instead in some cases.
Renamed `CALL_PANIC` to `CALL_UNEXPECTED_ERROR` in the foreign bindings
templates. This matches the name in the Rust code and makes more sense
for foreign trait implementations.
Removed the reexport-scaffolding-macro fixture. I don't think this one
is giving us a lot of value anymore and I don't want to keep updating it
when the FFI changes.