From 60fd20898629aad5f3f05d1c260e5ff8ce5d0d97 Mon Sep 17 00:00:00 2001 From: Evan Bradley <11745660+evan-bradley@users.noreply.github.com> Date: Fri, 10 May 2024 15:11:38 -0400 Subject: [PATCH 1/3] [confmap] Encode string-like map keys --- .chloggen/string-encoding.yaml | 25 +++++++++++++++++++ confmap/internal/mapstructure/encoder.go | 15 ++++++++--- confmap/internal/mapstructure/encoder_test.go | 18 +++++++++++++ 3 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 .chloggen/string-encoding.yaml diff --git a/.chloggen/string-encoding.yaml b/.chloggen/string-encoding.yaml new file mode 100644 index 00000000000..594a4d7e296 --- /dev/null +++ b/.chloggen/string-encoding.yaml @@ -0,0 +1,25 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: bug_fix + +# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) +component: confmap + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Support string-like types as map keys when marshaling + +# One or more tracking issues or pull requests related to the change +issues: [] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [api] diff --git a/confmap/internal/mapstructure/encoder.go b/confmap/internal/mapstructure/encoder.go index 408560e2262..75f25f5fd9e 100644 --- a/confmap/internal/mapstructure/encoder.go +++ b/confmap/internal/mapstructure/encoder.go @@ -168,11 +168,18 @@ func (e *Encoder) encodeMap(value reflect.Value) (any, error) { if err != nil { return nil, fmt.Errorf("error encoding key: %w", err) } - key, ok := encoded.(string) - if !ok { - return nil, fmt.Errorf("%w key %q, kind: %v", errNonStringEncodedKey, iterator.Key().Interface(), iterator.Key().Kind()) + + v := reflect.ValueOf(encoded) + var key string + + switch v.Kind() { + case reflect.String: + key = v.String() + default: + return nil, fmt.Errorf("%w, key: %q, kind: %v, type: %v", errNonStringEncodedKey, iterator.Key().Interface(), iterator.Key().Kind(), reflect.TypeOf(encoded)) } - if _, ok = result[key]; ok { + + if _, ok := result[key]; ok { return nil, fmt.Errorf("duplicate key %q while encoding", key) } if result[key], err = e.encode(iterator.Value()); err != nil { diff --git a/confmap/internal/mapstructure/encoder_test.go b/confmap/internal/mapstructure/encoder_test.go index fac12e8a6df..54800e7a740 100644 --- a/confmap/internal/mapstructure/encoder_test.go +++ b/confmap/internal/mapstructure/encoder_test.go @@ -47,6 +47,8 @@ func (tID TestID) MarshalText() (text []byte, err error) { return []byte(out), nil } +type TestStringLike string + func TestEncode(t *testing.T) { enc := New(&EncoderConfig{ EncodeHook: TextMarshalerHookFunc(), @@ -63,6 +65,22 @@ func TestEncode(t *testing.T) { input: TestID("type"), want: "type_", }, + "MapWithTextMarshalerKey": { + input: map[TestID]TestSimpleStruct{ + TestID("type"): {Value: "value"}, + }, + want: map[string]any{ + "type_": map[string]any{"value": "value"}, + }, + }, + "MapWithoutTextMarshalerKey": { + input: map[TestStringLike]TestSimpleStruct{ + TestStringLike("key"): {Value: "value"}, + }, + want: map[string]any{ + "key": map[string]any{"value": "value"}, + }, + }, "WithSlice": { input: []TestID{ TestID("nop"), From 672721910c1ca8552ccdf8b23c0be38f57035b6f Mon Sep 17 00:00:00 2001 From: Evan Bradley <11745660+evan-bradley@users.noreply.github.com> Date: Fri, 10 May 2024 15:43:36 -0400 Subject: [PATCH 2/3] Add PR number --- .chloggen/string-encoding.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chloggen/string-encoding.yaml b/.chloggen/string-encoding.yaml index 594a4d7e296..1513ae96c93 100644 --- a/.chloggen/string-encoding.yaml +++ b/.chloggen/string-encoding.yaml @@ -10,7 +10,7 @@ component: confmap note: Support string-like types as map keys when marshaling # One or more tracking issues or pull requests related to the change -issues: [] +issues: [10137] # (Optional) One or more lines of additional information to render under the primary note. # These lines will be padded with 2 spaces and then inserted directly into the document. From 01276e24f3d4921ef531473914db1a079acce07f Mon Sep 17 00:00:00 2001 From: Evan Bradley <11745660+evan-bradley@users.noreply.github.com> Date: Wed, 15 May 2024 09:57:32 -0400 Subject: [PATCH 3/3] Update confmap/internal/mapstructure/encoder.go Co-authored-by: Pablo Baeyens --- confmap/internal/mapstructure/encoder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/confmap/internal/mapstructure/encoder.go b/confmap/internal/mapstructure/encoder.go index 75f25f5fd9e..d0e222e08b6 100644 --- a/confmap/internal/mapstructure/encoder.go +++ b/confmap/internal/mapstructure/encoder.go @@ -176,7 +176,7 @@ func (e *Encoder) encodeMap(value reflect.Value) (any, error) { case reflect.String: key = v.String() default: - return nil, fmt.Errorf("%w, key: %q, kind: %v, type: %v", errNonStringEncodedKey, iterator.Key().Interface(), iterator.Key().Kind(), reflect.TypeOf(encoded)) + return nil, fmt.Errorf("%w, key: %q, kind: %v, type: %T", errNonStringEncodedKey, iterator.Key().Interface(), iterator.Key().Kind(), encoded) } if _, ok := result[key]; ok {