123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- // Copyright 2013 Dario Castañé. All rights reserved.
- // Copyright 2009 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
-
- // Based on src/pkg/reflect/deepequal.go from official
- // golang's stdlib.
-
- package mergo
-
- import (
- "fmt"
- "reflect"
- "unsafe"
- )
-
- func hasExportedField(dst reflect.Value) (exported bool) {
- for i, n := 0, dst.NumField(); i < n; i++ {
- field := dst.Type().Field(i)
- if isExportedComponent(&field) {
- return true
- }
- }
- return
- }
-
- func isExportedComponent(field *reflect.StructField) bool {
- name := field.Name
- pkgPath := field.PkgPath
- if len(pkgPath) > 0 {
- return false
- }
- c := name[0]
- if 'a' <= c && c <= 'z' || c == '_' {
- return false
- }
- return true
- }
-
- type Config struct {
- Overwrite bool
- AppendSlice bool
- TypeCheck bool
- Transformers Transformers
- overwriteWithEmptyValue bool
- overwriteSliceWithEmptyValue bool
- }
-
- type Transformers interface {
- Transformer(reflect.Type) func(dst, src reflect.Value) error
- }
-
- // Traverses recursively both values, assigning src's fields values to dst.
- // The map argument tracks comparisons that have already been seen, which allows
- // short circuiting on recursive types.
- func deepMerge(dstIn, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (dst reflect.Value, err error) {
- dst = dstIn
- overwrite := config.Overwrite
- typeCheck := config.TypeCheck
- overwriteWithEmptySrc := config.overwriteWithEmptyValue
- overwriteSliceWithEmptySrc := config.overwriteSliceWithEmptyValue
-
- if !src.IsValid() {
- return
- }
-
- if dst.CanAddr() {
- addr := dst.UnsafeAddr()
- h := 17 * addr
- seen := visited[h]
- typ := dst.Type()
- for p := seen; p != nil; p = p.next {
- if p.ptr == addr && p.typ == typ {
- return dst, nil
- }
- }
- // Remember, remember...
- visited[h] = &visit{addr, typ, seen}
- }
-
- if config.Transformers != nil && !isEmptyValue(dst) {
- if fn := config.Transformers.Transformer(dst.Type()); fn != nil {
- err = fn(dst, src)
- return
- }
- }
-
- if dst.IsValid() && src.IsValid() && src.Type() != dst.Type() {
- err = fmt.Errorf("cannot append two different types (%s, %s)", src.Kind(), dst.Kind())
- return
- }
-
- switch dst.Kind() {
- case reflect.Struct:
- if hasExportedField(dst) {
- dstCp := reflect.New(dst.Type()).Elem()
- for i, n := 0, dst.NumField(); i < n; i++ {
- dstField := dst.Field(i)
- structField := dst.Type().Field(i)
- // copy un-exported struct fields
- if !isExportedComponent(&structField) {
- rf := dstCp.Field(i)
- rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem() //nolint:gosec
- dstRF := dst.Field(i)
- if !dst.Field(i).CanAddr() {
- continue
- }
-
- dstRF = reflect.NewAt(dstRF.Type(), unsafe.Pointer(dstRF.UnsafeAddr())).Elem() //nolint:gosec
- rf.Set(dstRF)
- continue
- }
- dstField, err = deepMerge(dstField, src.Field(i), visited, depth+1, config)
- if err != nil {
- return
- }
- dstCp.Field(i).Set(dstField)
- }
-
- if dst.CanSet() {
- dst.Set(dstCp)
- } else {
- dst = dstCp
- }
- return
- } else {
- if (isReflectNil(dst) || overwrite) && (!isEmptyValue(src) || overwriteWithEmptySrc) {
- dst = src
- }
- }
-
- case reflect.Map:
- if dst.IsNil() && !src.IsNil() {
- if dst.CanSet() {
- dst.Set(reflect.MakeMap(dst.Type()))
- } else {
- dst = src
- return
- }
- }
- for _, key := range src.MapKeys() {
- srcElement := src.MapIndex(key)
- dstElement := dst.MapIndex(key)
- if !srcElement.IsValid() {
- continue
- }
- if dst.MapIndex(key).IsValid() {
- k := dstElement.Interface()
- dstElement = reflect.ValueOf(k)
- }
- if isReflectNil(srcElement) {
- if overwrite || isReflectNil(dstElement) {
- dst.SetMapIndex(key, srcElement)
- }
- continue
- }
- if !srcElement.CanInterface() {
- continue
- }
-
- if srcElement.CanInterface() {
- srcElement = reflect.ValueOf(srcElement.Interface())
- if dstElement.IsValid() {
- dstElement = reflect.ValueOf(dstElement.Interface())
- }
- }
- dstElement, err = deepMerge(dstElement, srcElement, visited, depth+1, config)
- if err != nil {
- return
- }
- dst.SetMapIndex(key, dstElement)
-
- }
- case reflect.Slice:
- newSlice := dst
- if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
- if typeCheck && src.Type() != dst.Type() {
- return dst, fmt.Errorf("cannot override two slices with different type (%s, %s)", src.Type(), dst.Type())
- }
- newSlice = src
- } else if config.AppendSlice {
- if typeCheck && src.Type() != dst.Type() {
- err = fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
- return
- }
- newSlice = reflect.AppendSlice(dst, src)
- }
- if dst.CanSet() {
- dst.Set(newSlice)
- } else {
- dst = newSlice
- }
- case reflect.Ptr, reflect.Interface:
- if isReflectNil(src) {
- break
- }
-
- if dst.Kind() != reflect.Ptr && src.Type().AssignableTo(dst.Type()) {
- if dst.IsNil() || overwrite {
- if overwrite || isEmptyValue(dst) {
- if dst.CanSet() {
- dst.Set(src)
- } else {
- dst = src
- }
- }
- }
- break
- }
-
- if src.Kind() != reflect.Interface {
- if dst.IsNil() || (src.Kind() != reflect.Ptr && overwrite) {
- if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
- dst.Set(src)
- }
- } else if src.Kind() == reflect.Ptr {
- if dst, err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
- return
- }
- dst = dst.Addr()
- } else if dst.Elem().Type() == src.Type() {
- if dst, err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
- return
- }
- } else {
- return dst, ErrDifferentArgumentsTypes
- }
- break
- }
- if dst.IsNil() || overwrite {
- if (overwrite || isEmptyValue(dst)) && (overwriteWithEmptySrc || !isEmptyValue(src)) {
- if dst.CanSet() {
- dst.Set(src)
- } else {
- dst = src
- }
- }
- } else if _, err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
- return
- }
- default:
- overwriteFull := (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst))
- if overwriteFull {
- if dst.CanSet() {
- dst.Set(src)
- } else {
- dst = src
- }
- }
- }
-
- return
- }
-
- // Merge will fill any empty for value type attributes on the dst struct using corresponding
- // src attributes if they themselves are not empty. dst and src must be valid same-type structs
- // and dst must be a pointer to struct.
- // It won't merge unexported (private) fields and will do recursively any exported field.
- func Merge(dst, src interface{}, opts ...func(*Config)) error {
- return merge(dst, src, opts...)
- }
-
- // MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overridden by
- // non-empty src attribute values.
- // Deprecated: use Merge(…) with WithOverride
- func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
- return merge(dst, src, append(opts, WithOverride)...)
- }
-
- // WithTransformers adds transformers to merge, allowing to customize the merging of some types.
- func WithTransformers(transformers Transformers) func(*Config) {
- return func(config *Config) {
- config.Transformers = transformers
- }
- }
-
- // WithOverride will make merge override non-empty dst attributes with non-empty src attributes values.
- func WithOverride(config *Config) {
- config.Overwrite = true
- }
-
- // WithOverwriteWithEmptyValue will make merge override non empty dst attributes with empty src attributes values.
- func WithOverwriteWithEmptyValue(config *Config) {
- config.overwriteWithEmptyValue = true
- }
-
- // WithOverrideEmptySlice will make merge override empty dst slice with empty src slice.
- func WithOverrideEmptySlice(config *Config) {
- config.overwriteSliceWithEmptyValue = true
- }
-
- // WithAppendSlice will make merge append slices instead of overwriting it.
- func WithAppendSlice(config *Config) {
- config.AppendSlice = true
- }
-
- // WithTypeCheck will make merge check types while overwriting it (must be used with WithOverride).
- func WithTypeCheck(config *Config) {
- config.TypeCheck = true
- }
-
- func merge(dst, src interface{}, opts ...func(*Config)) error {
- var (
- vDst, vSrc reflect.Value
- err error
- )
-
- config := &Config{}
-
- for _, opt := range opts {
- opt(config)
- }
-
- if vDst, vSrc, err = resolveValues(dst, src); err != nil {
- return err
- }
- if !vDst.CanSet() {
- return fmt.Errorf("cannot set dst, needs reference")
- }
- if vDst.Type() != vSrc.Type() {
- return ErrDifferentArgumentsTypes
- }
- _, err = deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
- return err
- }
-
- // IsReflectNil is the reflect value provided nil
- func isReflectNil(v reflect.Value) bool {
- k := v.Kind()
- switch k {
- case reflect.Interface, reflect.Slice, reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr:
- // Both interface and slice are nil if first word is 0.
- // Both are always bigger than a word; assume flagIndir.
- return v.IsNil()
- default:
- return false
- }
- }
|