2
0

merge.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // Copyright 2013 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. // Based on src/pkg/reflect/deepequal.go from official
  6. // golang's stdlib.
  7. package mergo
  8. import (
  9. "fmt"
  10. "reflect"
  11. )
  12. func hasExportedField(dst reflect.Value) (exported bool) {
  13. for i, n := 0, dst.NumField(); i < n; i++ {
  14. field := dst.Type().Field(i)
  15. if field.Anonymous && dst.Field(i).Kind() == reflect.Struct {
  16. exported = exported || hasExportedField(dst.Field(i))
  17. } else {
  18. exported = exported || len(field.PkgPath) == 0
  19. }
  20. }
  21. return
  22. }
  23. type Config struct {
  24. Overwrite bool
  25. AppendSlice bool
  26. Transformers Transformers
  27. }
  28. type Transformers interface {
  29. Transformer(reflect.Type) func(dst, src reflect.Value) error
  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 deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
  35. overwrite := config.Overwrite
  36. if !src.IsValid() {
  37. return
  38. }
  39. if dst.CanAddr() {
  40. addr := dst.UnsafeAddr()
  41. h := 17 * addr
  42. seen := visited[h]
  43. typ := dst.Type()
  44. for p := seen; p != nil; p = p.next {
  45. if p.ptr == addr && p.typ == typ {
  46. return nil
  47. }
  48. }
  49. // Remember, remember...
  50. visited[h] = &visit{addr, typ, seen}
  51. }
  52. if config.Transformers != nil && !isEmptyValue(dst) {
  53. if fn := config.Transformers.Transformer(dst.Type()); fn != nil {
  54. err = fn(dst, src)
  55. return
  56. }
  57. }
  58. switch dst.Kind() {
  59. case reflect.Struct:
  60. if hasExportedField(dst) {
  61. for i, n := 0, dst.NumField(); i < n; i++ {
  62. if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil {
  63. return
  64. }
  65. }
  66. } else {
  67. if dst.CanSet() && !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) {
  68. dst.Set(src)
  69. }
  70. }
  71. case reflect.Map:
  72. if dst.IsNil() && !src.IsNil() {
  73. dst.Set(reflect.MakeMap(dst.Type()))
  74. }
  75. for _, key := range src.MapKeys() {
  76. srcElement := src.MapIndex(key)
  77. if !srcElement.IsValid() {
  78. continue
  79. }
  80. dstElement := dst.MapIndex(key)
  81. switch srcElement.Kind() {
  82. case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice:
  83. if srcElement.IsNil() {
  84. continue
  85. }
  86. fallthrough
  87. default:
  88. if !srcElement.CanInterface() {
  89. continue
  90. }
  91. switch reflect.TypeOf(srcElement.Interface()).Kind() {
  92. case reflect.Struct:
  93. fallthrough
  94. case reflect.Ptr:
  95. fallthrough
  96. case reflect.Map:
  97. srcMapElm := srcElement
  98. dstMapElm := dstElement
  99. if srcMapElm.CanInterface() {
  100. srcMapElm = reflect.ValueOf(srcMapElm.Interface())
  101. if dstMapElm.IsValid() {
  102. dstMapElm = reflect.ValueOf(dstMapElm.Interface())
  103. }
  104. }
  105. if err = deepMerge(dstMapElm, srcMapElm, visited, depth+1, config); err != nil {
  106. return
  107. }
  108. case reflect.Slice:
  109. srcSlice := reflect.ValueOf(srcElement.Interface())
  110. var dstSlice reflect.Value
  111. if !dstElement.IsValid() || dstElement.IsNil() {
  112. dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len())
  113. } else {
  114. dstSlice = reflect.ValueOf(dstElement.Interface())
  115. }
  116. if !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
  117. dstSlice = srcSlice
  118. } else if config.AppendSlice {
  119. if srcSlice.Type() != dstSlice.Type() {
  120. return fmt.Errorf("cannot append two slice with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
  121. }
  122. dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
  123. }
  124. dst.SetMapIndex(key, dstSlice)
  125. }
  126. }
  127. if dstElement.IsValid() && reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map {
  128. continue
  129. }
  130. if srcElement.IsValid() && (overwrite || (!dstElement.IsValid() || isEmptyValue(dstElement))) {
  131. if dst.IsNil() {
  132. dst.Set(reflect.MakeMap(dst.Type()))
  133. }
  134. dst.SetMapIndex(key, srcElement)
  135. }
  136. }
  137. case reflect.Slice:
  138. if !dst.CanSet() {
  139. break
  140. }
  141. if !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
  142. dst.Set(src)
  143. } else if config.AppendSlice {
  144. if src.Type() != dst.Type() {
  145. return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
  146. }
  147. dst.Set(reflect.AppendSlice(dst, src))
  148. }
  149. case reflect.Ptr:
  150. fallthrough
  151. case reflect.Interface:
  152. if src.IsNil() {
  153. break
  154. }
  155. if src.Kind() != reflect.Interface {
  156. if dst.IsNil() || overwrite {
  157. if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
  158. dst.Set(src)
  159. }
  160. } else if src.Kind() == reflect.Ptr {
  161. if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
  162. return
  163. }
  164. } else if dst.Elem().Type() == src.Type() {
  165. if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
  166. return
  167. }
  168. } else {
  169. return ErrDifferentArgumentsTypes
  170. }
  171. break
  172. }
  173. if dst.IsNil() || overwrite {
  174. if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
  175. dst.Set(src)
  176. }
  177. } else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
  178. return
  179. }
  180. default:
  181. if dst.CanSet() && !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) {
  182. dst.Set(src)
  183. }
  184. }
  185. return
  186. }
  187. // Merge will fill any empty for value type attributes on the dst struct using corresponding
  188. // src attributes if they themselves are not empty. dst and src must be valid same-type structs
  189. // and dst must be a pointer to struct.
  190. // It won't merge unexported (private) fields and will do recursively any exported field.
  191. func Merge(dst, src interface{}, opts ...func(*Config)) error {
  192. return merge(dst, src, opts...)
  193. }
  194. // MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overriden by
  195. // non-empty src attribute values.
  196. // Deprecated: use Merge(…) with WithOverride
  197. func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
  198. return merge(dst, src, append(opts, WithOverride)...)
  199. }
  200. // WithTransformers adds transformers to merge, allowing to customize the merging of some types.
  201. func WithTransformers(transformers Transformers) func(*Config) {
  202. return func(config *Config) {
  203. config.Transformers = transformers
  204. }
  205. }
  206. // WithOverride will make merge override non-empty dst attributes with non-empty src attributes values.
  207. func WithOverride(config *Config) {
  208. config.Overwrite = true
  209. }
  210. // WithAppendSlice will make merge append slices instead of overwriting it
  211. func WithAppendSlice(config *Config) {
  212. config.AppendSlice = true
  213. }
  214. func merge(dst, src interface{}, opts ...func(*Config)) error {
  215. var (
  216. vDst, vSrc reflect.Value
  217. err error
  218. )
  219. config := &Config{}
  220. for _, opt := range opts {
  221. opt(config)
  222. }
  223. if vDst, vSrc, err = resolveValues(dst, src); err != nil {
  224. return err
  225. }
  226. if vDst.Type() != vSrc.Type() {
  227. return ErrDifferentArgumentsTypes
  228. }
  229. return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
  230. }