returning untyped nil from decode hook will assign properly to interface
diff --git a/decode_hooks.go b/decode_hooks.go
index aa91f76..115ae67 100644
--- a/decode_hooks.go
+++ b/decode_hooks.go
@@ -72,7 +72,10 @@
}
// Modify the from kind to be correct with the new data
- f = reflect.ValueOf(data).Type()
+ f = nil
+ if val := reflect.ValueOf(data); val.IsValid() {
+ f = val.Type()
+ }
}
return data, nil
diff --git a/mapstructure.go b/mapstructure.go
index a367a95..4490521 100644
--- a/mapstructure.go
+++ b/mapstructure.go
@@ -246,6 +246,10 @@
// value to "data" of that type.
func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error {
dataVal := reflect.ValueOf(data)
+ if !dataVal.IsValid() {
+ dataVal = reflect.Zero(val.Type())
+ }
+
dataValType := dataVal.Type()
if !dataValType.AssignableTo(val.Type()) {
return fmt.Errorf(
diff --git a/mapstructure_test.go b/mapstructure_test.go
index 45e7284..4d40ace 100644
--- a/mapstructure_test.go
+++ b/mapstructure_test.go
@@ -1,6 +1,7 @@
package mapstructure
import (
+ "io"
"reflect"
"sort"
"strings"
@@ -60,6 +61,10 @@
Vbar *Basic
}
+type NilInterface struct {
+ W io.Writer
+}
+
type Slice struct {
Vfoo string
Vbar []string
@@ -382,6 +387,42 @@
}
}
+func TestDecode_NilInterfaceHook(t *testing.T) {
+ t.Parallel()
+
+ input := map[string]interface{}{
+ "w": "",
+ }
+
+ decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) {
+ if t.String() == "io.Writer" {
+ return nil, nil
+ }
+
+ return v, nil
+ }
+
+ var result NilInterface
+ config := &DecoderConfig{
+ DecodeHook: decodeHook,
+ Result: &result,
+ }
+
+ decoder, err := NewDecoder(config)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ err = decoder.Decode(input)
+ if err != nil {
+ t.Fatalf("got an err: %s", err)
+ }
+
+ if result.W != nil {
+ t.Errorf("W should be nil: %#v", result.W)
+ }
+}
+
func TestDecode_NonStruct(t *testing.T) {
t.Parallel()