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