Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / github.com / imdario / mergo / map.go
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
9 package mergo
10
11 import (
12         "fmt"
13         "reflect"
14         "unicode"
15         "unicode/utf8"
16 )
17
18 func 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
26 func 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.
34 func 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                         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.
132 func 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
139 func MapWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
140         return _map(dst, src, append(opts, WithOverride)...)
141 }
142
143 func _map(dst, src interface{}, opts ...func(*Config)) error {
144         var (
145                 vDst, vSrc reflect.Value
146                 err        error
147         )
148         config := &Config{}
149
150         for _, opt := range opts {
151                 opt(config)
152         }
153
154         if vDst, vSrc, err = resolveValues(dst, src); err != nil {
155                 return err
156         }
157         // To be friction-less, we redirect equal-type arguments
158         // to deepMerge. Only because arguments can be anything.
159         if vSrc.Kind() == vDst.Kind() {
160                 return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
161         }
162         switch vSrc.Kind() {
163         case reflect.Struct:
164                 if vDst.Kind() != reflect.Map {
165                         return ErrExpectedMapAsDestination
166                 }
167         case reflect.Map:
168                 if vDst.Kind() != reflect.Struct {
169                         return ErrExpectedStructAsDestination
170                 }
171         default:
172                 return ErrNotSupported
173         }
174         return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, config)
175 }