Skip to content

Commit 7ef5c62

Browse files
support custom unmarshalling for map keys (#453)
Co-authored-by: [email protected] <[email protected]>
1 parent 4653a1b commit 7ef5c62

File tree

2 files changed

+42
-5
lines changed

2 files changed

+42
-5
lines changed

decode.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ import (
1515
"strconv"
1616
"time"
1717

18+
"golang.org/x/xerrors"
19+
1820
"github.com/goccy/go-yaml/ast"
1921
"github.com/goccy/go-yaml/internal/errors"
2022
"github.com/goccy/go-yaml/parser"
2123
"github.com/goccy/go-yaml/token"
22-
"golang.org/x/xerrors"
2324
)
2425

2526
// Decoder reads and decodes YAML values from an input stream.
@@ -1500,10 +1501,19 @@ func (d *Decoder) decodeMap(ctx context.Context, dst reflect.Value, src ast.Node
15001501
}
15011502
continue
15021503
}
1503-
k := reflect.ValueOf(d.nodeToValue(key))
1504-
if k.IsValid() && k.Type().ConvertibleTo(keyType) {
1505-
k = k.Convert(keyType)
1504+
1505+
k := d.createDecodableValue(keyType)
1506+
if d.canDecodeByUnmarshaler(k) {
1507+
if err := d.decodeByUnmarshaler(ctx, k, key); err != nil {
1508+
return errors.Wrapf(err, "failed to decode by unmarshaler")
1509+
}
1510+
} else {
1511+
k = reflect.ValueOf(d.nodeToValue(key))
1512+
if k.IsValid() && k.Type().ConvertibleTo(keyType) {
1513+
k = k.Convert(keyType)
1514+
}
15061515
}
1516+
15071517
if k.IsValid() {
15081518
if err := d.validateDuplicateKey(keyMap, k.Interface(), key); err != nil {
15091519
return errors.Wrapf(err, "invalid map key")

decode_test.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ import (
1414
"testing"
1515
"time"
1616

17+
"golang.org/x/xerrors"
18+
1719
"github.com/goccy/go-yaml"
1820
"github.com/goccy/go-yaml/ast"
1921
"github.com/goccy/go-yaml/internal/errors"
2022
"github.com/goccy/go-yaml/parser"
21-
"golang.org/x/xerrors"
2223
)
2324

2425
type Child struct {
@@ -2906,3 +2907,29 @@ func TestSameNameInineStruct(t *testing.T) {
29062907
t.Fatalf("failed to decode")
29072908
}
29082909
}
2910+
2911+
type unmarshableMapKey struct {
2912+
Key string
2913+
}
2914+
2915+
func (mk *unmarshableMapKey) UnmarshalYAML(b []byte) error {
2916+
mk.Key = string(b)
2917+
return nil
2918+
}
2919+
2920+
func TestMapKeyCustomUnmarshaler(t *testing.T) {
2921+
var m map[unmarshableMapKey]string
2922+
if err := yaml.Unmarshal([]byte(`key: value`), &m); err != nil {
2923+
t.Fatalf("failed to unmarshal %v", err)
2924+
}
2925+
if len(m) != 1 {
2926+
t.Fatalf("expected 1 element in map, but got %d", len(m))
2927+
}
2928+
val, ok := m[unmarshableMapKey{Key: "key"}]
2929+
if !ok {
2930+
t.Fatal("expected to have element 'key' in map")
2931+
}
2932+
if val != "value" {
2933+
t.Fatalf("expected to have value \"value\", but got %q", val)
2934+
}
2935+
}

0 commit comments

Comments
 (0)