-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathregistry.go
More file actions
125 lines (115 loc) · 2.88 KB
/
registry.go
File metadata and controls
125 lines (115 loc) · 2.88 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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package x
import (
"sort"
"sync"
)
type (
//Registry represents an extension type
Registry struct {
mux sync.RWMutex
scn int //scn is the serial number of the registry
types map[string]*Type
listener Listener
mergeListener MergeListener
}
)
// Scn returns registry sequence change number
func (r *Registry) Scn() int {
return r.scn
}
// Merge merges all types from the supplied registry into r.
//
// Listener behaviour:
// - If a MergeListener is configured, Merge calls it once to obtain a
// per-merge Listener and uses that for all per-type notifications.
// After processing all types, the per-merge Listener is called once with
// a nil *Type to signal completion. Implementations MUST tolerate nil.
// - If no MergeListener is configured, Merge uses the registry's general
// Listener (if any) for per-type notifications and does not emit a final
// nil sentinel call.
func (r *Registry) Merge(registry *Registry) {
listener := r.listener
if r.mergeListener != nil {
listener = r.mergeListener()
}
for _, aType := range registry.types {
r.register(aType, listener)
}
if r.mergeListener != nil {
listener(nil)
}
}
// Register registers a type
func (r *Registry) Register(aType *Type) {
r.register(aType, r.listener)
}
func (r *Registry) register(aType *Type, listener Listener) {
if aType.Scn == 0 {
aType.Scn = r.scn
}
r.mux.RLock()
key := aType.Key()
prev, ok := r.types[key]
r.mux.RUnlock()
if !ok || aType.Force {
r.mux.Lock()
r.types[key] = aType
r.mux.Unlock()
if listener != nil {
listener(aType)
}
return
}
if prev.Scn >= aType.Scn {
return
}
r.mux.Lock()
r.types[key] = aType
r.mux.Unlock()
if listener != nil {
listener(aType)
}
}
// Lookup returns a type by name
func (r *Registry) Lookup(name string) *Type {
r.mux.RLock()
aType, _ := r.types[name]
r.mux.RUnlock()
return aType
}
// Keys returns a sorted snapshot of registry keys.
//
// The returned slice is detached from the underlying map so callers are
// free to modify it. Ordering is deterministic for a given registry
// state but concurrent mutation while iterating is not supported.
func (r *Registry) Keys() []string {
r.mux.RLock()
keys := make([]string, 0, len(r.types))
for k := range r.types {
keys = append(keys, k)
}
r.mux.RUnlock()
sort.Strings(keys)
return keys
}
// ForEach invokes fn for each registered type using a sorted snapshot of
// Keys. Iteration stops early when fn returns false. Callbacks are invoked
// without holding internal locks.
func (r *Registry) ForEach(fn func(key string, t *Type) bool) {
if fn == nil {
return
}
for _, k := range r.Keys() {
if !fn(k, r.Lookup(k)) {
return
}
}
}
// NewRegistry creates a registry
func NewRegistry(options ...RegistryOption) *Registry {
ret := &Registry{types: make(map[string]*Type)}
for _, opt := range options {
opt(ret)
}
return ret
}