prost icon indicating copy to clipboard operation
prost copied to clipboard

Question: Can we support enum-typed fields?

Open calder opened this issue 4 years ago • 5 comments

From the README:

Enumerations

All .proto enumeration types convert to the Rust i32 type. Additionally, each enumeration type gets a corresponding Rust enum type, with helper methods to convert i32 values to the enum type. The enum type isn't used directly as a field, because the Protobuf spec mandates that enumerations values are 'open', and decoding unrecognized enumeration values must be possible.

Given an enum:

enum Foo {
    A = 1;
    B = 2;
}

Would it be possible to support "open" enums with a special Unknown(i32) variant like this?

enum Foo {
    A,
    B,
    Unknown(i32),
}

impl From<i32> for Foo {
    fn from(i: i32) -> Self {
        match i {
            1 => Foo::A,
            2 => Foo::B,
            _ => Foo::Unknown(i),
        }
    }
}

impl From<&Foo> for i32 {
    fn from(f: &Foo) -> Self {
        match f {
            Foo::A => 1,
            Foo::B => 2,
            Foo::Unknown(v) => *v,
        }
    }
}

That would enable enum-typed fields while allowing match expressions to naturally handle unknown values.

calder avatar Apr 18 '20 15:04 calder

Possible duplicate of #276

nw0 avatar Apr 23 '20 12:04 nw0

That would enable enum-typed fields while allowing match expressions to naturally handle unknown values.

There's an existing way to do. this: use Foo::from_i32, which returns None if the i32 is not a known variant.

danburkert avatar May 11 '20 17:05 danburkert

prost predates the TryFrom API, which is why it's a method. We should probably fix that.

danburkert avatar May 11 '20 17:05 danburkert

Here's my solution: use num_derive derive all enums : #[derive(FromPrimitive, ToPrimitive)]. But you must handwrite all enums in bulid script which is inconvenient.

songzhi avatar May 14 '20 04:05 songzhi

This would be very convenient when trying to mix Prost with serde. GRPC enums are represented as strings. For example, a failed request might look like:

{
  "error": {
    "code": 400,
    "message": "API key not valid. Please pass a valid API key.",
    "status": "INVALID_ARGUMENT",
  }
}

Where status is the well known type defined here: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto (see here for more details on error mapping: https://cloud.google.com/apis/design/errors#http_mapping)

As is, a custom serde deserializer function needs to be implemented for each enum. If prost used a native enum type, all that would be required is a #[serde(rename_all = "SCREAMING_SNAKE_CASE"] annotation

bsurmanski avatar Jan 27 '22 21:01 bsurmanski