main
1// Copyright 2013 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)
15
16func hasMergeableFields(dst reflect.Value) (exported bool) {
17 for i, n := 0, dst.NumField(); i < n; i++ {
18 field := dst.Type().Field(i)
19 if field.Anonymous && dst.Field(i).Kind() == reflect.Struct {
20 exported = exported || hasMergeableFields(dst.Field(i))
21 } else if isExportedComponent(&field) {
22 exported = exported || len(field.PkgPath) == 0
23 }
24 }
25 return
26}
27
28func isExportedComponent(field *reflect.StructField) bool {
29 pkgPath := field.PkgPath
30 if len(pkgPath) > 0 {
31 return false
32 }
33 c := field.Name[0]
34 if 'a' <= c && c <= 'z' || c == '_' {
35 return false
36 }
37 return true
38}
39
40type Config struct {
41 Transformers Transformers
42 Overwrite bool
43 ShouldNotDereference bool
44 AppendSlice bool
45 TypeCheck bool
46 overwriteWithEmptyValue bool
47 overwriteSliceWithEmptyValue bool
48 sliceDeepCopy bool
49 debug bool
50}
51
52type Transformers interface {
53 Transformer(reflect.Type) func(dst, src reflect.Value) error
54}
55
56// Traverses recursively both values, assigning src's fields values to dst.
57// The map argument tracks comparisons that have already been seen, which allows
58// short circuiting on recursive types.
59func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
60 overwrite := config.Overwrite
61 typeCheck := config.TypeCheck
62 overwriteWithEmptySrc := config.overwriteWithEmptyValue
63 overwriteSliceWithEmptySrc := config.overwriteSliceWithEmptyValue
64 sliceDeepCopy := config.sliceDeepCopy
65
66 if !src.IsValid() {
67 return
68 }
69 if dst.CanAddr() {
70 addr := dst.UnsafeAddr()
71 h := 17 * addr
72 seen := visited[h]
73 typ := dst.Type()
74 for p := seen; p != nil; p = p.next {
75 if p.ptr == addr && p.typ == typ {
76 return nil
77 }
78 }
79 // Remember, remember...
80 visited[h] = &visit{typ, seen, addr}
81 }
82
83 if config.Transformers != nil && !isReflectNil(dst) && dst.IsValid() {
84 if fn := config.Transformers.Transformer(dst.Type()); fn != nil {
85 err = fn(dst, src)
86 return
87 }
88 }
89
90 switch dst.Kind() {
91 case reflect.Struct:
92 if hasMergeableFields(dst) {
93 for i, n := 0, dst.NumField(); i < n; i++ {
94 if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil {
95 return
96 }
97 }
98 } else {
99 if dst.CanSet() && (isReflectNil(dst) || overwrite) && (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc) {
100 dst.Set(src)
101 }
102 }
103 case reflect.Map:
104 if dst.IsNil() && !src.IsNil() {
105 if dst.CanSet() {
106 dst.Set(reflect.MakeMap(dst.Type()))
107 } else {
108 dst = src
109 return
110 }
111 }
112
113 if src.Kind() != reflect.Map {
114 if overwrite && dst.CanSet() {
115 dst.Set(src)
116 }
117 return
118 }
119
120 for _, key := range src.MapKeys() {
121 srcElement := src.MapIndex(key)
122 if !srcElement.IsValid() {
123 continue
124 }
125 dstElement := dst.MapIndex(key)
126 switch srcElement.Kind() {
127 case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice:
128 if srcElement.IsNil() {
129 if overwrite {
130 dst.SetMapIndex(key, srcElement)
131 }
132 continue
133 }
134 fallthrough
135 default:
136 if !srcElement.CanInterface() {
137 continue
138 }
139 switch reflect.TypeOf(srcElement.Interface()).Kind() {
140 case reflect.Struct:
141 fallthrough
142 case reflect.Ptr:
143 fallthrough
144 case reflect.Map:
145 srcMapElm := srcElement
146 dstMapElm := dstElement
147 if srcMapElm.CanInterface() {
148 srcMapElm = reflect.ValueOf(srcMapElm.Interface())
149 if dstMapElm.IsValid() {
150 dstMapElm = reflect.ValueOf(dstMapElm.Interface())
151 }
152 }
153 if err = deepMerge(dstMapElm, srcMapElm, visited, depth+1, config); err != nil {
154 return
155 }
156 case reflect.Slice:
157 srcSlice := reflect.ValueOf(srcElement.Interface())
158
159 var dstSlice reflect.Value
160 if !dstElement.IsValid() || dstElement.IsNil() {
161 dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len())
162 } else {
163 dstSlice = reflect.ValueOf(dstElement.Interface())
164 }
165
166 if (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) && !config.AppendSlice && !sliceDeepCopy {
167 if typeCheck && srcSlice.Type() != dstSlice.Type() {
168 return fmt.Errorf("cannot override two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
169 }
170 dstSlice = srcSlice
171 } else if config.AppendSlice {
172 if srcSlice.Type() != dstSlice.Type() {
173 return fmt.Errorf("cannot append two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
174 }
175 dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
176 } else if sliceDeepCopy {
177 i := 0
178 for ; i < srcSlice.Len() && i < dstSlice.Len(); i++ {
179 srcElement := srcSlice.Index(i)
180 dstElement := dstSlice.Index(i)
181
182 if srcElement.CanInterface() {
183 srcElement = reflect.ValueOf(srcElement.Interface())
184 }
185 if dstElement.CanInterface() {
186 dstElement = reflect.ValueOf(dstElement.Interface())
187 }
188
189 if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
190 return
191 }
192 }
193
194 }
195 dst.SetMapIndex(key, dstSlice)
196 }
197 }
198
199 if dstElement.IsValid() && !isEmptyValue(dstElement, !config.ShouldNotDereference) {
200 if reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Slice {
201 continue
202 }
203 if reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map && reflect.TypeOf(dstElement.Interface()).Kind() == reflect.Map {
204 continue
205 }
206 }
207
208 if srcElement.IsValid() && ((srcElement.Kind() != reflect.Ptr && overwrite) || !dstElement.IsValid() || isEmptyValue(dstElement, !config.ShouldNotDereference)) {
209 if dst.IsNil() {
210 dst.Set(reflect.MakeMap(dst.Type()))
211 }
212 dst.SetMapIndex(key, srcElement)
213 }
214 }
215
216 // Ensure that all keys in dst are deleted if they are not in src.
217 if overwriteWithEmptySrc {
218 for _, key := range dst.MapKeys() {
219 srcElement := src.MapIndex(key)
220 if !srcElement.IsValid() {
221 dst.SetMapIndex(key, reflect.Value{})
222 }
223 }
224 }
225 case reflect.Slice:
226 if !dst.CanSet() {
227 break
228 }
229 if (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) && !config.AppendSlice && !sliceDeepCopy {
230 dst.Set(src)
231 } else if config.AppendSlice {
232 if src.Type() != dst.Type() {
233 return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
234 }
235 dst.Set(reflect.AppendSlice(dst, src))
236 } else if sliceDeepCopy {
237 for i := 0; i < src.Len() && i < dst.Len(); i++ {
238 srcElement := src.Index(i)
239 dstElement := dst.Index(i)
240 if srcElement.CanInterface() {
241 srcElement = reflect.ValueOf(srcElement.Interface())
242 }
243 if dstElement.CanInterface() {
244 dstElement = reflect.ValueOf(dstElement.Interface())
245 }
246
247 if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
248 return
249 }
250 }
251 }
252 case reflect.Ptr:
253 fallthrough
254 case reflect.Interface:
255 if isReflectNil(src) {
256 if overwriteWithEmptySrc && dst.CanSet() && src.Type().AssignableTo(dst.Type()) {
257 dst.Set(src)
258 }
259 break
260 }
261
262 if src.Kind() != reflect.Interface {
263 if dst.IsNil() || (src.Kind() != reflect.Ptr && overwrite) {
264 if dst.CanSet() && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) {
265 dst.Set(src)
266 }
267 } else if src.Kind() == reflect.Ptr {
268 if !config.ShouldNotDereference {
269 if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
270 return
271 }
272 } else {
273 if overwriteWithEmptySrc || (overwrite && !src.IsNil()) || dst.IsNil() {
274 dst.Set(src)
275 }
276 }
277 } else if dst.Elem().Type() == src.Type() {
278 if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
279 return
280 }
281 } else {
282 return ErrDifferentArgumentsTypes
283 }
284 break
285 }
286
287 if dst.IsNil() || overwrite {
288 if dst.CanSet() && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) {
289 dst.Set(src)
290 }
291 break
292 }
293
294 if dst.Elem().Kind() == src.Elem().Kind() {
295 if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
296 return
297 }
298 break
299 }
300 default:
301 mustSet := (isEmptyValue(dst, !config.ShouldNotDereference) || overwrite) && (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc)
302 if mustSet {
303 if dst.CanSet() {
304 dst.Set(src)
305 } else {
306 dst = src
307 }
308 }
309 }
310
311 return
312}
313
314// Merge will fill any empty for value type attributes on the dst struct using corresponding
315// src attributes if they themselves are not empty. dst and src must be valid same-type structs
316// and dst must be a pointer to struct.
317// It won't merge unexported (private) fields and will do recursively any exported field.
318func Merge(dst, src interface{}, opts ...func(*Config)) error {
319 return merge(dst, src, opts...)
320}
321
322// MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overridden by
323// non-empty src attribute values.
324// Deprecated: use Merge(…) with WithOverride
325func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
326 return merge(dst, src, append(opts, WithOverride)...)
327}
328
329// WithTransformers adds transformers to merge, allowing to customize the merging of some types.
330func WithTransformers(transformers Transformers) func(*Config) {
331 return func(config *Config) {
332 config.Transformers = transformers
333 }
334}
335
336// WithOverride will make merge override non-empty dst attributes with non-empty src attributes values.
337func WithOverride(config *Config) {
338 config.Overwrite = true
339}
340
341// WithOverwriteWithEmptyValue will make merge override non empty dst attributes with empty src attributes values.
342func WithOverwriteWithEmptyValue(config *Config) {
343 config.Overwrite = true
344 config.overwriteWithEmptyValue = true
345}
346
347// WithOverrideEmptySlice will make merge override empty dst slice with empty src slice.
348func WithOverrideEmptySlice(config *Config) {
349 config.overwriteSliceWithEmptyValue = true
350}
351
352// WithoutDereference prevents dereferencing pointers when evaluating whether they are empty
353// (i.e. a non-nil pointer is never considered empty).
354func WithoutDereference(config *Config) {
355 config.ShouldNotDereference = true
356}
357
358// WithAppendSlice will make merge append slices instead of overwriting it.
359func WithAppendSlice(config *Config) {
360 config.AppendSlice = true
361}
362
363// WithTypeCheck will make merge check types while overwriting it (must be used with WithOverride).
364func WithTypeCheck(config *Config) {
365 config.TypeCheck = true
366}
367
368// WithSliceDeepCopy will merge slice element one by one with Overwrite flag.
369func WithSliceDeepCopy(config *Config) {
370 config.sliceDeepCopy = true
371 config.Overwrite = true
372}
373
374func merge(dst, src interface{}, opts ...func(*Config)) error {
375 if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
376 return ErrNonPointerArgument
377 }
378 var (
379 vDst, vSrc reflect.Value
380 err error
381 )
382
383 config := &Config{}
384
385 for _, opt := range opts {
386 opt(config)
387 }
388
389 if vDst, vSrc, err = resolveValues(dst, src); err != nil {
390 return err
391 }
392 if vDst.Type() != vSrc.Type() {
393 return ErrDifferentArgumentsTypes
394 }
395 return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
396}
397
398// IsReflectNil is the reflect value provided nil
399func isReflectNil(v reflect.Value) bool {
400 k := v.Kind()
401 switch k {
402 case reflect.Interface, reflect.Slice, reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr:
403 // Both interface and slice are nil if first word is 0.
404 // Both are always bigger than a word; assume flagIndir.
405 return v.IsNil()
406 default:
407 return false
408 }
409}