main
Raw Download raw file
  1// Copyright 2014 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	"unicode"
 15	"unicode/utf8"
 16)
 17
 18func changeInitialCase(s string, mapper func(rune) rune) string {
 19	if s == "" {
 20		return s
 21	}
 22	r, n := utf8.DecodeRuneInString(s)
 23	return string(mapper(r)) + s[n:]
 24}
 25
 26func isExported(field reflect.StructField) bool {
 27	r, _ := utf8.DecodeRuneInString(field.Name)
 28	return r >= 'A' && r <= 'Z'
 29}
 30
 31// Traverses recursively both values, assigning src's fields values to dst.
 32// The map argument tracks comparisons that have already been seen, which allows
 33// short circuiting on recursive types.
 34func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
 35	overwrite := config.Overwrite
 36	if dst.CanAddr() {
 37		addr := dst.UnsafeAddr()
 38		h := 17 * addr
 39		seen := visited[h]
 40		typ := dst.Type()
 41		for p := seen; p != nil; p = p.next {
 42			if p.ptr == addr && p.typ == typ {
 43				return nil
 44			}
 45		}
 46		// Remember, remember...
 47		visited[h] = &visit{typ, seen, addr}
 48	}
 49	zeroValue := reflect.Value{}
 50	switch dst.Kind() {
 51	case reflect.Map:
 52		dstMap := dst.Interface().(map[string]interface{})
 53		for i, n := 0, src.NumField(); i < n; i++ {
 54			srcType := src.Type()
 55			field := srcType.Field(i)
 56			if !isExported(field) {
 57				continue
 58			}
 59			fieldName := field.Name
 60			fieldName = changeInitialCase(fieldName, unicode.ToLower)
 61			if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v), !config.ShouldNotDereference) || overwrite) {
 62				dstMap[fieldName] = src.Field(i).Interface()
 63			}
 64		}
 65	case reflect.Ptr:
 66		if dst.IsNil() {
 67			v := reflect.New(dst.Type().Elem())
 68			dst.Set(v)
 69		}
 70		dst = dst.Elem()
 71		fallthrough
 72	case reflect.Struct:
 73		srcMap := src.Interface().(map[string]interface{})
 74		for key := range srcMap {
 75			config.overwriteWithEmptyValue = true
 76			srcValue := srcMap[key]
 77			fieldName := changeInitialCase(key, unicode.ToUpper)
 78			dstElement := dst.FieldByName(fieldName)
 79			if dstElement == zeroValue {
 80				// We discard it because the field doesn't exist.
 81				continue
 82			}
 83			srcElement := reflect.ValueOf(srcValue)
 84			dstKind := dstElement.Kind()
 85			srcKind := srcElement.Kind()
 86			if srcKind == reflect.Ptr && dstKind != reflect.Ptr {
 87				srcElement = srcElement.Elem()
 88				srcKind = reflect.TypeOf(srcElement.Interface()).Kind()
 89			} else if dstKind == reflect.Ptr {
 90				// Can this work? I guess it can't.
 91				if srcKind != reflect.Ptr && srcElement.CanAddr() {
 92					srcPtr := srcElement.Addr()
 93					srcElement = reflect.ValueOf(srcPtr)
 94					srcKind = reflect.Ptr
 95				}
 96			}
 97
 98			if !srcElement.IsValid() {
 99				continue
100			}
101			if srcKind == dstKind {
102				if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
103					return
104				}
105			} else if dstKind == reflect.Interface && dstElement.Kind() == reflect.Interface {
106				if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
107					return
108				}
109			} else if srcKind == reflect.Map {
110				if err = deepMap(dstElement, srcElement, visited, depth+1, config); err != nil {
111					return
112				}
113			} else {
114				return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind)
115			}
116		}
117	}
118	return
119}
120
121// Map sets fields' values in dst from src.
122// src can be a map with string keys or a struct. dst must be the opposite:
123// if src is a map, dst must be a valid pointer to struct. If src is a struct,
124// dst must be map[string]interface{}.
125// It won't merge unexported (private) fields and will do recursively
126// any exported field.
127// If dst is a map, keys will be src fields' names in lower camel case.
128// Missing key in src that doesn't match a field in dst will be skipped. This
129// doesn't apply if dst is a map.
130// This is separated method from Merge because it is cleaner and it keeps sane
131// semantics: merging equal types, mapping different (restricted) types.
132func Map(dst, src interface{}, opts ...func(*Config)) error {
133	return _map(dst, src, opts...)
134}
135
136// MapWithOverwrite will do the same as Map except that non-empty dst attributes will be overridden by
137// non-empty src attribute values.
138// Deprecated: Use Map(…) with WithOverride
139func MapWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
140	return _map(dst, src, append(opts, WithOverride)...)
141}
142
143func _map(dst, src interface{}, opts ...func(*Config)) error {
144	if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
145		return ErrNonPointerArgument
146	}
147	var (
148		vDst, vSrc reflect.Value
149		err        error
150	)
151	config := &Config{}
152
153	for _, opt := range opts {
154		opt(config)
155	}
156
157	if vDst, vSrc, err = resolveValues(dst, src); err != nil {
158		return err
159	}
160	// To be friction-less, we redirect equal-type arguments
161	// to deepMerge. Only because arguments can be anything.
162	if vSrc.Kind() == vDst.Kind() {
163		return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
164	}
165	switch vSrc.Kind() {
166	case reflect.Struct:
167		if vDst.Kind() != reflect.Map {
168			return ErrExpectedMapAsDestination
169		}
170	case reflect.Map:
171		if vDst.Kind() != reflect.Struct {
172			return ErrExpectedStructAsDestination
173		}
174	default:
175		return ErrNotSupported
176	}
177	return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, config)
178}