-
Notifications
You must be signed in to change notification settings - Fork 6
/
control_registry.go
70 lines (62 loc) · 2.21 KB
/
control_registry.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
package page
import (
"hash/fnv"
"reflect"
)
var controlRegistry = make(map[uint64]reflect.Type)
var controlRegistryIds = make(map[reflect.Type]uint64)
// RegisterControl registers the control for the serialize/deserialize process. You should call this
// for each control from an init() function.
//
// As a control is added to the registry, it is assigned an id. That id is used to identify a control
// in the serialization and deserialization process. We make a significant attempt to prevent the
// addition of controls to an application from causing a change in these ids, since an id change will
// also cause the current page cache to be invalidated. We use a hashing function, and a collision detector
// to do that. If a collision is detected, it will panic, and you should change the hash salt and try again,
// as well as bump the cache version to invalidate the cache.
func RegisterControl(i ControlI) {
typ := reflect.Indirect(reflect.ValueOf(i)).Type()
if _, ok := controlRegistryIds[typ]; ok {
panic("Registering duplicate control")
}
hash := fnv.New64()
n := typ.Name()
if n == "" {
panic("type problem")
}
_,_ = hash.Write([]byte(ControlRegistrySalt))
_,_ = hash.Write([]byte(typ.PkgPath()))
_,_ = hash.Write([]byte(typ.Name()))
id := hash.Sum64()
if t,ok := controlRegistry[id]; ok {
panic("The control registry has detected a collision. " +
t.Name() + " has collided with " + typ.Name() + ". " +
"This is a very rare situation, but needs " +
"to be fixed. To fix it, change the ControlRegistrySalt value, and also change the " +
"PageCacheVersionID")
}
controlRegistry[id] = typ
controlRegistryIds[typ] = id
}
func controlRegistryID(i ControlI) uint64 {
val := reflect.Indirect(reflect.ValueOf(i))
typ := val.Type()
id, ok := controlRegistryIds[typ]
if !ok {
panic("ControlBase type is not registered: " + typ.String())
}
return id
}
func createRegisteredControl(registryID uint64, p *Page) ControlI {
typ := controlRegistry[registryID]
v := reflect.New(typ)
c := v.Interface().(ControlI)
c.control().Self = c
c.control().page = p
return c
}
func controlIsRegistered(i interface{}) bool {
typ := reflect.Indirect(reflect.ValueOf(i)).Type()
_,ok := controlRegistryIds[typ]
return ok
}