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{addr, typ, seen}
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)) || 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			srcValue := srcMap[key]
76			fieldName := changeInitialCase(key, unicode.ToUpper)
77			dstElement := dst.FieldByName(fieldName)
78			if dstElement == zeroValue {
79				// We discard it because the field doesn't exist.
80				continue
81			}
82			srcElement := reflect.ValueOf(srcValue)
83			dstKind := dstElement.Kind()
84			srcKind := srcElement.Kind()
85			if srcKind == reflect.Ptr && dstKind != reflect.Ptr {
86				srcElement = srcElement.Elem()
87				srcKind = reflect.TypeOf(srcElement.Interface()).Kind()
88			} else if dstKind == reflect.Ptr {
89				// Can this work? I guess it can't.
90				if srcKind != reflect.Ptr && srcElement.CanAddr() {
91					srcPtr := srcElement.Addr()
92					srcElement = reflect.ValueOf(srcPtr)
93					srcKind = reflect.Ptr
94				}
95			}
96
97			if !srcElement.IsValid() {
98				continue
99			}
100			if srcKind == dstKind {
101				if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
102					return
103				}
104			} else if dstKind == reflect.Interface && dstElement.Kind() == reflect.Interface {
105				if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
106					return
107				}
108			} else if srcKind == reflect.Map {
109				if err = deepMap(dstElement, srcElement, visited, depth+1, config); err != nil {
110					return
111				}
112			} else {
113				return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind)
114			}
115		}
116	}
117	return
118}
119
120// Map sets fields' values in dst from src.
121// src can be a map with string keys or a struct. dst must be the opposite:
122// if src is a map, dst must be a valid pointer to struct. If src is a struct,
123// dst must be map[string]interface{}.
124// It won't merge unexported (private) fields and will do recursively
125// any exported field.
126// If dst is a map, keys will be src fields' names in lower camel case.
127// Missing key in src that doesn't match a field in dst will be skipped. This
128// doesn't apply if dst is a map.
129// This is separated method from Merge because it is cleaner and it keeps sane
130// semantics: merging equal types, mapping different (restricted) types.
131func Map(dst, src interface{}, opts ...func(*config)) error {
132	return _map(dst, src, opts...)
133}
134
135// MapWithOverwrite will do the same as Map except that non-empty dst attributes will be overriden by
136// non-empty src attribute values.
137// Deprecated: Use Map(…) with WithOverride
138func MapWithOverwrite(dst, src interface{}, opts ...func(*config)) error {
139	return _map(dst, src, append(opts, WithOverride)...)
140}
141
142func _map(dst, src interface{}, opts ...func(*config)) error {
143	var (
144		vDst, vSrc reflect.Value
145		err        error
146	)
147	config := &config{}
148
149	for _, opt := range opts {
150		opt(config)
151	}
152
153	if vDst, vSrc, err = resolveValues(dst, src); err != nil {
154		return err
155	}
156	// To be friction-less, we redirect equal-type arguments
157	// to deepMerge. Only because arguments can be anything.
158	if vSrc.Kind() == vDst.Kind() {
159		return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
160	}
161	switch vSrc.Kind() {
162	case reflect.Struct:
163		if vDst.Kind() != reflect.Map {
164			return ErrExpectedMapAsDestination
165		}
166	case reflect.Map:
167		if vDst.Kind() != reflect.Struct {
168			return ErrExpectedStructAsDestination
169		}
170	default:
171		return ErrNotSupported
172	}
173	return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, config)
174}
175