Skip to content

Commit

Permalink
add-special-handling
Browse files Browse the repository at this point in the history
  • Loading branch information
BoskyWSMFN committed Sep 2, 2024
1 parent 46effb6 commit 455d289
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
### Added

- Support converting unmarshalled configurations to `interface{}`.
Defaults to `map[string]interface{}` for now if the source has nested values and
the destination is just an `interface{}`.

## [1.3.0] - 2024-08-26

Expand Down
53 changes: 50 additions & 3 deletions internal/convert/converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,7 @@ func (c Converter) convert(name string, from any, toVal reflect.Value) error { /
case toVal.Kind() == reflect.Struct:
return c.convertStruct(name, fromVal, toVal)
case toVal.Kind() == reflect.Interface: // Right after all other checks.
toVal.Set(fromVal)

return nil
return c.convertInterface(name, fromVal, toVal)
default:
// If it reached here then it weren't able to convert it.
return fmt.Errorf("%s: unsupported type: %s", name, toVal.Kind()) //nolint:err113
Expand Down Expand Up @@ -554,6 +552,55 @@ func (c Converter) convertStruct(name string, fromVal, toVal reflect.Value) erro
}
}

func (c Converter) convertInterface(name string, fromVal, toVal reflect.Value) error {
switch fromVal.Kind() {
case reflect.Map:
if fromVal.IsNil() {
toVal.SetZero()

Check warning on line 559 in internal/convert/converter.go

View check run for this annotation

Codecov / codecov/patch

internal/convert/converter.go#L559

Added line #L559 was not covered by tests

return nil

Check warning on line 561 in internal/convert/converter.go

View check run for this annotation

Codecov / codecov/patch

internal/convert/converter.go#L561

Added line #L561 was not covered by tests
}

if toVal.IsNil() {
toVal.Set(reflect.MakeMapWithSize(fromVal.Type(), fromVal.Len()))
}

fromKeyType := fromVal.Type().Key()
fromValueType := fromVal.Type().Elem()
errs := make([]error, 0, fromVal.Len())
for _, fromKeyVal := range fromVal.MapKeys() {
fieldName := name + "[" + fromKeyVal.String() + "]"

fromValueVal := fromVal.MapIndex(fromKeyVal)
toValueVal := reflect.New(fromValueType)
key, value := maps.Unpack(fromValueVal.Interface())
if err := c.convert(fieldName, value, pointer(toValueVal)); err != nil {
errs = append(errs, err)

Check warning on line 578 in internal/convert/converter.go

View check run for this annotation

Codecov / codecov/patch

internal/convert/converter.go#L578

Added line #L578 was not covered by tests

continue

Check warning on line 580 in internal/convert/converter.go

View check run for this annotation

Codecov / codecov/patch

internal/convert/converter.go#L580

Added line #L580 was not covered by tests
}

if key == "" {
key = fromKeyVal.String()
}
toKeyVal := reflect.New(fromKeyType)
if err := c.convert(fieldName, key, pointer(toKeyVal)); err != nil {
errs = append(errs, err)

Check warning on line 588 in internal/convert/converter.go

View check run for this annotation

Codecov / codecov/patch

internal/convert/converter.go#L588

Added line #L588 was not covered by tests

continue

Check warning on line 590 in internal/convert/converter.go

View check run for this annotation

Codecov / codecov/patch

internal/convert/converter.go#L590

Added line #L590 was not covered by tests
}

toVal.Elem().SetMapIndex(reflect.Indirect(toKeyVal), reflect.Indirect(toValueVal))
}

return errors.Join(errs...)
default:
toVal.Set(fromVal)

return nil
}
}

func pointer(val reflect.Value) reflect.Value {
if val.Kind() == reflect.Pointer {
if val.IsNil() {
Expand Down
15 changes: 15 additions & 0 deletions internal/convert/converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,21 @@ func TestConverter(t *testing.T) { //nolint:maintidx
Key2: "value2",
}),
},
{
description: "packed KV and field to interface{}",
from: map[string]interface{}{
"key1": maps.KeyValue{
Key: "key1",
Value: "value1",
},
"key2": "value2",
},
to: pointer(any(nil)),
expected: pointer(any(map[string]interface{}{
"key1": "value1",
"key2": "value2",
})),
},
{
description: "slice to interface",
from: []int{1, 2, 3},
Expand Down

0 comments on commit 455d289

Please sign in to comment.