Decoding arbitrary maps works
diff --git a/mapstructure.go b/mapstructure.go index eda04fd..536e8c2 100644 --- a/mapstructure.go +++ b/mapstructure.go
@@ -49,6 +49,8 @@ return decodeBasic(name, data, val) case reflect.Struct: return decodeStruct(name, data, val) + case reflect.Map: + return decodeMap(name, data, val) } // If we reached this point then we weren't able to decode it @@ -75,6 +77,25 @@ return nil } +func decodeMap(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + if dataVal.Kind() != reflect.Map { + return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) + } + + dataValType := dataVal.Type() + if dataValType.Key().Kind() != reflect.String { + return fmt.Errorf( + "'%s' needs a map with string keys, has '%s' keys", + name, dataValType.Key().Kind()) + } + + // Just go ahead and set one map to the other... + val.Set(dataVal) + + return nil +} + func decodeStruct(name string, data interface{}, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataValKind := dataVal.Kind()
diff --git a/mapstructure_test.go b/mapstructure_test.go index f420fc5..d87d151 100644 --- a/mapstructure_test.go +++ b/mapstructure_test.go
@@ -9,6 +9,11 @@ Vextra string } +type Map struct { + Vfoo string + Vother map[string]interface{} +} + type Nested struct { Vfoo string Vbar Basic @@ -47,6 +52,46 @@ } } +func TestMap(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vfoo": "foo", + "vother": map[string]interface{}{ + "foo": 42, + "bar": true, + }, + } + + var result Map + err := Decode(input, &result) + if err != nil { + t.Errorf("got an error: %s", err) + t.FailNow() + } + + if result.Vfoo != "foo" { + t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) + } + + if result.Vother == nil { + t.Error("vother should not be nil") + t.FailNow() + } + + if len(result.Vother) != 2 { + t.Error("vother should have two items") + } + + if result.Vother["foo"].(int) != 42 { + t.Errorf("'foo' key should be 42, got: %#v", result.Vother["foo"]) + } + + if result.Vother["bar"].(bool) != true { + t.Errorf("'bar' key should be true, got: %#v", result.Vother["bar"]) + } +} + func TestNestedType(t *testing.T) { t.Parallel()