2
* Copyright 2021 ByteDance Inc.
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
8
* http://www.apache.org/licenses/LICENSE-2.0
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.
30
F_omitempty FieldOpts = 1 << iota
35
F_offset OffsetType = iota
45
type FieldMeta struct {
52
func (self *FieldMeta) String() string {
56
/* dump the field path */
57
for _, off := range self.Path {
58
if off.Kind == F_offset {
59
path = append(path, fmt.Sprintf("%d", off.Size))
61
path = append(path, fmt.Sprintf("%d.(*%s)", off.Size, off.Type))
65
/* check for "string" */
66
if (self.Opts & F_stringize) != 0 {
67
opts = append(opts, "string")
70
/* check for "omitempty" */
71
if (self.Opts & F_omitempty) != 0 {
72
opts = append(opts, "omitempty")
75
/* format the field */
77
"{Field \"%s\" @ %s, opts=%s, type=%s}",
79
strings.Join(path, "."),
80
strings.Join(opts, ","),
85
func (self *FieldMeta) optimize() {
89
/* merge adjacent offsets */
90
for _, o := range self.Path {
91
if v += o.Size; o.Kind == F_deref {
93
self.Path[n].Type, v = o.Type, 0
94
self.Path[n].Kind, n = F_deref, n + 1
98
/* last offset value */
100
self.Path[n].Size = v
101
self.Path[n].Type = nil
102
self.Path[n].Kind = F_offset
106
/* must be at least 1 offset */
108
self.Path = self.Path[:n]
110
self.Path = []Offset{{Kind: F_offset}}
114
func resolveFields(vt reflect.Type) []FieldMeta {
115
tfv := typeFields(vt)
116
ret := []FieldMeta(nil)
118
/* convert each field */
119
for _, fv := range tfv.list {
121
path := []Offset(nil)
124
/* check for "string" */
129
/* check for "omitempty" */
134
/* dump the field path */
135
for _, i := range fv.index {
137
fval := item.Field(i)
140
/* deref the pointer if needed */
141
if item.Kind() == reflect.Ptr {
147
path = append(path, Offset {
154
/* get the index to the last offset */
156
fvt := path[idx].Type
158
/* do not dereference into fields */
159
if path[idx].Kind == F_deref {
160
fvt = reflect.PtrTo(fvt)
161
path[idx].Kind = F_offset
165
ret = append(ret, FieldMeta {
173
/* optimize the offsets */
183
fieldLock = sync.RWMutex{}
184
fieldCache = map[reflect.Type][]FieldMeta{}
187
func ResolveStruct(vt reflect.Type) []FieldMeta {
191
/* attempt to read from cache */
193
fm, ok = fieldCache[vt]
196
/* check if it was cached */
201
/* otherwise use write-lock */
203
defer fieldLock.Unlock()
206
if fm, ok = fieldCache[vt]; ok {
210
/* resolve the field */
211
fm = resolveFields(vt)