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.
6 // Based on src/pkg/reflect/deepequal.go from official
15 // Traverses recursively both values, assigning src's fields values to dst.
16 // The map argument tracks comparisons that have already been seen, which allows
17 // short circuiting on recursive types.
18 func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, overwrite bool) (err error) {
23 addr := dst.UnsafeAddr()
27 for p := seen; p != nil; p = p.next {
28 if p.ptr == addr && p.typ == typ {
32 // Remember, remember...
33 visited[h] = &visit{addr, typ, seen}
37 for i, n := 0, dst.NumField(); i < n; i++ {
38 if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, overwrite); err != nil {
43 for _, key := range src.MapKeys() {
44 srcElement := src.MapIndex(key)
45 if !srcElement.IsValid() {
48 dstElement := dst.MapIndex(key)
49 switch srcElement.Kind() {
50 case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice:
51 if srcElement.IsNil() {
56 switch reflect.TypeOf(srcElement.Interface()).Kind() {
62 if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
67 if !isEmptyValue(srcElement) && (overwrite || (!dstElement.IsValid() || isEmptyValue(dst))) {
69 dst.Set(reflect.MakeMap(dst.Type()))
71 dst.SetMapIndex(key, srcElement)
76 case reflect.Interface:
79 } else if dst.IsNil() {
80 if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
83 } else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, overwrite); err != nil {
87 if dst.CanSet() && !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) {
94 // Merge sets fields' values in dst from src if they have a zero
95 // value of their type.
96 // dst and src must be valid same-type structs and dst must be
97 // a pointer to struct.
98 // It won't merge unexported (private) fields and will do recursively
99 // any exported field.
100 func Merge(dst, src interface{}) error {
101 return merge(dst, src, false)
104 func MergeWithOverwrite(dst, src interface{}) error {
105 return merge(dst, src, true)
108 func merge(dst, src interface{}, overwrite bool) error {
110 vDst, vSrc reflect.Value
113 if vDst, vSrc, err = resolveValues(dst, src); err != nil {
116 if vDst.Type() != vSrc.Type() {
117 return ErrDifferentArgumentsTypes
119 return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, overwrite)