Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go: best practice for safely converting integers to protocol buffer enum values

I have an enum in a proto file that generates to integer constants in the pb.go file. I now have some integers coming from the an external data source and want to safely map them to the possible constants.

Here is what I currently have: https://play.golang.org/p/-5VZqPbukd

package main

import (
    "errors"
    "fmt"
)

//enum in the proto file
//
// enum X {
//    A = 0;
//    B = 1;
//    C = 2;
//    D = 3;
// }

//enum type generated by protoc
type X int32

//enum constants generated by protoc
const (
    X_A X = 0
    X_B X = 1
    X_C X = 2
    X_D X = 3
)

func intToX(v int) (X, error) {
    x := X(v)
    switch x {
    case X_A, X_B, X_C, X_D:
        return x, nil
    }
    return 0, errors.New("could not convert int to X")
}

func main() {
    for i := -1; i < 10; i++ {
        if x, err := intToX(i); err != nil {
            fmt.Println("unhandled error:", err, "for input value", i)
        } else {
            fmt.Printf("%d => X(%d)\n", i, x)
        }
    }
}

Question: Is there a better, more idiomatic way to map incoming integer values to protoc-generated constants?

In particular, I would like to avoid listing all constants explicitly in the case A, B, C, D statement.

like image 516
Juve Avatar asked Jun 04 '26 06:06

Juve


1 Answers

I do not know which proto generation package you are using, but with github.com/golang/protobuf/proto you also get the reverse mapping of enums.

Example xyz.pb.go generated file:

type TimeInterval int32

const (
    TimeInterval_TI_UNKNOWN TimeInterval = 0
    TimeInterval_TI_HOUR    TimeInterval = 1
    TimeInterval_TI_DAY     TimeInterval = 2
    TimeInterval_TI_WEEK    TimeInterval = 3
    TimeInterval_TI_MONTH   TimeInterval = 4
    TimeInterval_TI_QUARTER TimeInterval = 5
    TimeInterval_TI_YEAR    TimeInterval = 6
)

var TimeInterval_name = map[int32]string{
    0: "TI_UNKNOWN",
    1: "TI_HOUR",
    2: "TI_DAY",
    3: "TI_WEEK",
    4: "TI_MONTH",
    5: "TI_QUARTER",
    6: "TI_YEAR",
}
var TimeInterval_value = map[string]int32{
    "TI_UNKNOWN": 0,
    "TI_HOUR":    1,
    "TI_DAY":     2,
    "TI_WEEK":    3,
    "TI_MONTH":   4,
    "TI_QUARTER": 5,
    "TI_YEAR":    6,
}

func (x TimeInterval) String() string {
    return proto.EnumName(TimeInterval_name, int32(x))
}
func (TimeInterval) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }

So with this you could test for existence in the following manner:

if _, found := TimeInterval_name[testinputint]; found{
    //all ok
} else {
   //not a value for this enum
}
like image 75
RickyA Avatar answered Jun 06 '26 06:06

RickyA