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