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

any_to_any.go 3.6 kB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package serder
  2. import (
  3. "reflect"
  4. mp "github.com/mitchellh/mapstructure"
  5. "gitlink.org.cn/cloudream/common/utils/reflect2"
  6. )
  7. type Converter func(from reflect.Value, to reflect.Value) (interface{}, error)
  8. type AnyToAnyOption struct {
  9. NoFromAny bool // 不判断目的字段是否实现了FromAny接口
  10. NoToAny bool // 不判断源字段是否实现了ToAny接口
  11. Converters []Converter // 字段类型转换函数
  12. // 当目的类型为map[string]any,是否要递归的将源类型的每一个字段都变成map[string]any。
  13. // 注:字段的类型(而不是实际值的类型)必须为结构体或者结构体指针。
  14. RecursiveStructToMap bool
  15. }
  16. type FromAny interface {
  17. FromAny(val any) (ok bool, err error)
  18. }
  19. type ToAny interface {
  20. ToAny(typ reflect.Type) (val any, ok bool, err error)
  21. }
  22. // AnyToAny 相同结构的任意类型对象之间的转换
  23. func AnyToAny(src any, dst any, opts ...AnyToAnyOption) error {
  24. var opt AnyToAnyOption
  25. if len(opts) > 0 {
  26. opt = opts[0]
  27. }
  28. var hooks []mp.DecodeHookFunc
  29. if !opt.NoToAny {
  30. hooks = append(hooks, toAny)
  31. }
  32. if !opt.NoFromAny {
  33. hooks = append(hooks, fromAny)
  34. }
  35. for _, c := range opt.Converters {
  36. hooks = append(hooks, c)
  37. }
  38. if opt.RecursiveStructToMap {
  39. hooks = append(hooks, mp.RecursiveStructToMapHookFunc())
  40. }
  41. config := &mp.DecoderConfig{
  42. TagName: "json",
  43. Squash: true,
  44. WeaklyTypedInput: true,
  45. Result: dst,
  46. DecodeHook: mp.ComposeDecodeHookFunc(hooks...),
  47. }
  48. decoder, err := mp.NewDecoder(config)
  49. if err != nil {
  50. return err
  51. }
  52. return decoder.Decode(src)
  53. }
  54. // fromAny 如果目的字段实现的FromAny接口,那么通过此接口实现字段类型转换
  55. func fromAny(srcType reflect.Type, targetType reflect.Type, data interface{}) (interface{}, error) {
  56. if reflect2.TypeOfValue(data) == targetType {
  57. return data, nil
  58. }
  59. if targetType.Implements(reflect2.TypeOf[FromAny]()) {
  60. // 非pointer receiver的FromAny没有意义,因为修改不了receiver的内容,所以这里只支持指针类型
  61. if targetType.Kind() == reflect.Pointer {
  62. val := reflect.New(targetType.Elem())
  63. anyIf := val.Interface().(FromAny)
  64. ok, err := anyIf.FromAny(data)
  65. if err != nil {
  66. return nil, err
  67. }
  68. if !ok {
  69. return data, nil
  70. }
  71. return val.Interface(), nil
  72. }
  73. } else if reflect.PointerTo(targetType).Implements(reflect2.TypeOf[FromAny]()) {
  74. val := reflect.New(targetType)
  75. anyIf := val.Interface().(FromAny)
  76. ok, err := anyIf.FromAny(data)
  77. if err != nil {
  78. return nil, err
  79. }
  80. if !ok {
  81. return data, nil
  82. }
  83. return val.Interface(), nil
  84. }
  85. return data, nil
  86. }
  87. // 如果源字段实现了ToAny接口,那么通过此接口实现字段类型转换
  88. func toAny(srcType reflect.Type, targetType reflect.Type, data interface{}) (interface{}, error) {
  89. dataType := reflect2.TypeOfValue(data)
  90. if dataType == targetType {
  91. return data, nil
  92. }
  93. if dataType.Implements(reflect2.TypeOf[ToAny]()) {
  94. anyIf := data.(ToAny)
  95. dstVal, ok, err := anyIf.ToAny(targetType)
  96. if err != nil {
  97. return nil, err
  98. }
  99. if !ok {
  100. return data, nil
  101. }
  102. return dstVal, nil
  103. } else if reflect.PointerTo(dataType).Implements(reflect2.TypeOf[ToAny]()) {
  104. dataVal := reflect.ValueOf(data)
  105. dataPtrVal := reflect.New(dataType)
  106. dataPtrVal.Elem().Set(dataVal)
  107. anyIf := dataPtrVal.Interface().(ToAny)
  108. dstVal, ok, err := anyIf.ToAny(targetType)
  109. if err != nil {
  110. return nil, err
  111. }
  112. if !ok {
  113. return data, nil
  114. }
  115. return dstVal, nil
  116. }
  117. return data, nil
  118. }