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 hasExportedField(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 || hasExportedField(dst.Field(i))
21		} else {
22			exported = exported || len(field.PkgPath) == 0
23		}
24	}
25	return
26}
27
28type Config struct {
29	Overwrite                    bool
30	AppendSlice                  bool
31	TypeCheck                    bool
32	Transformers                 Transformers
33	overwriteWithEmptyValue      bool
34	overwriteSliceWithEmptyValue bool
35}
36
37type Transformers interface {
38	Transformer(reflect.Type) func(dst, src reflect.Value) error
39}
40
41// Traverses recursively both values, assigning src's fields values to dst.
42// The map argument tracks comparisons that have already been seen, which allows
43// short circuiting on recursive types.
44func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
45	overwrite := config.Overwrite
46	typeCheck := config.TypeCheck
47	overwriteWithEmptySrc := config.overwriteWithEmptyValue
48	overwriteSliceWithEmptySrc := config.overwriteSliceWithEmptyValue
49	config.overwriteWithEmptyValue = false
50
51	if !src.IsValid() {
52		return
53	}
54	if dst.CanAddr() {
55		addr := dst.UnsafeAddr()
56		h := 17 * addr
57		seen := visited[h]
58		typ := dst.Type()
59		for p := seen; p != nil; p = p.next {
60			if p.ptr == addr && p.typ == typ {
61				return nil
62			}
63		}
64		// Remember, remember...
65		visited[h] = &visit{addr, typ, seen}
66	}
67
68	if config.Transformers != nil && !isEmptyValue(dst) {
69		if fn := config.Transformers.Transformer(dst.Type()); fn != nil {
70			err = fn(dst, src)
71			return
72		}
73	}
74
75	switch dst.Kind() {
76	case reflect.Struct:
77		if hasExportedField(dst) {
78			for i, n := 0, dst.NumField(); i < n; i++ {
79				if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil {
80					return
81				}
82			}
83		} else {
84			if dst.CanSet() && (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) {
85				dst.Set(src)
86			}
87		}
88	case reflect.Map:
89		if dst.IsNil() && !src.IsNil() {
90			dst.Set(reflect.MakeMap(dst.Type()))
91		}
92		for _, key := range src.MapKeys() {
93			srcElement := src.MapIndex(key)
94			if !srcElement.IsValid() {
95				continue
96			}
97			dstElement := dst.MapIndex(key)
98			switch srcElement.Kind() {
99			case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice:
100				if srcElement.IsNil() {
101					continue
102				}
103				fallthrough
104			default:
105				if !srcElement.CanInterface() {
106					continue
107				}
108				switch reflect.TypeOf(srcElement.Interface()).Kind() {
109				case reflect.Struct:
110					fallthrough
111				case reflect.Ptr:
112					fallthrough
113				case reflect.Map:
114					srcMapElm := srcElement
115					dstMapElm := dstElement
116					if srcMapElm.CanInterface() {
117						srcMapElm = reflect.ValueOf(srcMapElm.Interface())
118						if dstMapElm.IsValid() {
119							dstMapElm = reflect.ValueOf(dstMapElm.Interface())
120						}
121					}
122					if err = deepMerge(dstMapElm, srcMapElm, visited, depth+1, config); err != nil {
123						return
124					}
125				case reflect.Slice:
126					srcSlice := reflect.ValueOf(srcElement.Interface())
127
128					var dstSlice reflect.Value
129					if !dstElement.IsValid() || dstElement.IsNil() {
130						dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len())
131					} else {
132						dstSlice = reflect.ValueOf(dstElement.Interface())
133					}
134
135					if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
136						if typeCheck && srcSlice.Type() != dstSlice.Type() {
137							return fmt.Errorf("cannot override two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
138						}
139						dstSlice = srcSlice
140					} else if config.AppendSlice {
141						if srcSlice.Type() != dstSlice.Type() {
142							return fmt.Errorf("cannot append two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
143						}
144						dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
145					}
146					dst.SetMapIndex(key, dstSlice)
147				}
148			}
149			if dstElement.IsValid() && !isEmptyValue(dstElement) && (reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map || reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Slice) {
150				continue
151			}
152
153			if srcElement.IsValid() && ((srcElement.Kind() != reflect.Ptr && overwrite) || !dstElement.IsValid() || isEmptyValue(dstElement)) {
154				if dst.IsNil() {
155					dst.Set(reflect.MakeMap(dst.Type()))
156				}
157				dst.SetMapIndex(key, srcElement)
158			}
159		}
160	case reflect.Slice:
161		if !dst.CanSet() {
162			break
163		}
164		if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
165			dst.Set(src)
166		} else if config.AppendSlice {
167			if src.Type() != dst.Type() {
168				return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
169			}
170			dst.Set(reflect.AppendSlice(dst, src))
171		}
172	case reflect.Ptr:
173		fallthrough
174	case reflect.Interface:
175		if src.IsNil() {
176			break
177		}
178
179		if dst.Kind() != reflect.Ptr && src.Type().AssignableTo(dst.Type()) {
180			if dst.IsNil() || overwrite {
181				if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
182					dst.Set(src)
183				}
184			}
185			break
186		}
187
188		if src.Kind() != reflect.Interface {
189			if dst.IsNil() || (src.Kind() != reflect.Ptr && overwrite) {
190				if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
191					dst.Set(src)
192				}
193			} else if src.Kind() == reflect.Ptr {
194				if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
195					return
196				}
197			} else if dst.Elem().Type() == src.Type() {
198				if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
199					return
200				}
201			} else {
202				return ErrDifferentArgumentsTypes
203			}
204			break
205		}
206		if dst.IsNil() || overwrite {
207			if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
208				dst.Set(src)
209			}
210		} else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
211			return
212		}
213	default:
214		if dst.CanSet() && (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) {
215			dst.Set(src)
216		}
217	}
218
219	return
220}
221
222// Merge will fill any empty for value type attributes on the dst struct using corresponding
223// src attributes if they themselves are not empty. dst and src must be valid same-type structs
224// and dst must be a pointer to struct.
225// It won't merge unexported (private) fields and will do recursively any exported field.
226func Merge(dst, src interface{}, opts ...func(*Config)) error {
227	return merge(dst, src, opts...)
228}
229
230// MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overridden by
231// non-empty src attribute values.
232// Deprecated: use Merge(…) with WithOverride
233func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
234	return merge(dst, src, append(opts, WithOverride)...)
235}
236
237// WithTransformers adds transformers to merge, allowing to customize the merging of some types.
238func WithTransformers(transformers Transformers) func(*Config) {
239	return func(config *Config) {
240		config.Transformers = transformers
241	}
242}
243
244// WithOverride will make merge override non-empty dst attributes with non-empty src attributes values.
245func WithOverride(config *Config) {
246	config.Overwrite = true
247}
248
249// WithOverride will make merge override empty dst slice with empty src slice.
250func WithOverrideEmptySlice(config *Config) {
251	config.overwriteSliceWithEmptyValue = true
252}
253
254// WithAppendSlice will make merge append slices instead of overwriting it.
255func WithAppendSlice(config *Config) {
256	config.AppendSlice = true
257}
258
259// WithTypeCheck will make merge check types while overwriting it (must be used with WithOverride).
260func WithTypeCheck(config *Config) {
261	config.TypeCheck = true
262}
263
264func merge(dst, src interface{}, opts ...func(*Config)) error {
265	var (
266		vDst, vSrc reflect.Value
267		err        error
268	)
269
270	config := &Config{}
271
272	for _, opt := range opts {
273		opt(config)
274	}
275
276	if vDst, vSrc, err = resolveValues(dst, src); err != nil {
277		return err
278	}
279	if vDst.Type() != vSrc.Type() {
280		return ErrDifferentArgumentsTypes
281	}
282	return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
283}
284