Protobuffer API for dynamic Enum Access

1k views Asked by At

I want to know how to set an Enum value dynamically.

I have the following .proto file:

syntax = "proto3";
package garden;

option go_package = "proto/garden";

message Garden {
  enum Flower {
    Rose = 0;
    Acacia = 1;
    Firethorn = 2;
    Nemophila = 3;
  }
  Flower flower = 1;
}

One way to set the enum is the following:

garden := pb.Garden{}
garden.Flower = pb.Garden_Rose

I want to generate my garden dynamically and only have the value "Rose". There is the value mapping but the following does not work:

garden := pb.Garden{}
garden.Flower = pb.Garden_Flower_value["Rose"] // gives error: cannot use garden.Garden_Flower_value[flower] (type int32) as type garden.Garden_Flower in assignment

garden.Flower = 0 // works somehow??

I assume that I can use the protoreflect package to set the value. Unfortunately, it is not clear to me yet how it works.

garden.Flower = protoreflect.EnumNumber(pb.Garden_Rose)

Furthermore, I want to set ".Flower" dynamically. I figured out how to set fields in a struct dynamically but lack the knowledge how to cast a protoreflect.Value to a reflect.Value type.

2

There are 2 answers

2
Matteo On BEST ANSWER

Have you already tried this approach?

flower := "Rose"
garden := pb.Garden{}
garden.Flower = pb.Garden_Flower(pb.Garden_Flower_value[flower])
fmt.Println(garden.Flower.String()) // Rose
0
Konrad On

If someone wants to know how to do all of this dynamically. I finally figured it out:

func main() {
    var garden = pb.Garden{}
    var gardenProto = garden.ProtoReflect()
    var fields = gardenProto.Descriptor().Fields()
    var flower = fields.ByName(protoreflect.Name("flower"))
    var rose = protoreflect.Name("Rose")
    var enumValue = protoreflect.ValueOfEnum(protoreflect.EnumNumber(flower.Enum().Values().ByName(rose).Number()))
    gardenProto.Set(flower, enumValue)
    fmt.Print(garden.GetFlower())
}

When changing the string "Rose" to any of the other valid Flowers the enum is automatically updated. Furthermore, make sure that the field name is the one as specified in the .proto file. In this example it was flower.