...

Source file src/github.com/imdario/mergo/merge.go

Documentation: github.com/imdario/mergo

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

View as plain text