mergo.go 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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.
  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. return v.IsNil()
  44. }
  45. return false
  46. }
  47. func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) {
  48. if dst == nil || src == nil {
  49. err = ErrNilArguments
  50. return
  51. }
  52. vDst = reflect.ValueOf(dst).Elem()
  53. if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map {
  54. err = ErrNotSupported
  55. return
  56. }
  57. vSrc = reflect.ValueOf(src)
  58. // We check if vSrc is a pointer to dereference it.
  59. if vSrc.Kind() == reflect.Ptr {
  60. vSrc = vSrc.Elem()
  61. }
  62. return
  63. }
  64. // Traverses recursively both values, assigning src's fields values to dst.
  65. // The map argument tracks comparisons that have already been seen, which allows
  66. // short circuiting on recursive types.
  67. func deeper(dst, src reflect.Value, visited map[uintptr]*visit, depth int) (err error) {
  68. if dst.CanAddr() {
  69. addr := dst.UnsafeAddr()
  70. h := 17 * addr
  71. seen := visited[h]
  72. typ := dst.Type()
  73. for p := seen; p != nil; p = p.next {
  74. if p.ptr == addr && p.typ == typ {
  75. return nil
  76. }
  77. }
  78. // Remember, remember...
  79. visited[h] = &visit{addr, typ, seen}
  80. }
  81. return // TODO refactor
  82. }