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 hasMergeableFields(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 || hasMergeableFields(dst.Field(i)) 21 } else if isExportedComponent(&field) { 22 exported = exported || len(field.PkgPath) == 0 23 } 24 } 25 return 26} 27 28func isExportedComponent(field *reflect.StructField) bool { 29 pkgPath := field.PkgPath 30 if len(pkgPath) > 0 { 31 return false 32 } 33 c := field.Name[0] 34 if 'a' <= c && c <= 'z' || c == '_' { 35 return false 36 } 37 return true 38} 39 40type Config struct { 41 Overwrite bool 42 AppendSlice bool 43 TypeCheck bool 44 Transformers Transformers 45 overwriteWithEmptyValue bool 46 overwriteSliceWithEmptyValue bool 47 sliceDeepCopy bool 48 debug bool 49} 50 51type Transformers interface { 52 Transformer(reflect.Type) func(dst, src reflect.Value) error 53} 54 55// Traverses recursively both values, assigning src's fields values to dst. 56// The map argument tracks comparisons that have already been seen, which allows 57// short circuiting on recursive types. 58func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) { 59 overwrite := config.Overwrite 60 typeCheck := config.TypeCheck 61 overwriteWithEmptySrc := config.overwriteWithEmptyValue 62 overwriteSliceWithEmptySrc := config.overwriteSliceWithEmptyValue 63 sliceDeepCopy := config.sliceDeepCopy 64 65 if !src.IsValid() { 66 return 67 } 68 if dst.CanAddr() { 69 addr := dst.UnsafeAddr() 70 h := 17 * addr 71 seen := visited[h] 72 typ := dst.Type() 73 for p := seen; p != nil; p = p.next { 74 if p.ptr == addr && p.typ == typ { 75 return nil 76 } 77 } 78 // Remember, remember... 79 visited[h] = &visit{addr, typ, seen} 80 } 81 82 if config.Transformers != nil && !isEmptyValue(dst) { 83 if fn := config.Transformers.Transformer(dst.Type()); fn != nil { 84 err = fn(dst, src) 85 return 86 } 87 } 88 89 switch dst.Kind() { 90 case reflect.Struct: 91 if hasMergeableFields(dst) { 92 for i, n := 0, dst.NumField(); i < n; i++ { 93 if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil { 94 return 95 } 96 } 97 } else { 98 if (isReflectNil(dst) || overwrite) && (!isEmptyValue(src) || overwriteWithEmptySrc) { 99 dst.Set(src) 100 } 101 } 102 case reflect.Map: 103 if dst.IsNil() && !src.IsNil() { 104 dst.Set(reflect.MakeMap(dst.Type())) 105 } 106 107 if src.Kind() != reflect.Map { 108 if overwrite { 109 dst.Set(src) 110 } 111 return 112 } 113 114 for _, key := range src.MapKeys() { 115 srcElement := src.MapIndex(key) 116 if !srcElement.IsValid() { 117 continue 118 } 119 dstElement := dst.MapIndex(key) 120 switch srcElement.Kind() { 121 case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice: 122 if srcElement.IsNil() { 123 if overwrite { 124 dst.SetMapIndex(key, srcElement) 125 } 126 continue 127 } 128 fallthrough 129 default: 130 if !srcElement.CanInterface() { 131 continue 132 } 133 switch reflect.TypeOf(srcElement.Interface()).Kind() { 134 case reflect.Struct: 135 fallthrough 136 case reflect.Ptr: 137 fallthrough 138 case reflect.Map: 139 srcMapElm := srcElement 140 dstMapElm := dstElement 141 if srcMapElm.CanInterface() { 142 srcMapElm = reflect.ValueOf(srcMapElm.Interface()) 143 if dstMapElm.IsValid() { 144 dstMapElm = reflect.ValueOf(dstMapElm.Interface()) 145 } 146 } 147 if err = deepMerge(dstMapElm, srcMapElm, visited, depth+1, config); err != nil { 148 return 149 } 150 case reflect.Slice: 151 srcSlice := reflect.ValueOf(srcElement.Interface()) 152 153 var dstSlice reflect.Value 154 if !dstElement.IsValid() || dstElement.IsNil() { 155 dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len()) 156 } else { 157 dstSlice = reflect.ValueOf(dstElement.Interface()) 158 } 159 160 if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice && !sliceDeepCopy { 161 if typeCheck && srcSlice.Type() != dstSlice.Type() { 162 return fmt.Errorf("cannot override two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type()) 163 } 164 dstSlice = srcSlice 165 } else if config.AppendSlice { 166 if srcSlice.Type() != dstSlice.Type() { 167 return fmt.Errorf("cannot append two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type()) 168 } 169 dstSlice = reflect.AppendSlice(dstSlice, srcSlice) 170 } else if sliceDeepCopy { 171 i := 0 172 for ; i < srcSlice.Len() && i < dstSlice.Len(); i++ { 173 srcElement := srcSlice.Index(i) 174 dstElement := dstSlice.Index(i) 175 176 if srcElement.CanInterface() { 177 srcElement = reflect.ValueOf(srcElement.Interface()) 178 } 179 if dstElement.CanInterface() { 180 dstElement = reflect.ValueOf(dstElement.Interface()) 181 } 182 183 if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil { 184 return 185 } 186 } 187 188 } 189 dst.SetMapIndex(key, dstSlice) 190 } 191 } 192 if dstElement.IsValid() && !isEmptyValue(dstElement) && (reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map || reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Slice) { 193 continue 194 } 195 196 if srcElement.IsValid() && ((srcElement.Kind() != reflect.Ptr && overwrite) || !dstElement.IsValid() || isEmptyValue(dstElement)) { 197 if dst.IsNil() { 198 dst.Set(reflect.MakeMap(dst.Type())) 199 } 200 dst.SetMapIndex(key, srcElement) 201 } 202 } 203 case reflect.Slice: 204 if !dst.CanSet() { 205 break 206 } 207 if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice && !sliceDeepCopy { 208 dst.Set(src) 209 } else if config.AppendSlice { 210 if src.Type() != dst.Type() { 211 return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type()) 212 } 213 dst.Set(reflect.AppendSlice(dst, src)) 214 } else if sliceDeepCopy { 215 for i := 0; i < src.Len() && i < dst.Len(); i++ { 216 srcElement := src.Index(i) 217 dstElement := dst.Index(i) 218 if srcElement.CanInterface() { 219 srcElement = reflect.ValueOf(srcElement.Interface()) 220 } 221 if dstElement.CanInterface() { 222 dstElement = reflect.ValueOf(dstElement.Interface()) 223 } 224 225 if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil { 226 return 227 } 228 } 229 } 230 case reflect.Ptr: 231 fallthrough 232 case reflect.Interface: 233 if isReflectNil(src) { 234 if overwriteWithEmptySrc && dst.CanSet() && src.Type().AssignableTo(dst.Type()) { 235 dst.Set(src) 236 } 237 break 238 } 239 240 if src.Kind() != reflect.Interface { 241 if dst.IsNil() || (src.Kind() != reflect.Ptr && overwrite) { 242 if dst.CanSet() && (overwrite || isEmptyValue(dst)) { 243 dst.Set(src) 244 } 245 } else if src.Kind() == reflect.Ptr { 246 if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil { 247 return 248 } 249 } else if dst.Elem().Type() == src.Type() { 250 if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil { 251 return 252 } 253 } else { 254 return ErrDifferentArgumentsTypes 255 } 256 break 257 } 258 259 if dst.IsNil() || overwrite { 260 if dst.CanSet() && (overwrite || isEmptyValue(dst)) { 261 dst.Set(src) 262 } 263 break 264 } 265 266 if dst.Elem().Kind() == src.Elem().Kind() { 267 if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil { 268 return 269 } 270 break 271 } 272 default: 273 mustSet := (isEmptyValue(dst) || overwrite) && (!isEmptyValue(src) || overwriteWithEmptySrc) 274 if mustSet { 275 if dst.CanSet() { 276 dst.Set(src) 277 } else { 278 dst = src 279 } 280 } 281 } 282 283 return 284} 285 286// Merge will fill any empty for value type attributes on the dst struct using corresponding 287// src attributes if they themselves are not empty. dst and src must be valid same-type structs 288// and dst must be a pointer to struct. 289// It won't merge unexported (private) fields and will do recursively any exported field. 290func Merge(dst, src interface{}, opts ...func(*Config)) error { 291 return merge(dst, src, opts...) 292} 293 294// MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overridden by 295// non-empty src attribute values. 296// Deprecated: use Merge(…) with WithOverride 297func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error { 298 return merge(dst, src, append(opts, WithOverride)...) 299} 300 301// WithTransformers adds transformers to merge, allowing to customize the merging of some types. 302func WithTransformers(transformers Transformers) func(*Config) { 303 return func(config *Config) { 304 config.Transformers = transformers 305 } 306} 307 308// WithOverride will make merge override non-empty dst attributes with non-empty src attributes values. 309func WithOverride(config *Config) { 310 config.Overwrite = true 311} 312 313// WithOverwriteWithEmptyValue will make merge override non empty dst attributes with empty src attributes values. 314func WithOverwriteWithEmptyValue(config *Config) { 315 config.Overwrite = true 316 config.overwriteWithEmptyValue = true 317} 318 319// WithOverrideEmptySlice will make merge override empty dst slice with empty src slice. 320func WithOverrideEmptySlice(config *Config) { 321 config.overwriteSliceWithEmptyValue = true 322} 323 324// WithAppendSlice will make merge append slices instead of overwriting it. 325func WithAppendSlice(config *Config) { 326 config.AppendSlice = true 327} 328 329// WithTypeCheck will make merge check types while overwriting it (must be used with WithOverride). 330func WithTypeCheck(config *Config) { 331 config.TypeCheck = true 332} 333 334// WithSliceDeepCopy will merge slice element one by one with Overwrite flag. 335func WithSliceDeepCopy(config *Config) { 336 config.sliceDeepCopy = true 337 config.Overwrite = true 338} 339 340func merge(dst, src interface{}, opts ...func(*Config)) error { 341 if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr { 342 return ErrNonPointerAgument 343 } 344 var ( 345 vDst, vSrc reflect.Value 346 err error 347 ) 348 349 config := &Config{} 350 351 for _, opt := range opts { 352 opt(config) 353 } 354 355 if vDst, vSrc, err = resolveValues(dst, src); err != nil { 356 return err 357 } 358 if vDst.Type() != vSrc.Type() { 359 return ErrDifferentArgumentsTypes 360 } 361 return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config) 362} 363 364// IsReflectNil is the reflect value provided nil 365func isReflectNil(v reflect.Value) bool { 366 k := v.Kind() 367 switch k { 368 case reflect.Interface, reflect.Slice, reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr: 369 // Both interface and slice are nil if first word is 0. 370 // Both are always bigger than a word; assume flagIndir. 371 return v.IsNil() 372 default: 373 return false 374 } 375} 376