main
Raw Download raw file
  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}