1
2
3
4
5
6
7
8
9 package mergo
10
11 import (
12 "fmt"
13 "reflect"
14 )
15
16 func 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
28 func 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
40 type 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
52 type Transformers interface {
53 Transformer(reflect.Type) func(dst, src reflect.Value) error
54 }
55
56
57
58
59 func 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
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
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
315
316
317
318 func Merge(dst, src interface{}, opts ...func(*Config)) error {
319 return merge(dst, src, opts...)
320 }
321
322
323
324
325 func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
326 return merge(dst, src, append(opts, WithOverride)...)
327 }
328
329
330 func WithTransformers(transformers Transformers) func(*Config) {
331 return func(config *Config) {
332 config.Transformers = transformers
333 }
334 }
335
336
337 func WithOverride(config *Config) {
338 config.Overwrite = true
339 }
340
341
342 func WithOverwriteWithEmptyValue(config *Config) {
343 config.Overwrite = true
344 config.overwriteWithEmptyValue = true
345 }
346
347
348 func WithOverrideEmptySlice(config *Config) {
349 config.overwriteSliceWithEmptyValue = true
350 }
351
352
353
354 func WithoutDereference(config *Config) {
355 config.ShouldNotDereference = true
356 }
357
358
359 func WithAppendSlice(config *Config) {
360 config.AppendSlice = true
361 }
362
363
364 func WithTypeCheck(config *Config) {
365 config.TypeCheck = true
366 }
367
368
369 func WithSliceDeepCopy(config *Config) {
370 config.sliceDeepCopy = true
371 config.Overwrite = true
372 }
373
374 func 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
399 func 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
404
405 return v.IsNil()
406 default:
407 return false
408 }
409 }
410
View as plain text