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.

serder.go 4.2 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package serder
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "reflect"
  7. "strings"
  8. myreflect "gitlink.org.cn/cloudream/common/utils/reflect"
  9. )
  10. func ObjectToJSON(obj any) ([]byte, error) {
  11. return json.Marshal(obj)
  12. }
  13. func ObjectToJSONStream(obj any) io.ReadCloser {
  14. pr, pw := io.Pipe()
  15. enc := json.NewEncoder(pw)
  16. go func() {
  17. err := enc.Encode(obj)
  18. if err != nil && err != io.EOF {
  19. pw.CloseWithError(err)
  20. } else {
  21. pw.Close()
  22. }
  23. }()
  24. return pr
  25. }
  26. func JSONToObject(data []byte, obj any) error {
  27. return json.Unmarshal(data, obj)
  28. }
  29. func JSONToObjectStream(str io.Reader, obj any) error {
  30. dec := json.NewDecoder(str)
  31. err := dec.Decode(obj)
  32. if err != io.EOF {
  33. return err
  34. }
  35. return nil
  36. }
  37. type TypeResolver interface {
  38. TypeToString(typ reflect.Type) (string, error)
  39. StringToType(typeStr string) (reflect.Type, error)
  40. }
  41. type UnionTypeInfo struct {
  42. UnionType reflect.Type
  43. TypeFieldName string
  44. ElementTypes TypeResolver
  45. }
  46. func NewTypeUnion[TU any](typeField string, eleTypes TypeResolver) UnionTypeInfo {
  47. return UnionTypeInfo{
  48. UnionType: myreflect.TypeOf[TU](),
  49. TypeFieldName: typeField,
  50. ElementTypes: eleTypes,
  51. }
  52. }
  53. type MapToObjectOption struct {
  54. UnionTypes []UnionTypeInfo // 转换过程中遇到这些类型时,会依据指定的字段的值,来决定转换后的实际类型
  55. }
  56. func MapToObject(m map[string]any, obj any, opt ...MapToObjectOption) error {
  57. var op MapToObjectOption
  58. if len(opt) > 0 {
  59. op = opt[0]
  60. }
  61. unionTypeMapping := make(map[reflect.Type]*UnionTypeInfo)
  62. for _, u := range op.UnionTypes {
  63. unionTypeMapping[u.UnionType] = &u
  64. }
  65. convs := []Converter{
  66. func(from reflect.Value, to reflect.Value) (interface{}, error) {
  67. info, ok := unionTypeMapping[to.Type()]
  68. if !ok {
  69. return from.Interface(), nil
  70. }
  71. mp := from.Interface().(map[string]any)
  72. tag, ok := mp[info.TypeFieldName]
  73. if !ok {
  74. return nil, fmt.Errorf("converting to %v: no tag field %s in map", to.Type(), info.TypeFieldName)
  75. }
  76. tagStr, ok := tag.(string)
  77. if !ok {
  78. return nil, fmt.Errorf("converting to %v: tag field %s value is %v, which is not a string", to.Type(), info.TypeFieldName, tag)
  79. }
  80. eleType, err := info.ElementTypes.StringToType(tagStr)
  81. if err != nil {
  82. return nil, fmt.Errorf("converting to %v: %w", to.Type(), err)
  83. }
  84. to.Set(reflect.Indirect(reflect.New(eleType)))
  85. return from.Interface(), nil
  86. },
  87. }
  88. return AnyToAny(m, obj, AnyToAnyOption{
  89. Converters: convs,
  90. })
  91. }
  92. func ObjectToMap(obj any) (map[string]any, error) {
  93. ctx := WalkValue(obj, func(ctx *WalkContext, event WalkEvent) WalkingOp {
  94. switch e := event.(type) {
  95. case StructBeginEvent:
  96. mp := make(map[string]any)
  97. ctx.StackPush(mp)
  98. case StructArriveFieldEvent:
  99. if !WillWalkInto(e.Value) {
  100. ctx.StackPush(e.Value.Interface())
  101. }
  102. case StructLeaveFieldEvent:
  103. val := ctx.StackPop()
  104. mp := ctx.StackPeek().(map[string]any)
  105. jsonTag := e.Info.Tag.Get("json")
  106. if jsonTag == "-" {
  107. break
  108. }
  109. opts := strings.Split(jsonTag, ",")
  110. keyName := opts[0]
  111. if keyName == "" {
  112. keyName = e.Info.Name
  113. }
  114. if contains(opts, "string", 1) {
  115. val = fmt.Sprintf("%v", val)
  116. }
  117. mp[keyName] = val
  118. case StructEndEvent:
  119. case MapBeginEvent:
  120. ctx.StackPush(make(map[string]any))
  121. case MapArriveEntryEvent:
  122. if !WillWalkInto(e.Value) {
  123. ctx.StackPush(e.Value.Interface())
  124. }
  125. case MapLeaveEntryEvent:
  126. val := ctx.StackPop()
  127. mp := ctx.StackPeek().(map[string]any)
  128. mp[fmt.Sprintf("%v", e.Key)] = val
  129. case MapEndEvent:
  130. case ArrayBeginEvent:
  131. ctx.StackPush(make([]any, e.Value.Len()))
  132. case ArrayArriveElementEvent:
  133. if !WillWalkInto(e.Value) {
  134. ctx.StackPush(e.Value.Interface())
  135. }
  136. case ArrayLeaveElementEvent:
  137. val := ctx.StackPop()
  138. arr := ctx.StackPeek().([]any)
  139. arr[e.Index] = val
  140. case ArrayEndEvent:
  141. }
  142. return Next
  143. }, WalkOption{
  144. StackValues: []any{make(map[string]any)},
  145. })
  146. return ctx.StackPop().(map[string]any), nil
  147. }
  148. func contains(arr []string, ele string, startIndex int) bool {
  149. for i := startIndex; i < len(arr); i++ {
  150. if arr[i] == ele {
  151. return true
  152. }
  153. }
  154. return false
  155. }