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