mozilla / uniffi-rs

a multi-language bindings generator for rust
https://mozilla.github.io/uniffi-rs/
Mozilla Public License 2.0
2.66k stars 218 forks source link

Ability to expose enum variant disciminants #1792

Open skhamis opened 10 months ago

skhamis commented 10 months ago

Allow the Enum's underlying discriminants to be defined so we can leverage the foreign languages built-in functions.

### Tasks
- [ ] Add support to the metadata (#1885)
- [ ] Expose this capability to UDL
- [ ] Expose the value to Python (#1885)
- [x] Expose the value to Swift
- [ ] Expose the value to Kotlin
- [ ] Expose the value to Ruby

The issue

Defining an enum in rust as so:

Rust

#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum VisitType {
    Link = 1,
    Typed = 2,
}

UDL

enum VisitType {
 "Link",
 "Typed",
}

Generates

swift

public enum VisitType {
    case link
    case typed
}

kotlin

enum class VisitType {
    LINK, TYPED
}

The problem is at least in swift we lose the ability to init the enum as a raw value or turn the enum into a raw value without recreating those values via extension VisitType...

Proposed solution

a decorated in the udl (or proc macro) to define the underlying type for the Enum. Using the above example: UDL

[Int]
enum VisitType {
 "Link",
 "Typed",
}

would generate

swift

public enum VisitType: Int {
    case link
    case typed
}

kotlin

enum class VisitType(var type: Int) {
    LINK, TYPED
}

Thus the foreign languages can take advantage of using in-built features like in Swift: VisitType(rawValue: v) as well as let value = visitType.rawValue.

linabutler commented 10 months ago

Thanks for filing this! Over in https://github.com/mozilla/application-services/pull/5867#pullrequestreview-1676696796, @ncloudioj was just commenting how nice it would have been to pass a bitset instead of a Vec of enum variants.

I think that's a little more involved than your suggestion—a bitset's variants would need to have specific raw values, not just implicitly assigned ones—but it would be wonderful to be able to support both, as well as other underlying types like strings!

skhamis commented 10 months ago

Thanks for filing this! Over in mozilla/application-services#5867 (review), @ncloudioj was just commenting how nice it would have been to pass a bitset instead of a Vec of enum variants.

I think that's a little more involved than your suggestion—a bitset's variants would need to have specific raw values, not just implicitly assigned ones—but it would be wonderful to be able to support both, as well as other underlying types like strings!

yes! I'm definitely okay with either starting out implicitly assigning or just go the full manual assigning. Though as you mentioned that might involved a little thinking of designing how the proc-macro/udl would define that

mhammond commented 10 months ago

I think that's a little more involved than your suggestion—a bitset's variants would need to have specific raw values, not just implicitly assigned ones

How is that different from Sammy's example, at least on the Rust side? His enum has both the repr and the value. ISTM that supporting implicitly assigned values would be much trickier, as uniffi_bindgen wouldn't know what the values are and "guessing" is probably a path to pain.

But I think Sammy's example above could be done for both UDL and procmacros with a little effort. You'd probably need to work out how to cram it into a VariantMetadata. Because only "unit variants" can assign discriminant values, I guess you'd probably end up with another enum there and I guess you'd probably want to insist on the discriminant type being explicit (as the default of usize might be problematic).

It's probably worth sketching out the foreign sides too - eg, it's not quite clear above how the swift and kotlin examples would deal with explicit values as they aren't specified (which is probably what Lina was referring to?). I'm sure there is a story there, and similarly for Python, but it's probably worth working out what that story is before digging too deep.

I'd be happy to help where I can!

mhammond commented 9 months ago

Hey Sammy, I think if #1855 lands this will become far more tractable for UDL and the other languages!