Tizen_4.0 base
[platform/upstream/docker-engine.git] / 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, overwrite bool) (err error) {
35         if dst.CanAddr() {
36                 addr := dst.UnsafeAddr()
37                 h := 17 * addr
38                 seen := visited[h]
39                 typ := dst.Type()
40                 for p := seen; p != nil; p = p.next {
41                         if p.ptr == addr && p.typ == typ {
42                                 return nil
43                         }
44                 }
45                 // Remember, remember...
46                 visited[h] = &visit{addr, typ, seen}
47         }
48         zeroValue := reflect.Value{}
49         switch dst.Kind() {
50         case reflect.Map:
51                 dstMap := dst.Interface().(map[string]interface{})
52                 for i, n := 0, src.NumField(); i < n; i++ {
53                         srcType := src.Type()
54                         field := srcType.Field(i)
55                         if !isExported(field) {
56                                 continue
57                         }
58                         fieldName := field.Name
59                         fieldName = changeInitialCase(fieldName, unicode.ToLower)
60                         if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v)) || overwrite) {
61                                 dstMap[fieldName] = src.Field(i).Interface()
62                         }
63                 }
64         case reflect.Struct:
65                 srcMap := src.Interface().(map[string]interface{})
66                 for key := range srcMap {
67                         srcValue := srcMap[key]
68                         fieldName := changeInitialCase(key, unicode.ToUpper)
69                         dstElement := dst.FieldByName(fieldName)
70                         if dstElement == zeroValue {
71                                 // We discard it because the field doesn't exist.
72                                 continue
73                         }
74                         srcElement := reflect.ValueOf(srcValue)
75                         dstKind := dstElement.Kind()
76                         srcKind := srcElement.Kind()
77                         if srcKind == reflect.Ptr && dstKind != reflect.Ptr {
78                                 srcElement = srcElement.Elem()
79                                 srcKind = reflect.TypeOf(srcElement.Interface()).Kind()
80                         } else if dstKind == reflect.Ptr {
81                                 // Can this work? I guess it can't.
82                                 if srcKind != reflect.Ptr && srcElement.CanAddr() {
83                                         srcPtr := srcElement.Addr()
84                                         srcElement = reflect.ValueOf(srcPtr)
85                                         srcKind = reflect.Ptr
86                                 }
87                         }
88                         if !srcElement.IsValid() {
89                                 continue
90                         }
91                         if srcKind == dstKind {
92                                 if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
93                                         return
94                                 }
95                         } else {
96                                 if srcKind == reflect.Map {
97                                         if err = deepMap(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
98                                                 return
99                                         }
100                                 } else {
101                                         return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind)
102                                 }
103                         }
104                 }
105         }
106         return
107 }
108
109 // Map sets fields' values in dst from src.
110 // src can be a map with string keys or a struct. dst must be the opposite:
111 // if src is a map, dst must be a valid pointer to struct. If src is a struct,
112 // dst must be map[string]interface{}.
113 // It won't merge unexported (private) fields and will do recursively
114 // any exported field.
115 // If dst is a map, keys will be src fields' names in lower camel case.
116 // Missing key in src that doesn't match a field in dst will be skipped. This
117 // doesn't apply if dst is a map.
118 // This is separated method from Merge because it is cleaner and it keeps sane
119 // semantics: merging equal types, mapping different (restricted) types.
120 func Map(dst, src interface{}) error {
121         return _map(dst, src, false)
122 }
123
124 func MapWithOverwrite(dst, src interface{}) error {
125         return _map(dst, src, true)
126 }
127
128 func _map(dst, src interface{}, overwrite bool) error {
129         var (
130                 vDst, vSrc reflect.Value
131                 err        error
132         )
133         if vDst, vSrc, err = resolveValues(dst, src); err != nil {
134                 return err
135         }
136         // To be friction-less, we redirect equal-type arguments
137         // to deepMerge. Only because arguments can be anything.
138         if vSrc.Kind() == vDst.Kind() {
139                 return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, overwrite)
140         }
141         switch vSrc.Kind() {
142         case reflect.Struct:
143                 if vDst.Kind() != reflect.Map {
144                         return ErrExpectedMapAsDestination
145                 }
146         case reflect.Map:
147                 if vDst.Kind() != reflect.Struct {
148                         return ErrExpectedStructAsDestination
149                 }
150         default:
151                 return ErrNotSupported
152         }
153         return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, overwrite)
154 }