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