structfields.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. // Copyright (c) Faye Amacker. All rights reserved.
  2. // Licensed under the MIT License. See LICENSE in the project root for license information.
  3. package cbor
  4. import (
  5. "reflect"
  6. "sort"
  7. "strings"
  8. )
  9. type field struct {
  10. name string
  11. nameAsInt int64 // used to decoder to match field name with CBOR int
  12. cborName []byte
  13. cborNameByteString []byte // major type 2 name encoding iff cborName has major type 3
  14. idx []int
  15. typ reflect.Type
  16. ef encodeFunc
  17. ief isEmptyFunc
  18. izf isZeroFunc
  19. typInfo *typeInfo // used to decoder to reuse type info
  20. tagged bool // used to choose dominant field (at the same level tagged fields dominate untagged fields)
  21. omitEmpty bool // used to skip empty field
  22. omitZero bool // used to skip zero field
  23. keyAsInt bool // used to encode/decode field name as int
  24. }
  25. type fields []*field
  26. // indexFieldSorter sorts fields by field idx at each level, breaking ties with idx depth.
  27. type indexFieldSorter struct {
  28. fields fields
  29. }
  30. func (x *indexFieldSorter) Len() int {
  31. return len(x.fields)
  32. }
  33. func (x *indexFieldSorter) Swap(i, j int) {
  34. x.fields[i], x.fields[j] = x.fields[j], x.fields[i]
  35. }
  36. func (x *indexFieldSorter) Less(i, j int) bool {
  37. iIdx, jIdx := x.fields[i].idx, x.fields[j].idx
  38. for k := 0; k < len(iIdx) && k < len(jIdx); k++ {
  39. if iIdx[k] != jIdx[k] {
  40. return iIdx[k] < jIdx[k]
  41. }
  42. }
  43. return len(iIdx) <= len(jIdx)
  44. }
  45. // nameLevelAndTagFieldSorter sorts fields by field name, idx depth, and presence of tag.
  46. type nameLevelAndTagFieldSorter struct {
  47. fields fields
  48. }
  49. func (x *nameLevelAndTagFieldSorter) Len() int {
  50. return len(x.fields)
  51. }
  52. func (x *nameLevelAndTagFieldSorter) Swap(i, j int) {
  53. x.fields[i], x.fields[j] = x.fields[j], x.fields[i]
  54. }
  55. func (x *nameLevelAndTagFieldSorter) Less(i, j int) bool {
  56. fi, fj := x.fields[i], x.fields[j]
  57. if fi.name != fj.name {
  58. return fi.name < fj.name
  59. }
  60. if len(fi.idx) != len(fj.idx) {
  61. return len(fi.idx) < len(fj.idx)
  62. }
  63. if fi.tagged != fj.tagged {
  64. return fi.tagged
  65. }
  66. return i < j // Field i and j have the same name, depth, and tagged status. Nothing else matters.
  67. }
  68. // getFields returns visible fields of struct type t following visibility rules for JSON encoding.
  69. func getFields(t reflect.Type) (flds fields, structOptions string) {
  70. // Get special field "_" tag options
  71. if f, ok := t.FieldByName("_"); ok {
  72. tag := f.Tag.Get("cbor")
  73. if tag != "-" {
  74. structOptions = tag
  75. }
  76. }
  77. // nTypes contains next level anonymous fields' types and indexes
  78. // (there can be multiple fields of the same type at the same level)
  79. flds, nTypes := appendFields(t, nil, nil, nil)
  80. if len(nTypes) > 0 {
  81. var cTypes map[reflect.Type][][]int // current level anonymous fields' types and indexes
  82. vTypes := map[reflect.Type]bool{t: true} // visited field types at less nested levels
  83. for len(nTypes) > 0 {
  84. cTypes, nTypes = nTypes, nil
  85. for t, idx := range cTypes {
  86. // If there are multiple anonymous fields of the same struct type at the same level, all are ignored.
  87. if len(idx) > 1 {
  88. continue
  89. }
  90. // Anonymous field of the same type at deeper nested level is ignored.
  91. if vTypes[t] {
  92. continue
  93. }
  94. vTypes[t] = true
  95. flds, nTypes = appendFields(t, idx[0], flds, nTypes)
  96. }
  97. }
  98. }
  99. sort.Sort(&nameLevelAndTagFieldSorter{flds})
  100. // Keep visible fields.
  101. j := 0 // index of next unique field
  102. for i := 0; i < len(flds); {
  103. name := flds[i].name
  104. if i == len(flds)-1 || // last field
  105. name != flds[i+1].name || // field i has unique field name
  106. len(flds[i].idx) < len(flds[i+1].idx) || // field i is at a less nested level than field i+1
  107. (flds[i].tagged && !flds[i+1].tagged) { // field i is tagged while field i+1 is not
  108. flds[j] = flds[i]
  109. j++
  110. }
  111. // Skip fields with the same field name.
  112. for i++; i < len(flds) && name == flds[i].name; i++ { //nolint:revive
  113. }
  114. }
  115. if j != len(flds) {
  116. flds = flds[:j]
  117. }
  118. // Sort fields by field index
  119. sort.Sort(&indexFieldSorter{flds})
  120. return flds, structOptions
  121. }
  122. // appendFields appends type t's exportable fields to flds and anonymous struct fields to nTypes .
  123. func appendFields(
  124. t reflect.Type,
  125. idx []int,
  126. flds fields,
  127. nTypes map[reflect.Type][][]int,
  128. ) (
  129. _flds fields,
  130. _nTypes map[reflect.Type][][]int,
  131. ) {
  132. for i := 0; i < t.NumField(); i++ {
  133. f := t.Field(i)
  134. ft := f.Type
  135. for ft.Kind() == reflect.Pointer {
  136. ft = ft.Elem()
  137. }
  138. if !isFieldExportable(f, ft.Kind()) {
  139. continue
  140. }
  141. cborTag := true
  142. tag := f.Tag.Get("cbor")
  143. if tag == "" {
  144. tag = f.Tag.Get("json")
  145. cborTag = false
  146. }
  147. if tag == "-" {
  148. continue
  149. }
  150. tagged := tag != ""
  151. // Parse field tag options
  152. var tagFieldName string
  153. var omitempty, omitzero, keyasint bool
  154. for j := 0; tag != ""; j++ {
  155. var token string
  156. idx := strings.IndexByte(tag, ',')
  157. if idx == -1 {
  158. token, tag = tag, ""
  159. } else {
  160. token, tag = tag[:idx], tag[idx+1:]
  161. }
  162. if j == 0 {
  163. tagFieldName = token
  164. } else {
  165. switch token {
  166. case "omitempty":
  167. omitempty = true
  168. case "omitzero":
  169. if cborTag || jsonStdlibSupportsOmitzero {
  170. omitzero = true
  171. }
  172. case "keyasint":
  173. keyasint = true
  174. }
  175. }
  176. }
  177. fieldName := tagFieldName
  178. if tagFieldName == "" {
  179. fieldName = f.Name
  180. }
  181. fIdx := make([]int, len(idx)+1)
  182. copy(fIdx, idx)
  183. fIdx[len(fIdx)-1] = i
  184. if !f.Anonymous || ft.Kind() != reflect.Struct || tagFieldName != "" {
  185. flds = append(flds, &field{
  186. name: fieldName,
  187. idx: fIdx,
  188. typ: f.Type,
  189. omitEmpty: omitempty,
  190. omitZero: omitzero,
  191. keyAsInt: keyasint,
  192. tagged: tagged})
  193. } else {
  194. if nTypes == nil {
  195. nTypes = make(map[reflect.Type][][]int)
  196. }
  197. nTypes[ft] = append(nTypes[ft], fIdx)
  198. }
  199. }
  200. return flds, nTypes
  201. }
  202. // isFieldExportable returns true if f is an exportable (regular or anonymous) field or
  203. // a nonexportable anonymous field of struct type.
  204. // Nonexportable anonymous field of struct type can contain exportable fields.
  205. func isFieldExportable(f reflect.StructField, fk reflect.Kind) bool { //nolint:gocritic // ignore hugeParam
  206. return f.IsExported() || (f.Anonymous && fk == reflect.Struct)
  207. }
  208. type embeddedFieldNullPtrFunc func(reflect.Value) (reflect.Value, error)
  209. // getFieldValue returns field value of struct v by index. When encountering null pointer
  210. // to anonymous (embedded) struct field, f is called with the last traversed field value.
  211. func getFieldValue(v reflect.Value, idx []int, f embeddedFieldNullPtrFunc) (fv reflect.Value, err error) {
  212. fv = v
  213. for i, n := range idx {
  214. fv = fv.Field(n)
  215. if i < len(idx)-1 {
  216. if fv.Kind() == reflect.Pointer && fv.Type().Elem().Kind() == reflect.Struct {
  217. if fv.IsNil() {
  218. // Null pointer to embedded struct field
  219. fv, err = f(fv)
  220. if err != nil || !fv.IsValid() {
  221. return fv, err
  222. }
  223. }
  224. fv = fv.Elem()
  225. }
  226. }
  227. }
  228. return fv, nil
  229. }