Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / imdario / mergo / merge.go
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
9 package mergo
10
11 import (
12         "reflect"
13 )
14
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) {
19         if !src.IsValid() {
20                 return
21         }
22         if dst.CanAddr() {
23                 addr := dst.UnsafeAddr()
24                 h := 17 * addr
25                 seen := visited[h]
26                 typ := dst.Type()
27                 for p := seen; p != nil; p = p.next {
28                         if p.ptr == addr && p.typ == typ {
29                                 return nil
30                         }
31                 }
32                 // Remember, remember...
33                 visited[h] = &visit{addr, typ, seen}
34         }
35         switch dst.Kind() {
36         case reflect.Struct:
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 {
39                                 return
40                         }
41                 }
42         case reflect.Map:
43                 for _, key := range src.MapKeys() {
44                         srcElement := src.MapIndex(key)
45                         if !srcElement.IsValid() {
46                                 continue
47                         }
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() {
52                                         continue
53                                 }
54                                 fallthrough
55                         default:
56                                 switch reflect.TypeOf(srcElement.Interface()).Kind() {
57                                 case reflect.Struct:
58                                         fallthrough
59                                 case reflect.Ptr:
60                                         fallthrough
61                                 case reflect.Map:
62                                         if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
63                                                 return
64                                         }
65                                 }
66                         }
67                         if !isEmptyValue(srcElement) && (overwrite || (!dstElement.IsValid() || isEmptyValue(dst))) {
68                                 if dst.IsNil() {
69                                         dst.Set(reflect.MakeMap(dst.Type()))
70                                 }
71                                 dst.SetMapIndex(key, srcElement)
72                         }
73                 }
74         case reflect.Ptr:
75                 fallthrough
76         case reflect.Interface:
77                 if src.IsNil() {
78                         break
79                 } else if dst.IsNil() {
80                         if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
81                                 dst.Set(src)
82                         }
83                 } else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, overwrite); err != nil {
84                         return
85                 }
86         default:
87                 if dst.CanSet() && !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) {
88                         dst.Set(src)
89                 }
90         }
91         return
92 }
93
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)
102 }
103
104 func MergeWithOverwrite(dst, src interface{}) error {
105         return merge(dst, src, true)
106 }
107
108 func merge(dst, src interface{}, overwrite bool) error {
109         var (
110                 vDst, vSrc reflect.Value
111                 err        error
112         )
113         if vDst, vSrc, err = resolveValues(dst, src); err != nil {
114                 return err
115         }
116         if vDst.Type() != vSrc.Type() {
117                 return ErrDifferentArgumentsTypes
118         }
119         return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, overwrite)
120 }