-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcache.go
91 lines (81 loc) · 1.72 KB
/
cache.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package form
import (
"reflect"
"strings"
)
type fieldInfo struct {
Type reflect.Type
index []int
}
type structInfo map[string]fieldInfo
type cacheT struct {
data map[reflect.Type]structInfo
tagKey string
tagDelimiter string
tagValueIgnore string
}
func newCache() cacheT {
return cacheT{
tagKey: "form",
tagDelimiter: ",",
tagValueIgnore: "-",
data: map[reflect.Type]structInfo{},
}
}
func (c *cacheT) elementType(t reflect.Type, path []string) (reflect.Type, bool) {
for _, leg := range path {
for t.Kind() == reflect.Pointer {
t = t.Elem()
}
if t.Kind() == reflect.Struct {
info := c.fetchCached(t)
if field, ok := info[leg]; ok {
t = t.FieldByIndex(field.index).Type
} else {
return t, false
}
continue
}
if t.Kind() == reflect.Map || t.Kind() == reflect.Array || t.Kind() == reflect.Slice {
t = t.Elem()
} else {
return t, false
}
}
for t.Kind() == reflect.Pointer {
t = t.Elem()
}
return t, true
}
// t must be of struct type
func (c *cacheT) appendCache(t reflect.Type) structInfo {
var info structInfo = make(structInfo)
for _, field := range reflect.VisibleFields(t) {
if field.IsExported() {
key := field.Name
if tag, ok := field.Tag.Lookup(c.tagKey); ok && len(tag) != 0 {
if tag == c.tagValueIgnore {
continue
}
vals := strings.Split(tag, c.tagDelimiter)
if len(vals[0]) != 0 {
key = vals[0]
}
}
info[key] = fieldInfo{
field.Type,
field.Index,
}
}
}
c.data[t] = info
return info
}
// t must be of struct type
func (c *cacheT) fetchCached(t reflect.Type) (info structInfo) {
if info, ok := c.data[t]; ok {
return info
} else {
return c.appendCache(t)
}
}