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.
* Using anyhow in templates works fine, so start doing that for literals,
replacing a number of panics with errors.
* Filters can't return anyhow, so add better helpers for converting &str
and anyhow::Error to rinja::Error.
* Other shared filters weren't used consistently and add no value so are removed.
I added these while trying to figure out the swift tests were failing on
my machine. It seems like it might actually be a swift issue (see
#2305), but I still think these are useful.
Converted some more vars to lets. Swift still complains about async
calls. I believe the next step would be to make all UniFFI objects
conform to `Sendable`.
Split the `FfiType::Reference` variant into `Reference` and
`MutReference`. This allows us to define some more variables using
`let` in swift.
See #2279.
Implemented a new custom type system described in the new docs. This
system is easier to use and also allows us to do some extra tricks
behind the scene. For example, I hope to add a flag that will toggle
between implementing `FfiConverter` for the local tag vs a blanket impl.
It's not possible to do that with the current system and adding support
would be awkward.
I wanted to keep backwards compatibility for a bit, but couldn't figure
out a good way to do it. The main issue is that for the old system, if
a custom type is declared in the UDL then we generate the `FfiConverter`
implementation, while the new system expects the user to call
`custom_type!` to create the impl. I tried to get things working by
creating a blanket impl of `FfiConverter` for types that implemented
`UniffiCustomTypeConverter`, but ran into issues -- the first blocker I
found was that there's no way to generate `TYPE_ID_META` since we don't
know the name of the custom type.
Removed the nested-module-import fixture. The custom type code will no
longer test it once we remove the old code, since it's not using
`UniffiCustomTypeConverter`. I couldn't think of a way to make it work
again.
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.