uniffi-rs
uniffi-rs copied to clipboard
Enum with associated data containing a callback interface produces incorrect Swit code.
UniFFI automatically declares enums in Swift as being Equatable
and Hashable
. This results in a compiler error when the associated data of the enum contains a callback interface.
Example Rust code:
pub trait Foo: Send + Sync {
fn value(&self) -> u32;
}
pub enum Bar {
Baz { foo: Box<dyn Foo> },
}
pub fn get_foo(bar: Bar) -> u32 {
match bar {
Bar::Baz { foo } => foo.value(),
}
}
Example UDL file:
namespace test_uni_ffi {
u32 get_foo(Bar bar);
};
callback interface Foo {
u32 value();
};
[Enum]
interface Bar {
Baz(Foo foo);
};
Relevant part of the produced Swift code:
public protocol Foo: AnyObject {
func value() -> UInt32
}
public enum Bar {
case baz(foo: Foo)
}
extension Bar: Equatable, Hashable {}
// error: type 'Bar' does not conform to protocol 'Equatable'
// error: type 'Bar' does not conform to protocol 'Hashable'
public func getFoo(bar: Bar) -> UInt32 {
// ...
}
I only gave this a very shallow look just now. We do try to avoid those implementations for types that contain other object references: https://github.com/mozilla/uniffi-rs/blob/1696344a8f1643cfa1a36a3fac201340b0b62a98/uniffi_bindgen/src/bindings/swift/templates/EnumTemplate.swift
Maybe we should extend that.
+1 I have a struct
#[derive(uniffi::Object)]
pub struct Animal {
pub name: String;
}
#[derive(uniffi::Record)]
pub struct Person {
pub animal: Arc<Animal>
}
In swift, this generates a Person which conforms to equatable, but Animal doesn't
In swift, this generates a Person which conforms to equatable, but Animal doesn't
That's because Swift is able to directly compare each field for the record. However, it is possible to expose some builtin Rust traits on an interface, such as Eq
etc, which Swift should then support.
https://mozilla.github.io/uniffi-rs/latest/udl/interfaces.html#exposing-methods-from-standard-rust-traits
Here is an example of Rust code doing that and of the swift code testing it
(In fact with this capability, I suspect this issue should be closed?)
(In fact with this capability, I suspect this issue should be closed?)
hrm, probably not - the original issue is about interfaces inside records, so that's probably still true. Using Eq
might help interfaces in that case, but probably not traits/callbacks.
@mhammond My current workaround is to implement Equatable/Hashable as an extension
extension Animal: Equatable, Hashable {
... // this tend to be a bit more custom for Objects
}