You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mergo.go 2.8KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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. "errors"
  10. "reflect"
  11. )
  12. // Errors reported by Mergo when it finds invalid arguments.
  13. var (
  14. ErrNilArguments = errors.New("src and dst must not be nil")
  15. ErrDifferentArgumentsTypes = errors.New("src and dst must be of same type")
  16. ErrNotSupported = errors.New("only structs and maps are supported")
  17. ErrExpectedMapAsDestination = errors.New("dst was expected to be a map")
  18. ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct")
  19. )
  20. // During deepMerge, must keep track of checks that are
  21. // in progress. The comparison algorithm assumes that all
  22. // checks in progress are true when it reencounters them.
  23. // Visited are stored in a map indexed by 17 * a1 + a2;
  24. type visit struct {
  25. ptr uintptr
  26. typ reflect.Type
  27. next *visit
  28. }
  29. // From src/pkg/encoding/json/encode.go.
  30. func isEmptyValue(v reflect.Value) bool {
  31. switch v.Kind() {
  32. case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
  33. return v.Len() == 0
  34. case reflect.Bool:
  35. return !v.Bool()
  36. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  37. return v.Int() == 0
  38. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  39. return v.Uint() == 0
  40. case reflect.Float32, reflect.Float64:
  41. return v.Float() == 0
  42. case reflect.Interface, reflect.Ptr:
  43. if v.IsNil() {
  44. return true
  45. }
  46. return isEmptyValue(v.Elem())
  47. case reflect.Func:
  48. return v.IsNil()
  49. case reflect.Invalid:
  50. return true
  51. }
  52. return false
  53. }
  54. func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) {
  55. if dst == nil || src == nil {
  56. err = ErrNilArguments
  57. return
  58. }
  59. vDst = reflect.ValueOf(dst).Elem()
  60. if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map {
  61. err = ErrNotSupported
  62. return
  63. }
  64. vSrc = reflect.ValueOf(src)
  65. // We check if vSrc is a pointer to dereference it.
  66. if vSrc.Kind() == reflect.Ptr {
  67. vSrc = vSrc.Elem()
  68. }
  69. return
  70. }
  71. // Traverses recursively both values, assigning src's fields values to dst.
  72. // The map argument tracks comparisons that have already been seen, which allows
  73. // short circuiting on recursive types.
  74. func deeper(dst, src reflect.Value, visited map[uintptr]*visit, depth int) (err error) {
  75. if dst.CanAddr() {
  76. addr := dst.UnsafeAddr()
  77. h := 17 * addr
  78. seen := visited[h]
  79. typ := dst.Type()
  80. for p := seen; p != nil; p = p.next {
  81. if p.ptr == addr && p.typ == typ {
  82. return nil
  83. }
  84. }
  85. // Remember, remember...
  86. visited[h] = &visit{addr, typ, seen}
  87. }
  88. return // TODO refactor
  89. }