copy.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package awsutil
  2. import (
  3. "io"
  4. "reflect"
  5. )
  6. // Copy deeply copies a src structure to dst. Useful for copying request and
  7. // response structures.
  8. //
  9. // Can copy between structs of different type, but will only copy fields which
  10. // are assignable, and exist in both structs. Fields which are not assignable,
  11. // or do not exist in both structs are ignored.
  12. func Copy(dst, src interface{}) {
  13. dstval := reflect.ValueOf(dst)
  14. if !dstval.IsValid() {
  15. panic("Copy dst cannot be nil")
  16. }
  17. rcopy(dstval, reflect.ValueOf(src), true)
  18. }
  19. // CopyOf returns a copy of src while also allocating the memory for dst.
  20. // src must be a pointer type or this operation will fail.
  21. func CopyOf(src interface{}) (dst interface{}) {
  22. dsti := reflect.New(reflect.TypeOf(src).Elem())
  23. dst = dsti.Interface()
  24. rcopy(dsti, reflect.ValueOf(src), true)
  25. return
  26. }
  27. // rcopy performs a recursive copy of values from the source to destination.
  28. //
  29. // root is used to skip certain aspects of the copy which are not valid
  30. // for the root node of a object.
  31. func rcopy(dst, src reflect.Value, root bool) {
  32. if !src.IsValid() {
  33. return
  34. }
  35. switch src.Kind() {
  36. case reflect.Ptr:
  37. if _, ok := src.Interface().(io.Reader); ok {
  38. if dst.Kind() == reflect.Ptr && dst.Elem().CanSet() {
  39. dst.Elem().Set(src)
  40. } else if dst.CanSet() {
  41. dst.Set(src)
  42. }
  43. } else {
  44. e := src.Type().Elem()
  45. if dst.CanSet() && !src.IsNil() {
  46. dst.Set(reflect.New(e))
  47. }
  48. if src.Elem().IsValid() {
  49. // Keep the current root state since the depth hasn't changed
  50. rcopy(dst.Elem(), src.Elem(), root)
  51. }
  52. }
  53. case reflect.Struct:
  54. t := dst.Type()
  55. for i := 0; i < t.NumField(); i++ {
  56. name := t.Field(i).Name
  57. srcVal := src.FieldByName(name)
  58. dstVal := dst.FieldByName(name)
  59. if srcVal.IsValid() && dstVal.CanSet() {
  60. rcopy(dstVal, srcVal, false)
  61. }
  62. }
  63. case reflect.Slice:
  64. if src.IsNil() {
  65. break
  66. }
  67. s := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
  68. dst.Set(s)
  69. for i := 0; i < src.Len(); i++ {
  70. rcopy(dst.Index(i), src.Index(i), false)
  71. }
  72. case reflect.Map:
  73. if src.IsNil() {
  74. break
  75. }
  76. s := reflect.MakeMap(src.Type())
  77. dst.Set(s)
  78. for _, k := range src.MapKeys() {
  79. v := src.MapIndex(k)
  80. v2 := reflect.New(v.Type()).Elem()
  81. rcopy(v2, v, false)
  82. dst.SetMapIndex(k, v2)
  83. }
  84. default:
  85. // Assign the value if possible. If its not assignable, the value would
  86. // need to be converted and the impact of that may be unexpected, or is
  87. // not compatible with the dst type.
  88. if src.Type().AssignableTo(dst.Type()) {
  89. dst.Set(src)
  90. }
  91. }
  92. }