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