blob: f1a0c80a9d865b1b8022abb63bd77ca5f3212cc1 [file] [log] [blame]
package mapstructure
import (
"errors"
"fmt"
"reflect"
"strings"
)
// MapToStruct takes a map and uses reflection to convert it into the
// given Go native structure. val must be a pointer to a struct.
func MapToStruct(m map[string]interface{}, rawVal interface{}) error {
val := reflect.ValueOf(rawVal)
if val.Kind() != reflect.Ptr {
return errors.New("val must be a pointer")
}
val = val.Elem()
if !val.CanAddr() {
return errors.New("val must be addressable (a pointer)")
}
if val.Kind() != reflect.Struct {
return errors.New("val must be an addressable struct")
}
valType := val.Type()
for i := 0; i < valType.NumField(); i++ {
fieldType := valType.Field(i)
fieldName := fieldType.Name
rawMapVal, ok := m[fieldName]
if !ok {
// Do a slower search by iterating over each key and
// doing case-insensitive search.
for mK, mV := range m {
if strings.EqualFold(mK, fieldName) {
rawMapVal = mV
break
}
}
if rawMapVal == nil {
// There was no matching key in the map for the value in
// the struct. Just ignore.
continue
}
}
field := val.Field(i)
if !field.IsValid() {
// This should never happen
panic("field is not valid")
}
mapVal := reflect.ValueOf(rawMapVal)
if !mapVal.IsValid() {
// This should never happen because we got the value out
// of the map.
panic("map value is not valid")
}
mapValType := mapVal.Type()
if !mapValType.AssignableTo(field.Type()) {
// If the value in the map can't be assigned to the field
// in the struct, then this is a problem...
return fmt.Errorf(
"field '%s' expected type '%s', got '%s'",
fieldName, field.Type(), mapValType)
}
field.Set(mapVal)
}
return nil
}