blob: 6ea38e636b64fed288b527c244d85515fb606c54 [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001// 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.
5
6// Based on src/pkg/reflect/deepequal.go from official
7// golang's stdlib.
8
9package mergo
10
11import (
12 "fmt"
13 "reflect"
14 "unicode"
15 "unicode/utf8"
16)
17
18func changeInitialCase(s string, mapper func(rune) rune) string {
19 if s == "" {
20 return s
21 }
22 r, n := utf8.DecodeRuneInString(s)
23 return string(mapper(r)) + s[n:]
24}
25
26func isExported(field reflect.StructField) bool {
27 r, _ := utf8.DecodeRuneInString(field.Name)
28 return r >= 'A' && r <= 'Z'
29}
30
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.
34func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
35 overwrite := config.Overwrite
36 if dst.CanAddr() {
37 addr := dst.UnsafeAddr()
38 h := 17 * addr
39 seen := visited[h]
40 typ := dst.Type()
41 for p := seen; p != nil; p = p.next {
42 if p.ptr == addr && p.typ == typ {
43 return nil
44 }
45 }
46 // Remember, remember...
47 visited[h] = &visit{addr, typ, seen}
48 }
49 zeroValue := reflect.Value{}
50 switch dst.Kind() {
51 case reflect.Map:
52 dstMap := dst.Interface().(map[string]interface{})
53 for i, n := 0, src.NumField(); i < n; i++ {
54 srcType := src.Type()
55 field := srcType.Field(i)
56 if !isExported(field) {
57 continue
58 }
59 fieldName := field.Name
60 fieldName = changeInitialCase(fieldName, unicode.ToLower)
61 if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v)) || overwrite) {
62 dstMap[fieldName] = src.Field(i).Interface()
63 }
64 }
65 case reflect.Ptr:
66 if dst.IsNil() {
67 v := reflect.New(dst.Type().Elem())
68 dst.Set(v)
69 }
70 dst = dst.Elem()
71 fallthrough
72 case reflect.Struct:
73 srcMap := src.Interface().(map[string]interface{})
74 for key := range srcMap {
75 srcValue := srcMap[key]
76 fieldName := changeInitialCase(key, unicode.ToUpper)
77 dstElement := dst.FieldByName(fieldName)
78 if dstElement == zeroValue {
79 // We discard it because the field doesn't exist.
80 continue
81 }
82 srcElement := reflect.ValueOf(srcValue)
83 dstKind := dstElement.Kind()
84 srcKind := srcElement.Kind()
85 if srcKind == reflect.Ptr && dstKind != reflect.Ptr {
86 srcElement = srcElement.Elem()
87 srcKind = reflect.TypeOf(srcElement.Interface()).Kind()
88 } else if dstKind == reflect.Ptr {
89 // Can this work? I guess it can't.
90 if srcKind != reflect.Ptr && srcElement.CanAddr() {
91 srcPtr := srcElement.Addr()
92 srcElement = reflect.ValueOf(srcPtr)
93 srcKind = reflect.Ptr
94 }
95 }
96
97 if !srcElement.IsValid() {
98 continue
99 }
100 if srcKind == dstKind {
101 if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
102 return
103 }
104 } else if dstKind == reflect.Interface && dstElement.Kind() == reflect.Interface {
105 if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
106 return
107 }
108 } else if srcKind == reflect.Map {
109 if err = deepMap(dstElement, srcElement, visited, depth+1, config); err != nil {
110 return
111 }
112 } else {
113 return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind)
114 }
115 }
116 }
117 return
118}
119
120// Map sets fields' values in dst from src.
121// src can be a map with string keys or a struct. dst must be the opposite:
122// if src is a map, dst must be a valid pointer to struct. If src is a struct,
123// dst must be map[string]interface{}.
124// It won't merge unexported (private) fields and will do recursively
125// any exported field.
126// If dst is a map, keys will be src fields' names in lower camel case.
127// Missing key in src that doesn't match a field in dst will be skipped. This
128// doesn't apply if dst is a map.
129// This is separated method from Merge because it is cleaner and it keeps sane
130// semantics: merging equal types, mapping different (restricted) types.
131func Map(dst, src interface{}, opts ...func(*Config)) error {
132 return _map(dst, src, opts...)
133}
134
135// MapWithOverwrite will do the same as Map except that non-empty dst attributes will be overridden by
136// non-empty src attribute values.
137// Deprecated: Use Map(…) with WithOverride
138func MapWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
139 return _map(dst, src, append(opts, WithOverride)...)
140}
141
142func _map(dst, src interface{}, opts ...func(*Config)) error {
143 var (
144 vDst, vSrc reflect.Value
145 err error
146 )
147 config := &Config{}
148
149 for _, opt := range opts {
150 opt(config)
151 }
152
153 if vDst, vSrc, err = resolveValues(dst, src); err != nil {
154 return err
155 }
156 // To be friction-less, we redirect equal-type arguments
157 // to deepMerge. Only because arguments can be anything.
158 if vSrc.Kind() == vDst.Kind() {
159 return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
160 }
161 switch vSrc.Kind() {
162 case reflect.Struct:
163 if vDst.Kind() != reflect.Map {
164 return ErrExpectedMapAsDestination
165 }
166 case reflect.Map:
167 if vDst.Kind() != reflect.Struct {
168 return ErrExpectedStructAsDestination
169 }
170 default:
171 return ErrNotSupported
172 }
173 return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, config)
174}