forked from vmihailenco/gforms
/
typeinfo.go
94 lines (77 loc) · 1.58 KB
/
typeinfo.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
92
93
94
package gforms
import (
"reflect"
"strings"
"sync"
)
var (
fieldType = reflect.TypeOf((*Field)(nil)).Elem()
tinfoMap = newTypeInfoMap()
)
//------------------------------------------------------------------------------
type fieldFlags int
const (
fReq fieldFlags = 1 << iota
)
type fieldInfo struct {
idx []int
name string
label string
constr constructor
flags fieldFlags
}
type typeInfo struct {
fields []*fieldInfo
}
type typeInfoMap struct {
l sync.RWMutex
m map[reflect.Type]*typeInfo
}
func newTypeInfoMap() *typeInfoMap {
return &typeInfoMap{
m: make(map[reflect.Type]*typeInfo),
}
}
func (m *typeInfoMap) TypeInfo(typ reflect.Type) *typeInfo {
m.l.RLock()
tinfo, ok := m.m[typ]
m.l.RUnlock()
if ok {
return tinfo
}
tinfo = &typeInfo{}
for i := 0; i < typ.NumField(); i++ {
f := typ.Field(i)
if f.PkgPath != "" || !f.Type.Implements(fieldType) {
continue
}
tinfo.fields = append(tinfo.fields, m.newStructFieldInfo(typ, &f))
}
m.l.Lock()
m.m[typ] = tinfo
m.l.Unlock()
return tinfo
}
func (m *typeInfoMap) newStructFieldInfo(typ reflect.Type, f *reflect.StructField) *fieldInfo {
finfo := &fieldInfo{
idx: f.Index,
constr: tconstrMap.Constructor(f.Type),
}
tokens := strings.Split(f.Tag.Get("gforms"), ",")
finfo.label = tokens[0]
if len(tokens) > 1 {
for _, flag := range tokens[1:] {
switch flag {
case "required":
finfo.flags |= fReq
}
}
}
finfo.name = f.Name
if finfo.label == "" {
finfo.label = strings.Join(splitWords(f.Name), " ")
} else if finfo.label == "-" {
finfo.label = ""
}
return finfo
}