forked from iotaledger/hive.go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
group.go
66 lines (52 loc) · 1.91 KB
/
group.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
package event
import (
"reflect"
"sync"
"github.com/izuc/zipp.foundation/constraints"
)
// Group is a trait that can be embedded into a struct to make the contained events linkable.
type Group[GroupType any, GroupPtrType ptrGroupType[GroupType, GroupPtrType]] struct {
linkUpdated *Event1[GroupPtrType]
sync.Once
}
// CreateGroupConstructor returns the linkable constructor for the given event group.
func CreateGroupConstructor[GroupType any, GroupPtrType ptrGroupType[GroupType, GroupPtrType]](newFunc func() GroupPtrType) func(...GroupPtrType) GroupPtrType {
return func(optLinkTargets ...GroupPtrType) (self GroupPtrType) {
self = newFunc()
selfValue := reflect.ValueOf(self).Elem()
self.linkUpdatedEvent().Hook(func(linkTarget GroupPtrType) {
if linkTarget == nil {
linkTarget = new(GroupType)
}
linkTargetValue := reflect.ValueOf(linkTarget).Elem()
for i := 0; i < selfValue.NumField(); i++ {
if sourceField := selfValue.Field(i); sourceField.Kind() == reflect.Ptr {
if linkTo := sourceField.MethodByName("LinkTo"); linkTo.IsValid() {
linkTo.Call([]reflect.Value{linkTargetValue.Field(i)})
}
}
}
})
if len(optLinkTargets) > 0 {
self.LinkTo(optLinkTargets[0])
}
return self
}
}
// LinkTo links the group to another group of the same type (nil unlinks).
func (g *Group[GroupType, GroupPtrType]) LinkTo(target GroupPtrType) {
g.linkUpdatedEvent().Trigger(target)
}
// linkUpdatedEvent returns the linkUpdated Event (it is lazily created to simplify the embedding).
func (g *Group[GroupType, GroupPtrType]) linkUpdatedEvent() *Event1[GroupPtrType] {
g.Do(func() {
g.linkUpdated = New1[GroupPtrType]()
})
return g.linkUpdated
}
// ptrGroupType is a helper type to create a pointer to a Group type.
type ptrGroupType[GroupType any, GroupPtrType constraints.Ptr[GroupType]] interface {
*GroupType
linkUpdatedEvent() *Event1[GroupPtrType]
LinkTo(target GroupPtrType)
}