uniffi-rs icon indicating copy to clipboard operation
uniffi-rs copied to clipboard

Suggestion: generate permissive, C-compatible enums

Open BatmanAoD opened this issue 1 year ago • 11 comments

It's often useful to interoperate with C libraries that may return enum values; in this case you do not necessarily have a guarantee that the returned value is a valid variant, and it may be useful to preserve the original value, e.g. for round-tripping data.

It's simple enough to represent this in Rust:

#[repr(u32)]
enum Foo {
    KnownValue1 = 1,
    KnownValue2 = 2,
    Unknown(u32),
}

...and then explicitly implement From<u32> for Foo and From<Foo> for u32. Here's a library that provides a macro for defining enums in this way: https://github.com/cimbul/tartan-c-enum

This seems like something that would be useful for UniFFI to support as well.

BatmanAoD avatar Mar 08 '24 17:03 BatmanAoD

@BatmanAoD How feasible is it to implement this feature with uniffi-rs?

I've been using serde-repr for C-like enums and would like to see how I can generate their bindings for other languages, currently Swift.

setoelkahfi avatar Aug 26 '24 20:08 setoelkahfi

@setoelkahfi Sorry, I don't know; I'm not a UniFFI contributor, just a user.

BatmanAoD avatar Aug 26 '24 22:08 BatmanAoD

I'm not really sure what's requested here. How do you see this being relevant for UniFFI? What would it look like on the Kotlin/Swift/Python side to use this?

badboy avatar Aug 28 '24 09:08 badboy

@BatmanAoD, no worries.

@badboy TLDR: Never mind. I'll change my implementation, and this request is no longer relevant. I have a separate ErrorCode enum representing my integer-based error_code in an ErrorResponse struct, like this:

#[derive(Serialize, Deserialize, Debug)]
#[tsync]
pub struct ErrorResponse {
  pub error_code: ErrorCode,
  pub message: String,
}

#[repr(i32)]
#[derive(Serialize_repr, Deserialize_repr, Debug, EnumIter)]
#[tsync]
pub enum ErrorCode {
    Unknown = 0,
    // User-defined error codes begin from 1000
    UserNotFound = 1000,
    // Rest of the codes

Then I realized I'd not be able to use the throwing errors, as explained here.

setoelkahfi avatar Aug 28 '24 14:08 setoelkahfi

For Python, it would presumably generate an enum with FlagBoundary set to either EJECT (forcing the user to do type checks to handle unknown values) or KEEP with the final variant being Unknown. https://docs.python.org/3/library/enum.html#enum.FlagBoundary.EJECT

I don't know enough about Swift or Kotlin enums to say how they should handle this.

For Go, normal int newtypes already work this way.

BatmanAoD avatar Aug 28 '24 16:08 BatmanAoD

Okay, I take back my word. I'd still want this feature. For a better explanation, see this Serde doc.

I changed my error structure to use a parent enum instead of struct, but I'll still need the int representation of the error code. In Swift, we use raw representable protocol to express this.

An enum with an integer raw value can be expressed like this:

enum ErrorCode: Int {
    case parseError = 1, 
    case networkError = 2,
    // etc
}

Related https://github.com/mozilla/uniffi-rs/issues/2225

setoelkahfi avatar Aug 29 '24 21:08 setoelkahfi

Does https://mozilla.github.io/uniffi-rs/latest/proc_macro/index.html#variant-discriminants help here? The discriminants are exposed to bindings in that scenario.

mhammond avatar Aug 29 '24 21:08 mhammond

Yes, that's what I'm looking for, minus how to do it in a UDL file. At least I couldn't find it here.

setoelkahfi avatar Aug 30 '24 10:08 setoelkahfi

#1792 is for making it available to UDL, so I guess I'll close this one (but feel free to reopen if that's not appropriate!)

mhammond avatar Aug 30 '24 13:08 mhammond

@mhammond I don't understand how that helps, actually. My intent in this ticket is to provide a way to handle enum values from C (or other languages) that may actually be invalid variants. In Rust, even with repr, this is immediate undefined behavior.

BatmanAoD avatar Aug 30 '24 18:08 BatmanAoD

Fair enough - I got confused about who the OP was!

mhammond avatar Aug 30 '24 19:08 mhammond