resolver.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*
  2. * Copyright 2021 ByteDance Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package resolver
  17. import (
  18. `fmt`
  19. `reflect`
  20. `strings`
  21. `sync`
  22. )
  23. type FieldOpts int
  24. type OffsetType int
  25. const (
  26. F_omitempty FieldOpts = 1 << iota
  27. F_stringize
  28. )
  29. const (
  30. F_offset OffsetType = iota
  31. F_deref
  32. )
  33. type Offset struct {
  34. Size uintptr
  35. Kind OffsetType
  36. Type reflect.Type
  37. }
  38. type FieldMeta struct {
  39. Name string
  40. Path []Offset
  41. Opts FieldOpts
  42. Type reflect.Type
  43. }
  44. func (self *FieldMeta) String() string {
  45. var path []string
  46. var opts []string
  47. /* dump the field path */
  48. for _, off := range self.Path {
  49. if off.Kind == F_offset {
  50. path = append(path, fmt.Sprintf("%d", off.Size))
  51. } else {
  52. path = append(path, fmt.Sprintf("%d.(*%s)", off.Size, off.Type))
  53. }
  54. }
  55. /* check for "string" */
  56. if (self.Opts & F_stringize) != 0 {
  57. opts = append(opts, "string")
  58. }
  59. /* check for "omitempty" */
  60. if (self.Opts & F_omitempty) != 0 {
  61. opts = append(opts, "omitempty")
  62. }
  63. /* format the field */
  64. return fmt.Sprintf(
  65. "{Field \"%s\" @ %s, opts=%s, type=%s}",
  66. self.Name,
  67. strings.Join(path, "."),
  68. strings.Join(opts, ","),
  69. self.Type,
  70. )
  71. }
  72. func (self *FieldMeta) optimize() {
  73. var n int
  74. var v uintptr
  75. /* merge adjacent offsets */
  76. for _, o := range self.Path {
  77. if v += o.Size; o.Kind == F_deref {
  78. self.Path[n].Size = v
  79. self.Path[n].Type, v = o.Type, 0
  80. self.Path[n].Kind, n = F_deref, n + 1
  81. }
  82. }
  83. /* last offset value */
  84. if v != 0 {
  85. self.Path[n].Size = v
  86. self.Path[n].Type = nil
  87. self.Path[n].Kind = F_offset
  88. n++
  89. }
  90. /* must be at least 1 offset */
  91. if n != 0 {
  92. self.Path = self.Path[:n]
  93. } else {
  94. self.Path = []Offset{{Kind: F_offset}}
  95. }
  96. }
  97. func resolveFields(vt reflect.Type) []FieldMeta {
  98. tfv := typeFields(vt)
  99. ret := []FieldMeta(nil)
  100. /* convert each field */
  101. for _, fv := range tfv.list {
  102. item := vt
  103. path := []Offset(nil)
  104. opts := FieldOpts(0)
  105. /* check for "string" */
  106. if fv.quoted {
  107. opts |= F_stringize
  108. }
  109. /* check for "omitempty" */
  110. if fv.omitEmpty {
  111. opts |= F_omitempty
  112. }
  113. /* dump the field path */
  114. for _, i := range fv.index {
  115. kind := F_offset
  116. fval := item.Field(i)
  117. item = fval.Type
  118. /* deref the pointer if needed */
  119. if item.Kind() == reflect.Ptr {
  120. kind = F_deref
  121. item = item.Elem()
  122. }
  123. /* add to path */
  124. path = append(path, Offset {
  125. Kind: kind,
  126. Type: item,
  127. Size: fval.Offset,
  128. })
  129. }
  130. /* get the index to the last offset */
  131. idx := len(path) - 1
  132. fvt := path[idx].Type
  133. /* do not dereference into fields */
  134. if path[idx].Kind == F_deref {
  135. fvt = reflect.PtrTo(fvt)
  136. path[idx].Kind = F_offset
  137. }
  138. /* add to result */
  139. ret = append(ret, FieldMeta {
  140. Type: fvt,
  141. Opts: opts,
  142. Path: path,
  143. Name: fv.name,
  144. })
  145. }
  146. /* optimize the offsets */
  147. for i := range ret {
  148. ret[i].optimize()
  149. }
  150. /* all done */
  151. return ret
  152. }
  153. var (
  154. fieldLock = sync.RWMutex{}
  155. fieldCache = map[reflect.Type][]FieldMeta{}
  156. )
  157. func ResolveStruct(vt reflect.Type) []FieldMeta {
  158. var ok bool
  159. var fm []FieldMeta
  160. /* attempt to read from cache */
  161. fieldLock.RLock()
  162. fm, ok = fieldCache[vt]
  163. fieldLock.RUnlock()
  164. /* check if it was cached */
  165. if ok {
  166. return fm
  167. }
  168. /* otherwise use write-lock */
  169. fieldLock.Lock()
  170. defer fieldLock.Unlock()
  171. /* double check */
  172. if fm, ok = fieldCache[vt]; ok {
  173. return fm
  174. }
  175. /* resolve the field */
  176. fm = resolveFields(vt)
  177. fieldCache[vt] = fm
  178. return fm
  179. }