protoc-gen-go: generate MarshalText/UnmarshalText for enums
Is your feature request related to a problem? Please describe.
It's trivial to go from an enum's integer value to its string representation (name). You can just do enum.String(), which under the hood uses proto.EnumName.
However, it's not possible to go from the name to the integer value with a simple method call.
Describe the solution you'd like
An added method for all enums, like UnmarshalText(text []byte) error. A simpler alternative might be something like what flag.Value has, Set(string) error.
Describe alternatives you've considered
If one has access to the containing struct type, the struct field tag will contain protobuf:"enum=foo.Bar"`, which can be fed to proto.EnumValueMap to obtain the relevant map[string]int32. However, this has a few major disadvantages:
- The field tag is attached to the containing struct type, so it's unreachable if all you have is an enum value or type
- The use of
proto.EnumValueMapforces a module to require the protobuf module, whenencoding.TextUnmarshalerwould suffice - Even if the two issues above were fixed, it's still unnecessarily complex to go from
stringtoint32, given how trivial it is to go the opposite way.
Additional context
I realise the answer for 99% of users is to simply use your JSON decoder. But I'm not decoding JSON here :)
Also, I imagine that this could use https://godoc.org/github.com/golang/protobuf/proto#UnmarshalJSONEnum under the hood, meaning that each method would be just two lines.
Sorry, ignore my last comment. This wouldn't use UnmarshalJSONEnum, because that's specific to JSON. This function would accept ENUMTYPE_FOO, but not "ENUMTYPE_FOO".
Currently, binary bloat is increasingly a concern for generated types, and any method added contributes to that problem. It's unlikely that we generate such a method by default, but an option is possibly conceivable.
Thanks for the reply; I see your point about binary size. An option would be fine, if this adds too much code.
Any updates? I can take a stab at implementing it.
Yes, with all the typical Open Source caveats anyone may go ahead and take a stab at this.
It is now possible to do this via protobuf reflection:
var e somepb.Enum
val := e.Descriptor().Values().ByName("VALUE_NAME")
e = (somepb.Enum)(val.Number())
While verbose, manipulating enum values by name is a fairly rare case.
I don't believe we would want to add additional methods to enum types at this time.
I agree that reflection is likely enough. I'd be fine with having this issue closed.