gconv_maptomap.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package gconv
  7. import (
  8. "github.com/gogf/gf/errors/gcode"
  9. "github.com/gogf/gf/errors/gerror"
  10. "github.com/gogf/gf/internal/json"
  11. "reflect"
  12. )
  13. // MapToMap converts any map type variable `params` to another map type variable `pointer`
  14. // using reflect.
  15. // See doMapToMap.
  16. func MapToMap(params interface{}, pointer interface{}, mapping ...map[string]string) error {
  17. return doMapToMap(params, pointer, mapping...)
  18. }
  19. // doMapToMap converts any map type variable `params` to another map type variable `pointer`.
  20. //
  21. // The parameter `params` can be any type of map, like:
  22. // map[string]string, map[string]struct, map[string]*struct, etc.
  23. //
  24. // The parameter `pointer` should be type of *map, like:
  25. // map[int]string, map[string]struct, map[string]*struct, etc.
  26. //
  27. // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes
  28. // sense only if the items of original map `params` is type struct.
  29. func doMapToMap(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
  30. // If given `params` is JSON, it then uses json.Unmarshal doing the converting.
  31. switch r := params.(type) {
  32. case []byte:
  33. if json.Valid(r) {
  34. if rv, ok := pointer.(reflect.Value); ok {
  35. if rv.Kind() == reflect.Ptr {
  36. return json.UnmarshalUseNumber(r, rv.Interface())
  37. }
  38. } else {
  39. return json.UnmarshalUseNumber(r, pointer)
  40. }
  41. }
  42. case string:
  43. if paramsBytes := []byte(r); json.Valid(paramsBytes) {
  44. if rv, ok := pointer.(reflect.Value); ok {
  45. if rv.Kind() == reflect.Ptr {
  46. return json.UnmarshalUseNumber(paramsBytes, rv.Interface())
  47. }
  48. } else {
  49. return json.UnmarshalUseNumber(paramsBytes, pointer)
  50. }
  51. }
  52. }
  53. var (
  54. paramsRv reflect.Value
  55. paramsKind reflect.Kind
  56. keyToAttributeNameMapping map[string]string
  57. )
  58. if len(mapping) > 0 {
  59. keyToAttributeNameMapping = mapping[0]
  60. }
  61. if v, ok := params.(reflect.Value); ok {
  62. paramsRv = v
  63. } else {
  64. paramsRv = reflect.ValueOf(params)
  65. }
  66. paramsKind = paramsRv.Kind()
  67. if paramsKind == reflect.Ptr {
  68. paramsRv = paramsRv.Elem()
  69. paramsKind = paramsRv.Kind()
  70. }
  71. if paramsKind != reflect.Map {
  72. return doMapToMap(Map(params), pointer, mapping...)
  73. }
  74. // Empty params map, no need continue.
  75. if paramsRv.Len() == 0 {
  76. return nil
  77. }
  78. var pointerRv reflect.Value
  79. if v, ok := pointer.(reflect.Value); ok {
  80. pointerRv = v
  81. } else {
  82. pointerRv = reflect.ValueOf(pointer)
  83. }
  84. pointerKind := pointerRv.Kind()
  85. for pointerKind == reflect.Ptr {
  86. pointerRv = pointerRv.Elem()
  87. pointerKind = pointerRv.Kind()
  88. }
  89. if pointerKind != reflect.Map {
  90. return gerror.NewCodef(gcode.CodeInvalidParameter, "pointer should be type of *map, but got:%s", pointerKind)
  91. }
  92. defer func() {
  93. // Catch the panic, especially the reflect operation panics.
  94. if exception := recover(); exception != nil {
  95. if e, ok := exception.(errorStack); ok {
  96. err = e
  97. } else {
  98. err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%v", exception)
  99. }
  100. }
  101. }()
  102. var (
  103. paramsKeys = paramsRv.MapKeys()
  104. pointerKeyType = pointerRv.Type().Key()
  105. pointerValueType = pointerRv.Type().Elem()
  106. pointerValueKind = pointerValueType.Kind()
  107. dataMap = reflect.MakeMapWithSize(pointerRv.Type(), len(paramsKeys))
  108. )
  109. // Retrieve the true element type of target map.
  110. if pointerValueKind == reflect.Ptr {
  111. pointerValueKind = pointerValueType.Elem().Kind()
  112. }
  113. for _, key := range paramsKeys {
  114. e := reflect.New(pointerValueType).Elem()
  115. switch pointerValueKind {
  116. case reflect.Map, reflect.Struct:
  117. if err = doStruct(paramsRv.MapIndex(key).Interface(), e, keyToAttributeNameMapping, ""); err != nil {
  118. return err
  119. }
  120. default:
  121. e.Set(
  122. reflect.ValueOf(
  123. Convert(
  124. paramsRv.MapIndex(key).Interface(),
  125. pointerValueType.String(),
  126. ),
  127. ),
  128. )
  129. }
  130. dataMap.SetMapIndex(
  131. reflect.ValueOf(
  132. Convert(
  133. key.Interface(),
  134. pointerKeyType.Name(),
  135. ),
  136. ),
  137. e,
  138. )
  139. }
  140. pointerRv.Set(dataMap)
  141. return nil
  142. }