-
-
Save StevenACoffman/94642bd64afdc02aaefb019c575ea8d5 to your computer and use it in GitHub Desktop.
Create a go map from any proto message without proto->json->map
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"google.golang.org/protobuf/proto" | |
"google.golang.org/protobuf/reflect/protodesc" | |
"google.golang.org/protobuf/reflect/protoreflect" | |
"google.golang.org/protobuf/types/descriptorpb" | |
"google.golang.org/protobuf/types/dynamicpb" | |
) | |
func innerDynamicToMap(msg protoreflect.Message) (interface{}, error) { | |
mapData := make(map[string]interface{}, msg.Descriptor().Fields().Len()) | |
for i := 0; i < msg.Descriptor().Fields().Len(); i++ { | |
field := msg.Descriptor().Fields().Get(i) | |
switch field.Cardinality() { | |
case protoreflect.Repeated: | |
list := msg.Get(field).List() | |
values := make([]interface{}, 0, list.Len()) | |
for j := 0; j < list.Len(); j++ { | |
v, err := fieldToValue(field.Kind(), list.Get(j)) | |
if err != nil { | |
return nil, err | |
} | |
values = append(values, v) | |
} | |
mapData[string(field.Name())] = values | |
default: | |
value, err := fieldToValue(field.Kind(), msg.Get(field)) | |
if err != nil { | |
return nil, err | |
} | |
mapData[string(field.Name())] = value | |
} | |
} | |
return mapData, nil | |
} | |
func fieldToValue(kind protoreflect.Kind, value protoreflect.Value) (interface{}, error) { | |
switch kind { | |
case protoreflect.BoolKind: | |
return value.Bool(), nil | |
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, | |
protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: | |
return value.Int(), nil | |
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, | |
protoreflect.Uint64Kind, protoreflect.Fixed64Kind: | |
return value.Uint(), nil | |
case protoreflect.FloatKind, protoreflect.DoubleKind: | |
return value.Float(), nil | |
case protoreflect.StringKind: | |
return value.String(), nil | |
case protoreflect.BytesKind: | |
return value.Bytes(), nil | |
case protoreflect.EnumKind: | |
return value.Enum(), nil | |
case protoreflect.MessageKind: | |
return innerDynamicToMap(value.Message()) | |
default: | |
return nil, fmt.Errorf("unsupported field type: %s", kind) | |
} | |
} | |
// for use with dynamicProto messages | |
// takes in a wire-buffer (encoded proto) and a dynamic message (created in runtime from a decriptor set) | |
// and returns a native go map | |
func DynamicToMap(in []byte, msg *dynamicpb.Message) (map[string]interface{}, error) { | |
err := proto.Unmarshal(in, msg) | |
if err != nil { | |
return nil, err | |
} | |
content, err := innerDynamicToMap(msg) | |
if err != nil { | |
return nil, err | |
} | |
if content, ok := content.(map[string]interface{}); ok { | |
return content, nil | |
} | |
return nil, fmt.Errorf("failed to convert dynamic message to map") | |
} | |
func main(){ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment