...
1
16
17 package resolver
18
19 import (
20 `fmt`
21 `reflect`
22 `strings`
23 `sync`
24 )
25
26 type FieldOpts int
27 type OffsetType int
28
29 const (
30 F_omitempty FieldOpts = 1 << iota
31 F_stringize
32 )
33
34 const (
35 F_offset OffsetType = iota
36 F_deref
37 )
38
39 type Offset struct {
40 Size uintptr
41 Kind OffsetType
42 Type reflect.Type
43 }
44
45 type FieldMeta struct {
46 Name string
47 Path []Offset
48 Opts FieldOpts
49 Type reflect.Type
50 }
51
52 func (self *FieldMeta) String() string {
53 var path []string
54 var opts []string
55
56
57 for _, off := range self.Path {
58 if off.Kind == F_offset {
59 path = append(path, fmt.Sprintf("%d", off.Size))
60 } else {
61 path = append(path, fmt.Sprintf("%d.(*%s)", off.Size, off.Type))
62 }
63 }
64
65
66 if (self.Opts & F_stringize) != 0 {
67 opts = append(opts, "string")
68 }
69
70
71 if (self.Opts & F_omitempty) != 0 {
72 opts = append(opts, "omitempty")
73 }
74
75
76 return fmt.Sprintf(
77 "{Field \"%s\" @ %s, opts=%s, type=%s}",
78 self.Name,
79 strings.Join(path, "."),
80 strings.Join(opts, ","),
81 self.Type,
82 )
83 }
84
85 func (self *FieldMeta) optimize() {
86 var n int
87 var v uintptr
88
89
90 for _, o := range self.Path {
91 if v += o.Size; o.Kind == F_deref {
92 self.Path[n].Size = v
93 self.Path[n].Type, v = o.Type, 0
94 self.Path[n].Kind, n = F_deref, n + 1
95 }
96 }
97
98
99 if v != 0 {
100 self.Path[n].Size = v
101 self.Path[n].Type = nil
102 self.Path[n].Kind = F_offset
103 n++
104 }
105
106
107 if n != 0 {
108 self.Path = self.Path[:n]
109 } else {
110 self.Path = []Offset{{Kind: F_offset}}
111 }
112 }
113
114 func resolveFields(vt reflect.Type) []FieldMeta {
115 tfv := typeFields(vt)
116 ret := []FieldMeta(nil)
117
118
119 for _, fv := range tfv.list {
120 item := vt
121 path := []Offset(nil)
122 opts := FieldOpts(0)
123
124
125 if fv.quoted {
126 opts |= F_stringize
127 }
128
129
130 if fv.omitEmpty {
131 opts |= F_omitempty
132 }
133
134
135 for _, i := range fv.index {
136 kind := F_offset
137 fval := item.Field(i)
138 item = fval.Type
139
140
141 if item.Kind() == reflect.Ptr {
142 kind = F_deref
143 item = item.Elem()
144 }
145
146
147 path = append(path, Offset {
148 Kind: kind,
149 Type: item,
150 Size: fval.Offset,
151 })
152 }
153
154
155 idx := len(path) - 1
156 fvt := path[idx].Type
157
158
159 if path[idx].Kind == F_deref {
160 fvt = reflect.PtrTo(fvt)
161 path[idx].Kind = F_offset
162 }
163
164
165 ret = append(ret, FieldMeta {
166 Type: fvt,
167 Opts: opts,
168 Path: path,
169 Name: fv.name,
170 })
171 }
172
173
174 for i := range ret {
175 ret[i].optimize()
176 }
177
178
179 return ret
180 }
181
182 var (
183 fieldLock = sync.RWMutex{}
184 fieldCache = map[reflect.Type][]FieldMeta{}
185 )
186
187 func ResolveStruct(vt reflect.Type) []FieldMeta {
188 var ok bool
189 var fm []FieldMeta
190
191
192 fieldLock.RLock()
193 fm, ok = fieldCache[vt]
194 fieldLock.RUnlock()
195
196
197 if ok {
198 return fm
199 }
200
201
202 fieldLock.Lock()
203 defer fieldLock.Unlock()
204
205
206 if fm, ok = fieldCache[vt]; ok {
207 return fm
208 }
209
210
211 fm = resolveFields(vt)
212 fieldCache[vt] = fm
213 return fm
214 }
215
View as plain text