-
Notifications
You must be signed in to change notification settings - Fork 301
Open
Description
Hello, I'm attempting to register an extension for encoding and decoding a struct that has a polymorphic interface{}
field. I am not sure if this is a bug, or if I am misusing the library but would appreciate feedback either way.
If I set the value of check
in extHandle.getExt(...)
to be true through a debugger or local clone then this test passes as I expected. If I do not overwrite this value it is always passed as false via *encoderMsgpackBytes.fn(...)
and *decoderMsgpackBytes.fn(...)
and the resulting type for Polymorphic.Data
is always a map[string]any
.
package msgp_test
import (
"fmt"
"reflect"
"testing"
mp "github.com/ugorji/go/codec"
)
type Polymorphic struct {
Type string
Data any
}
type One struct {
Value string
}
type Two struct {
Value int
}
type PolymorphicExt struct{}
func (m PolymorphicExt) WriteExt(v interface{}) []byte {
dto, ok := v.(*Polymorphic)
if !ok {
return nil
}
switch dto.Type {
case "one":
return []byte(dto.Data.(*One).Value)
case "two":
return []byte(fmt.Sprintf("two:%d", dto.Data.(*Two).Value))
default:
return nil
}
}
func (m PolymorphicExt) ReadExt(dst interface{}, src []byte) {
dto, ok := dst.(*Polymorphic)
if !ok {
return
}
// hack this to simplify reproduction
dto.Type = "two"
switch dto.Type {
case "one":
dto.Data = &One{Value: string(src)}
case "two":
var value int
if _, err := fmt.Sscanf(string(src), "two:%d", &value); err != nil {
panic(err)
}
dto.Data = &Two{Value: value}
default:
panic(fmt.Sprintf("unknown type: %s", dto.Type))
}
}
func TestEncodingDecoding(t *testing.T) {
handle := &mp.MsgpackHandle{
WriteExt: true,
}
if err := handle.SetBytesExt(reflect.TypeOf(Polymorphic{}), 0xaa, PolymorphicExt{}); err != nil {
t.Fatalf("SetBytesExt() failed: %v", err)
}
input := &Polymorphic{
Type: "two",
Data: &Two{Value: 420},
}
byteSlice := make([]byte, 0, reflect.TypeOf(input).Size())
if err := mp.NewEncoderBytes(&byteSlice, handle).Encode(input); err != nil {
t.Fatalf("failed to encode polymorphic data: %v", err)
}
var decoded Polymorphic
if err := mp.NewDecoderBytes(byteSlice, handle).Decode(&decoded); err != nil {
t.Fatalf("failed to decode polymorphic data: %v", err)
}
t.Logf("%T", decoded.Data)
data, ok := decoded.Data.(*Two)
if !ok {
t.Fatalf("failed to type case to *One, got %T", decoded.Data)
}
if actual := input.Data.(*Two).Value; data.Value != actual {
t.Fatalf("expected %v, got %v", actual, data.Value)
}
}
Here is my local diff that gets this test to pass
➜ go git:(master) ✗ git diff
diff --git a/codec/msgpack.mono.generated.go b/codec/msgpack.mono.generated.go
index ff2fe4a..7bab9c8 100644
--- a/codec/msgpack.mono.generated.go
+++ b/codec/msgpack.mono.generated.go
@@ -1,4 +1,4 @@
-//go:build !notmono && !codec.notmono
+//go:build !notmono && !codec.notmono
// Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
@@ -1138,7 +1138,7 @@ func (e *encoderMsgpackBytes) rawBytes(vv Raw) {
}
func (e *encoderMsgpackBytes) fn(t reflect.Type) *encFnMsgpackBytes {
- return e.dh.encFnViaBH(t, e.rtidFn, e.h, e.fp, false)
+ return e.dh.encFnViaBH(t, e.rtidFn, e.h, e.fp, true)
}
func (e *encoderMsgpackBytes) fnNoExt(t reflect.Type) *encFnMsgpackBytes {
@@ -2847,7 +2847,7 @@ func (d *decoderMsgpackBytes) interfaceExtConvertAndDecode(v interface{}, ext In
}
func (d *decoderMsgpackBytes) fn(t reflect.Type) *decFnMsgpackBytes {
- return d.dh.decFnViaBH(t, d.rtidFn, d.h, d.fp, false)
+ return d.dh.decFnViaBH(t, d.rtidFn, d.h, d.fp, true)
}
func (d *decoderMsgpackBytes) fnNoExt(t reflect.Type) *decFnMsgpackBytes {
➜ go git:(master) ✗
Test results before changes
--- FAIL: TestEncodingDecoding (0.00s)
msgpack_test.go:88: map[interface {}]interface {}
msgpack_test.go:92: failed to type case to *One, got map[interface {}]interface {}
FAIL
FAIL msgp-sam-testing 0.243s
FAIL
Thanks for your time.
Metadata
Metadata
Assignees
Labels
No labels