-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcache.go
More file actions
104 lines (87 loc) · 2.12 KB
/
cache.go
File metadata and controls
104 lines (87 loc) · 2.12 KB
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
92
93
94
95
96
97
98
99
100
101
102
103
104
package structwalker
import (
"reflect"
"sync"
)
type typeCache struct {
m sync.Map // map[reflect.Type]*typeMeta
}
type typeMeta struct {
Fields []fieldMeta
}
type fieldMeta struct {
StructField reflect.StructField
Tags []Tag
TagMap map[string]Tag // key → Tag for fast lookup during dispatch
IsStruct bool
IsPtr bool
IsSlice bool
IsMap bool
HandlerKeys []string
}
func newTypeCache() *typeCache {
return &typeCache{}
}
func (c *typeCache) get(t reflect.Type, handlerKeys []string, tagParser func(string, string) Tag) *typeMeta {
if meta, ok := c.m.Load(t); ok {
return meta.(*typeMeta)
}
meta := buildTypeMeta(t, handlerKeys, tagParser)
actual, _ := c.m.LoadOrStore(t, meta)
return actual.(*typeMeta)
}
func buildTypeMeta(t reflect.Type, handlerKeys []string, tagParser func(string, string) Tag) *typeMeta {
n := t.NumField()
meta := &typeMeta{
Fields: make([]fieldMeta, 0, n),
}
keySet := make(map[string]struct{}, len(handlerKeys))
for _, k := range handlerKeys {
keySet[k] = struct{}{}
}
for i := range n {
sf := t.Field(i)
var tags []Tag
if tagParser != nil {
for _, stdTag := range ParseAllTags(sf.Tag) {
tags = append(tags, tagParser(stdTag.Key, stdTag.Raw))
}
} else {
tags = ParseAllTags(sf.Tag)
}
ft := sf.Type
isPtr := ft.Kind() == reflect.Ptr
if isPtr {
ft = ft.Elem()
}
fm := fieldMeta{
StructField: sf,
Tags: tags,
IsStruct: ft.Kind() == reflect.Struct,
IsPtr: isPtr,
IsSlice: sf.Type.Kind() == reflect.Slice || sf.Type.Kind() == reflect.Array,
IsMap: sf.Type.Kind() == reflect.Map,
}
// Pre-compute tag map and matching handler keys
if len(tags) > 0 {
fm.TagMap = make(map[string]Tag, len(tags))
for _, tag := range tags {
fm.TagMap[tag.Key] = tag
if _, ok := keySet[tag.Key]; ok {
fm.HandlerKeys = append(fm.HandlerKeys, tag.Key)
}
}
}
meta.Fields = append(meta.Fields, fm)
}
return meta
}
func (c *typeCache) invalidate(t reflect.Type) {
c.m.Delete(t)
}
func (c *typeCache) clear() {
c.m.Range(func(key, _ any) bool {
c.m.Delete(key)
return true
})
}