Skip to content

Commit 82f46cf

Browse files
authored
Merge pull request #46 from Basekick-Labs/fix/text-unmarshaler-str-format
fix(decode): choose TextUnmarshaler over BinaryUnmarshaler for str format (#10)
2 parents a46d152 + be64e92 commit 82f46cf

2 files changed

Lines changed: 56 additions & 0 deletions

File tree

decode_value.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"errors"
66
"fmt"
77
"reflect"
8+
9+
"github.com/vmihailenco/msgpack/v5/msgpcode"
810
)
911

1012
var (
@@ -71,6 +73,9 @@ func _getDecoder(typ reflect.Type) decoderFunc {
7173
return nilAwareDecoder(typ, unmarshalValue)
7274
}
7375
if typ.Implements(binaryUnmarshalerType) {
76+
if typ.Implements(textUnmarshalerType) {
77+
return nilAwareDecoder(typ, unmarshalBinaryOrTextValue)
78+
}
7479
return nilAwareDecoder(typ, unmarshalBinaryValue)
7580
}
7681
if typ.Implements(textUnmarshalerType) {
@@ -87,6 +92,9 @@ func _getDecoder(typ reflect.Type) decoderFunc {
8792
return addrDecoder(nilAwareDecoder(typ, unmarshalValue))
8893
}
8994
if ptr.Implements(binaryUnmarshalerType) {
95+
if ptr.Implements(textUnmarshalerType) {
96+
return addrDecoder(nilAwareDecoder(typ, unmarshalBinaryOrTextValue))
97+
}
9098
return addrDecoder(nilAwareDecoder(typ, unmarshalBinaryValue))
9199
}
92100
if ptr.Implements(textUnmarshalerType) {
@@ -238,6 +246,20 @@ func unmarshalValue(d *Decoder, v reflect.Value) error {
238246
return unmarshaler.UnmarshalMsgpack(b)
239247
}
240248

249+
// unmarshalBinaryOrTextValue peeks at the wire format to choose between
250+
// BinaryUnmarshaler (bin) and TextUnmarshaler (str). Used when a type
251+
// implements both interfaces.
252+
func unmarshalBinaryOrTextValue(d *Decoder, v reflect.Value) error {
253+
c, err := d.PeekCode()
254+
if err != nil {
255+
return err
256+
}
257+
if msgpcode.IsString(c) {
258+
return unmarshalTextValue(d, v)
259+
}
260+
return unmarshalBinaryValue(d, v)
261+
}
262+
241263
func unmarshalBinaryValue(d *Decoder, v reflect.Value) error {
242264
data, err := d.DecodeBytes()
243265
if err != nil {

types_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,40 @@ func TestPoolReleasesOversizedBuffers(t *testing.T) {
12941294
require.Equal(t, "small", s)
12951295
}
12961296

1297+
// Issue #10: types implementing both TextUnmarshaler and BinaryUnmarshaler
1298+
// should use TextUnmarshaler when wire format is str.
1299+
type dualUnmarshaler struct {
1300+
text string
1301+
binary []byte
1302+
}
1303+
1304+
func (d *dualUnmarshaler) MarshalText() ([]byte, error) { return []byte(d.text), nil }
1305+
func (d *dualUnmarshaler) UnmarshalText(b []byte) error { d.text = string(b); return nil }
1306+
func (d *dualUnmarshaler) MarshalBinary() ([]byte, error) { return d.binary, nil }
1307+
func (d *dualUnmarshaler) UnmarshalBinary(b []byte) error { d.binary = b; return nil }
1308+
1309+
func TestTextUnmarshalerWithStrFormat(t *testing.T) {
1310+
// Encode a plain string (str format) and decode into a type that
1311+
// implements both BinaryUnmarshaler and TextUnmarshaler.
1312+
b, err := msgpack.Marshal("hello")
1313+
require.NoError(t, err)
1314+
1315+
var du dualUnmarshaler
1316+
require.NoError(t, msgpack.Unmarshal(b, &du))
1317+
// Should have used TextUnmarshaler because the wire format is str.
1318+
require.Equal(t, "hello", du.text)
1319+
require.Nil(t, du.binary)
1320+
1321+
// Encode as binary (bin format) and decode — should use BinaryUnmarshaler.
1322+
b, err = msgpack.Marshal([]byte{0xDE, 0xAD})
1323+
require.NoError(t, err)
1324+
1325+
var du2 dualUnmarshaler
1326+
require.NoError(t, msgpack.Unmarshal(b, &du2))
1327+
require.Equal(t, []byte{0xDE, 0xAD}, du2.binary)
1328+
require.Equal(t, "", du2.text)
1329+
}
1330+
12971331
func mustParseTime(format, s string) time.Time {
12981332
tm, err := time.Parse(format, s)
12991333
if err != nil {

0 commit comments

Comments
 (0)