#48: fixes for ptr and slice cases
diff --git a/mapstructure.go b/mapstructure.go index a554e79..81b0c01 100644 --- a/mapstructure.go +++ b/mapstructure.go
@@ -546,7 +546,12 @@ // into that. Then set the value of the pointer to this type. valType := val.Type() valElemType := valType.Elem() - realVal := reflect.New(valElemType) + + realVal:=val + if realVal.IsNil() || d.config.ZeroFields { + realVal = reflect.New(valElemType) + } + if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil { return err } @@ -562,20 +567,24 @@ valElemType := valType.Elem() sliceType := reflect.SliceOf(valElemType) - // Check input type - if dataValKind != reflect.Array && dataValKind != reflect.Slice { - // Accept empty map instead of array/slice in weakly typed mode - if d.config.WeaklyTypedInput && dataVal.Kind() == reflect.Map && dataVal.Len() == 0 { - val.Set(reflect.MakeSlice(sliceType, 0, 0)) - return nil - } else { - return fmt.Errorf( - "'%s': source data must be an array or slice, got %s", name, dataValKind) - } - } + valSlice:=val + if valSlice.IsNil() || d.config.ZeroFields { - // Make a new slice to hold our result, same size as the original data. - valSlice := reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len()) + // Check input type + if dataValKind != reflect.Array && dataValKind != reflect.Slice { + // Accept empty map instead of array/slice in weakly typed mode + if d.config.WeaklyTypedInput && dataVal.Kind() == reflect.Map && dataVal.Len() == 0 { + val.Set(reflect.MakeSlice(sliceType, 0, 0)) + return nil + } else { + return fmt.Errorf( + "'%s': source data must be an array or slice, got %s", name, dataValKind) + } + } + + // Make a new slice to hold our result, same size as the original data. + valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len()) + } // Accumulate any errors errors := make([]string, 0)
diff --git a/mapstructure_bugs_test.go b/mapstructure_bugs_test.go index c6b8697..2e210ca 100644 --- a/mapstructure_bugs_test.go +++ b/mapstructure_bugs_test.go
@@ -46,6 +46,7 @@ } } +// #48 func TestNestedTypePointerWithDefaults(t *testing.T) { t.Parallel() @@ -90,12 +91,60 @@ // this is the error if result.Vbar.Vuint != 42 { - t.Errorf("vuint value should be 42: %#v", result.Vbar.Vint) + t.Errorf("vuint value should be 42: %#v", result.Vbar.Vuint) } } +type NestedSlice struct { + Vfoo string + Vbars []Basic + Vempty []Basic +} + +// #48 +func TestNestedTypeSliceWithDefaults(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vfoo": "foo", + "vbars": []map[string]interface{}{ + { "vstring": "foo", "vint": 42, "vbool": true }, + { "vint": 42, "vbool": true }, + }, + "vempty": []map[string]interface{}{ + { "vstring": "foo", "vint": 42, "vbool": true }, + { "vint": 42, "vbool": true }, + }, + } + + result:=NestedSlice{ + Vbars: []Basic{ + {Vuint: 42}, + {Vstring: "foo"}, + }, + } + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err.Error()) + } + + if result.Vfoo != "foo" { + t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) + } + + if result.Vbars[0].Vstring != "foo" { + t.Errorf("vstring value should be 'foo': %#v", result.Vbars[0].Vstring) + } + // this is the error + if result.Vbars[0].Vuint != 42 { + t.Errorf("vuint value should be 42: %#v", result.Vbars[0].Vuint) + } + +} + +// #48 workaround func TestNestedTypeWithDefaults(t *testing.T) { t.Parallel() @@ -140,7 +189,7 @@ // this is the error if result.Vbar.Vuint != 42 { - t.Errorf("vuint value should be 42: %#v", result.Vbar.Vint) + t.Errorf("vuint value should be 42: %#v", result.Vbar.Vuint) } } \ No newline at end of file