Skip to content

Commit

Permalink
chore: add support for map[string]interface{}
Browse files Browse the repository at this point in the history
For siderolabs/talos#6057

Signed-off-by: Dmitriy Matrenichev <[email protected]>
  • Loading branch information
DmitriyMV committed Aug 10, 2022
1 parent bf5e39b commit 49a85fa
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 13 deletions.
17 changes: 17 additions & 0 deletions marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/timestamppb"
)

Expand Down Expand Up @@ -253,6 +254,22 @@ func (m *marshaller) encodeValue(num protowire.Number, val reflect.Value) {

func (m *marshaller) tryEncodePredefined(num protowire.Number, val reflect.Value) bool {
switch val.Type() {
case typeMapInterface:
v := val.Interface().(map[string]interface{}) //nolint:errcheck,forcetypeassert

val, err := structpb.NewStruct(v)
if err != nil {
panic(fmt.Errorf("failed to create structpb.Struct: %w", err))
}

encoded, err := proto.Marshal(val)
if err != nil {
panic(err)
}

putTag(m, num, protowire.BytesType)
putBytes(m, encoded)

case typeDuration:
d := val.Interface().(time.Duration) //nolint:errcheck,forcetypeassert
duration := durationpb.New(d)
Expand Down
14 changes: 14 additions & 0 deletions marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,3 +592,17 @@ func TestIncorrectCustomEncoders(t *testing.T) {
)
})
}

func TestMarshalMapInterface(t *testing.T) {
// json decodes numeric values as float64s
// json decoder do not support slices
testEncodeDecode(OneFieldStruct[map[string]interface{}]{map[string]interface{}{
"a": 1.0,
"b": "2",
"c": true,
"e": map[string]interface{}{
"a": 1.0,
"g": 10.10,
},
}})(t)
}
25 changes: 13 additions & 12 deletions predefined_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,19 @@ type (
)

var (
typeFixedU32 = typeOf[FixedU32]()
typeFixedU64 = typeOf[FixedU64]()
typeFixedS32 = typeOf[FixedS32]()
typeFixedS64 = typeOf[FixedS64]()
typeTime = typeOf[time.Time]()
typeDuration = typeOf[time.Duration]()
typeFixedU32s = reflect.SliceOf(typeFixedU32)
typeFixedU64s = reflect.SliceOf(typeFixedU64)
typeFixedS32s = reflect.SliceOf(typeFixedS32)
typeFixedS64s = reflect.SliceOf(typeFixedS64)
typeDurations = reflect.SliceOf(typeDuration)
typeByte = typeOf[byte]()
typeFixedU32 = typeOf[FixedU32]()
typeFixedU64 = typeOf[FixedU64]()
typeFixedS32 = typeOf[FixedS32]()
typeFixedS64 = typeOf[FixedS64]()
typeTime = typeOf[time.Time]()
typeDuration = typeOf[time.Duration]()
typeMapInterface = typeOf[map[string]interface{}]()
typeFixedU32s = reflect.SliceOf(typeFixedU32)
typeFixedU64s = reflect.SliceOf(typeFixedU64)
typeFixedS32s = reflect.SliceOf(typeFixedS32)
typeFixedS64s = reflect.SliceOf(typeFixedS64)
typeDurations = reflect.SliceOf(typeDuration)
typeByte = typeOf[byte]()
)

func typeOf[T any]() reflect.Type {
Expand Down
6 changes: 6 additions & 0 deletions slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ func TestSmallIntegers(t *testing.T) {

type customByte byte

type customSlice []byte

type customType struct {
Int16 int16 `protobuf:"1"`
Uint16 uint16 `protobuf:"3"`
Expand Down Expand Up @@ -243,6 +245,10 @@ func TestSmallIntegers(t *testing.T) {
"slice of uint16 type should be encoded in 'fixed32' form",
testEncodeDecodeWrapped([]uint16{1, 0xFFFF, 3}, encodedUint16s),
},
{
"customSlice should be encoded in 'bytes' form",
testEncodeDecodeWrapped(customSlice{1, 0xFF, 3}, encodedBytes),
},
{
"customType should be encoded in 'fixed32' form",
testEncodeDecodeWrapped(customType{
Expand Down
14 changes: 13 additions & 1 deletion unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/timestamppb"
)

Expand Down Expand Up @@ -348,7 +349,7 @@ func instantiate(dst reflect.Value) error {
return nil
}

//nolint:cyclop
//nolint:cyclop,gocyclo
func unmarshalBytes(dst reflect.Value, value complexValue) (err error) {
defer func() {
if err != nil {
Expand Down Expand Up @@ -389,6 +390,17 @@ func unmarshalBytes(dst reflect.Value, value complexValue) (err error) {

dst.Set(reflect.ValueOf(result.AsDuration()))

return nil
case typeMapInterface:
var result structpb.Struct

err = proto.Unmarshal(bytes, &result)
if err != nil {
return err
}

dst.Set(reflect.ValueOf(result.AsMap()))

return nil
}

Expand Down

0 comments on commit 49a85fa

Please sign in to comment.