Skip to content

Commit

Permalink
fix:panic while processing nested map and slice of structures (#152)
Browse files Browse the repository at this point in the history
  • Loading branch information
XIELongDragon committed Sep 25, 2024
1 parent b4a66c3 commit 20fdfff
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 19 deletions.
6 changes: 3 additions & 3 deletions aconfigtoml/go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module github.com/cristalhq/aconfig/aconfigtoml

go 1.16
go 1.18

require (
github.com/BurntSushi/toml v1.1.0
github.com/cristalhq/aconfig v0.17.0
github.com/BurntSushi/toml v1.4.0
github.com/cristalhq/aconfig v0.18.5
)
8 changes: 4 additions & 4 deletions aconfigtoml/go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/cristalhq/aconfig v0.17.0 h1:VYqg0YOM5yUEx0KH/VwUYF2e/PNI7dcUE66y+xEx73s=
github.com/cristalhq/aconfig v0.17.0/go.mod h1:NXaRp+1e6bkO4dJn+wZ71xyaihMDYPtCSvEhMTm/H3E=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/cristalhq/aconfig v0.18.5 h1:QqXH/Gy2c4QUQJTV2BN8UAuL/rqZ3IwhvxeC8OgzquA=
github.com/cristalhq/aconfig v0.18.5/go.mod h1:NXaRp+1e6bkO4dJn+wZ71xyaihMDYPtCSvEhMTm/H3E=
9 changes: 9 additions & 0 deletions aconfigtoml/testdata/config.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
foo = "value1"
bar = "value2"

[outter]
[outter.inner]
[[outter.inner.t1]]
a = "a"
b = "b"
[[outter.inner.t1]]
a = "c"
b = "d"
12 changes: 10 additions & 2 deletions aconfigtoml/toml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ var configEmbed embed.FS

func TestTOMLEmbed(t *testing.T) {
var cfg struct {
Foo string
Bar string
Foo string
Bar string
Outter map[string]map[string][]struct {
A string
B string
}
}
loader := aconfig.LoaderFor(&cfg, aconfig.Config{
SkipDefaults: true,
Expand All @@ -40,6 +44,10 @@ func TestTOMLEmbed(t *testing.T) {
if cfg.Bar != "value2" {
t.Fatalf("have: %v", cfg.Bar)
}

if cfg.Outter["inner"]["t1"][0].A != "a" {
t.Fatalf("have: %v", cfg.Outter["inner"]["t1"][0].A)
}
}

func TestTOML(t *testing.T) {
Expand Down
43 changes: 33 additions & 10 deletions reflection.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,11 @@ func (l *Loader) setFieldData(field *fieldData, value interface{}) error {
return nil
}

pv := field.value.Addr().Interface()
if v, ok := pv.(encoding.TextUnmarshaler); ok {
return v.UnmarshalText([]byte(fmt.Sprint(value)))
if field.value.CanAddr() {
pv := field.value.Addr().Interface()
if v, ok := pv.(encoding.TextUnmarshaler); ok {
return v.UnmarshalText([]byte(fmt.Sprint(value)))
}
}

switch kind := field.value.Type().Kind(); kind {
Expand All @@ -186,26 +188,44 @@ func (l *Loader) setFieldData(field *fieldData, value interface{}) error {
case reflect.Interface:
return l.setInterface(field, value)

case reflect.Struct:
fd := l.newFieldData(reflect.StructField{}, field.value, nil)
return l.m2s(mii(value), fd.value)

case reflect.Slice:
if field.field.Type.Elem().Kind() == reflect.Struct {
if value == nil {
return nil
}
v, ok := value.([]interface{})

if v, ok := value.([]interface{}); ok {
slice := reflect.MakeSlice(field.field.Type, len(v), len(v))
for i, val := range v {
vv := mii(val)

fd := l.newFieldData(reflect.StructField{}, slice.Index(i), nil)
if err := l.m2s(vv, fd.value); err != nil {
return err
}
}
field.value.Set(slice)
return nil
}

v, ok := value.([]map[string]interface{})
if !ok {
panic(fmt.Errorf("%T %v", value, value))
}

slice := reflect.MakeSlice(field.field.Type, len(v), len(v))
for i, val := range v {
vv := mii(val)

fd := l.newFieldData(reflect.StructField{}, slice.Index(i), nil)
if err := l.m2s(vv, fd.value); err != nil {
if err := l.m2s(val, fd.value); err != nil {
return err
}
}
field.value.Set(slice)

return nil
}
return l.setSlice(field, sliceToString(value))
Expand All @@ -223,10 +243,12 @@ func (l *Loader) setFieldData(field *fieldData, value interface{}) error {
return fmt.Errorf("incorrect map key %q: %w", key, err)
}

fdv := l.newSimpleFieldData(reflect.New(field.field.Type.Elem()).Elem())
fdv := l.newFieldData(reflect.StructField{}, reflect.New(field.value.Type().Elem()).Elem(), field)
fdv.field.Type = field.value.Type().Elem()
if err := l.setFieldData(fdv, val); err != nil {
return fmt.Errorf("incorrect map value %q: %w", val, err)
}

mapp.SetMapIndex(fdk.value, fdv.value)
}
field.value.Set(mapp)
Expand Down Expand Up @@ -309,6 +331,7 @@ func (l *Loader) setSlice(field *fieldData, value string) error {
val = strings.TrimSpace(val)

fd := l.newFieldData(reflect.StructField{}, slice.Index(i), nil)
fd.field.Type = field.field.Type.Elem()
if err := l.setFieldData(fd, val); err != nil {
return fmt.Errorf("incorrect slice item %q: %w", val, err)
}
Expand All @@ -334,8 +357,8 @@ func (l *Loader) setMap(field *fieldData, value string) error {
return fmt.Errorf("incorrect map key %q: %w", key, err)
}

fdv := l.newSimpleFieldData(reflect.New(field.field.Type.Elem()).Elem())
fdv.field.Type = field.field.Type.Elem()
fdv := l.newFieldData(reflect.StructField{}, reflect.New(field.value.Type().Elem()).Elem(), field)
fdv.field.Type = field.value.Type().Elem()
if err := l.setFieldData(fdv, val); err != nil {
return fmt.Errorf("incorrect map value %q: %w", val, err)
}
Expand Down

0 comments on commit 20fdfff

Please sign in to comment.