1 // Copyright 2014 Dario Castañé. All rights reserved.
2 // Copyright 2009 The Go Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file.
6 // Based on src/pkg/reflect/deepequal.go from official
18 func changeInitialCase(s string, mapper func(rune) rune) string {
22 r, n := utf8.DecodeRuneInString(s)
23 return string(mapper(r)) + s[n:]
26 func isExported(field reflect.StructField) bool {
27 r, _ := utf8.DecodeRuneInString(field.Name)
28 return r >= 'A' && r <= 'Z'
31 // Traverses recursively both values, assigning src's fields values to dst.
32 // The map argument tracks comparisons that have already been seen, which allows
33 // short circuiting on recursive types.
34 func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, overwrite bool) (err error) {
36 addr := dst.UnsafeAddr()
40 for p := seen; p != nil; p = p.next {
41 if p.ptr == addr && p.typ == typ {
45 // Remember, remember...
46 visited[h] = &visit{addr, typ, seen}
48 zeroValue := reflect.Value{}
51 dstMap := dst.Interface().(map[string]interface{})
52 for i, n := 0, src.NumField(); i < n; i++ {
54 field := srcType.Field(i)
55 if !isExported(field) {
58 fieldName := field.Name
59 fieldName = changeInitialCase(fieldName, unicode.ToLower)
60 if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v)) || overwrite) {
61 dstMap[fieldName] = src.Field(i).Interface()
65 srcMap := src.Interface().(map[string]interface{})
66 for key := range srcMap {
67 srcValue := srcMap[key]
68 fieldName := changeInitialCase(key, unicode.ToUpper)
69 dstElement := dst.FieldByName(fieldName)
70 if dstElement == zeroValue {
71 // We discard it because the field doesn't exist.
74 srcElement := reflect.ValueOf(srcValue)
75 dstKind := dstElement.Kind()
76 srcKind := srcElement.Kind()
77 if srcKind == reflect.Ptr && dstKind != reflect.Ptr {
78 srcElement = srcElement.Elem()
79 srcKind = reflect.TypeOf(srcElement.Interface()).Kind()
80 } else if dstKind == reflect.Ptr {
81 // Can this work? I guess it can't.
82 if srcKind != reflect.Ptr && srcElement.CanAddr() {
83 srcPtr := srcElement.Addr()
84 srcElement = reflect.ValueOf(srcPtr)
88 if !srcElement.IsValid() {
91 if srcKind == dstKind {
92 if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
96 if srcKind == reflect.Map {
97 if err = deepMap(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
101 return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind)
109 // Map sets fields' values in dst from src.
110 // src can be a map with string keys or a struct. dst must be the opposite:
111 // if src is a map, dst must be a valid pointer to struct. If src is a struct,
112 // dst must be map[string]interface{}.
113 // It won't merge unexported (private) fields and will do recursively
114 // any exported field.
115 // If dst is a map, keys will be src fields' names in lower camel case.
116 // Missing key in src that doesn't match a field in dst will be skipped. This
117 // doesn't apply if dst is a map.
118 // This is separated method from Merge because it is cleaner and it keeps sane
119 // semantics: merging equal types, mapping different (restricted) types.
120 func Map(dst, src interface{}) error {
121 return _map(dst, src, false)
124 func MapWithOverwrite(dst, src interface{}) error {
125 return _map(dst, src, true)
128 func _map(dst, src interface{}, overwrite bool) error {
130 vDst, vSrc reflect.Value
133 if vDst, vSrc, err = resolveValues(dst, src); err != nil {
136 // To be friction-less, we redirect equal-type arguments
137 // to deepMerge. Only because arguments can be anything.
138 if vSrc.Kind() == vDst.Kind() {
139 return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, overwrite)
143 if vDst.Kind() != reflect.Map {
144 return ErrExpectedMapAsDestination
147 if vDst.Kind() != reflect.Struct {
148 return ErrExpectedStructAsDestination
151 return ErrNotSupported
153 return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, overwrite)