/
componentlib.go
185 lines (151 loc) · 4.15 KB
/
componentlib.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package pt
import (
"fmt"
"git.golaxy.org/core/ec"
"git.golaxy.org/core/internal/exception"
"git.golaxy.org/core/util/generic"
"git.golaxy.org/core/util/types"
"reflect"
"slices"
"sync"
)
// ComponentLib 组件原型库
type ComponentLib interface {
// Declare 声明组件原型
Declare(comp any, aliases ...string) ComponentPT
// Undeclare 取消声明组件原型
Undeclare(name string)
// Get 获取组件原型
Get(name string) (ComponentPT, bool)
// GetAlias 使用别名获取组件原型
GetAlias(alias string) []ComponentPT
// Range 遍历所有已注册的组件原型
Range(fun generic.Func1[ComponentPT, bool])
// ReversedRange 反向遍历所有已注册的组件原型
ReversedRange(fun generic.Func1[ComponentPT, bool])
}
var compLib = NewComponentLib()
// DefaultComponentLib 默认组件库
func DefaultComponentLib() ComponentLib {
return compLib
}
// NewComponentLib 创建组件原型库
func NewComponentLib() ComponentLib {
return &_ComponentLib{
compIdx: map[string]*ComponentPT{},
aliasTab: map[string][]*ComponentPT{},
}
}
type _ComponentLib struct {
sync.RWMutex
compIdx map[string]*ComponentPT
compList []*ComponentPT
aliasTab map[string][]*ComponentPT
}
// Declare 声明组件原型
func (lib *_ComponentLib) Declare(comp any, aliases ...string) ComponentPT {
if comp == nil {
panic(fmt.Errorf("%w: %w: comp is nil", ErrPt, exception.ErrArgs))
}
if tfComp, ok := comp.(reflect.Type); ok {
return lib.declare(tfComp, aliases)
} else {
return lib.declare(reflect.TypeOf(comp), aliases)
}
}
// Undeclare 取消声明组件原型
func (lib *_ComponentLib) Undeclare(name string) {
lib.Lock()
defer lib.Unlock()
delete(lib.compIdx, name)
lib.compList = slices.DeleteFunc(lib.compList, func(pt *ComponentPT) bool {
return pt.Name == name
})
lib.cleanAliases(name)
}
// Get 获取组件原型
func (lib *_ComponentLib) Get(name string) (ComponentPT, bool) {
lib.RLock()
defer lib.RUnlock()
comp, ok := lib.compIdx[name]
if !ok {
return ComponentPT{}, false
}
return *comp, ok
}
// GetAlias 使用别名获取组件原型
func (lib *_ComponentLib) GetAlias(alias string) []ComponentPT {
lib.RLock()
defer lib.RUnlock()
comps := lib.aliasTab[alias]
ret := make([]ComponentPT, 0, len(comps))
for _, comp := range comps {
ret = append(ret, *comp)
}
return ret
}
// Range 遍历所有已注册的组件原型
func (lib *_ComponentLib) Range(fun generic.Func1[ComponentPT, bool]) {
lib.RLock()
copied := slices.Clone(lib.compList)
lib.RUnlock()
for i := range copied {
if !fun.Exec(*copied[i]) {
return
}
}
}
// ReversedRange 反向遍历所有已注册的组件原型
func (lib *_ComponentLib) ReversedRange(fun generic.Func1[ComponentPT, bool]) {
lib.RLock()
copied := slices.Clone(lib.compList)
lib.RUnlock()
for i := len(copied) - 1; i >= 0; i-- {
if !fun.Exec(*copied[i]) {
return
}
}
}
func (lib *_ComponentLib) declare(tfComp reflect.Type, aliases []string) ComponentPT {
lib.Lock()
defer lib.Unlock()
for tfComp.Kind() == reflect.Pointer || tfComp.Kind() == reflect.Interface {
tfComp = tfComp.Elem()
}
if tfComp.Name() == "" {
panic(fmt.Errorf("%w: anonymous component not allowed", ErrPt))
}
compName := types.AnyFullName(tfComp)
if !reflect.PointerTo(tfComp).Implements(reflect.TypeOf((*ec.Component)(nil)).Elem()) {
panic(fmt.Errorf("%w: component %q not implement ec.Component", ErrPt, compName))
}
comp, ok := lib.compIdx[compName]
if ok {
lib.addAliases(comp, aliases)
return *comp
}
comp = &ComponentPT{
Name: compName,
RType: tfComp,
}
lib.compIdx[compName] = comp
lib.compList = append(lib.compList, comp)
lib.addAliases(comp, aliases)
return *comp
}
func (lib *_ComponentLib) addAliases(comp *ComponentPT, aliases []string) {
for _, alias := range aliases {
if !slices.ContainsFunc(lib.aliasTab[alias], func(pt *ComponentPT) bool {
return pt.Name == comp.Name
}) {
lib.aliasTab[alias] = append(lib.aliasTab[alias], comp)
}
}
}
func (lib *_ComponentLib) cleanAliases(compName string) {
for alias, comps := range lib.aliasTab {
lib.aliasTab[alias] = slices.DeleteFunc(comps, func(pt *ComponentPT) bool {
return pt.Name == compName
})
}
}