merge.go 6.6 KB

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