-
Notifications
You must be signed in to change notification settings - Fork 22
/
event.go
79 lines (61 loc) · 2.35 KB
/
event.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
package event
import (
"sync"
"sync/atomic"
"unsafe"
"github.com/iotaledger/hive.go/ds/orderedmap"
"github.com/iotaledger/hive.go/runtime/options"
)
// event is the base type for all generic events.
type event[TriggerFunc any] struct {
// hooks is a dictionary of callbacks that are currently registered with the event.
hooks *orderedmap.OrderedMap[uint64, *Hook[TriggerFunc]]
// hooksCounter is used to assign a unique ID to each hook.
hooksCounter atomic.Uint64
// link is the Hook to another event.
link *Hook[TriggerFunc]
// linkMutex is used to prevent concurrent access to the link.
linkMutex sync.Mutex
// preTriggerFunc is a function that is called before each Hook is executed.
preTriggerFunc TriggerFunc
// triggerSettings are the settings that keep track of the number of times the event was triggered.
*triggerSettings
}
// newEvent creates a new event instance with the given options.
func newEvent[TriggerFunc any](opts ...Option) *event[TriggerFunc] {
e := &event[TriggerFunc]{
hooks: orderedmap.New[uint64, *Hook[TriggerFunc]](),
triggerSettings: options.Apply(new(triggerSettings), opts),
}
if !IsInterfaceNil(e.triggerSettings.preTriggerFunc) {
//nolint:forcetypeassert // false positive, we know that preTriggerFunc is of type TriggerFunc
e.preTriggerFunc = e.triggerSettings.preTriggerFunc.(TriggerFunc)
}
return e
}
// Hook adds a new callback to the event and returns the corresponding Hook.
func (e *event[TriggerFunc]) Hook(triggerFunc TriggerFunc, opts ...Option) *Hook[TriggerFunc] {
hook := newHook(e.hooksCounter.Add(1), e, triggerFunc, opts...)
e.hooks.Set(hook.id, hook)
return hook
}
// linkTo unhooks the previous Hook and then hooks the trigger function to the given target event.
func (e *event[TriggerFunc]) linkTo(target eventInterface[TriggerFunc], triggerFunc TriggerFunc) {
e.linkMutex.Lock()
defer e.linkMutex.Unlock()
if e.link != nil {
e.link.Unhook()
}
if IsInterfaceNil(target) {
e.link = nil
} else {
e.link = target.Hook(triggerFunc)
}
}
func IsInterfaceNil(param interface{}) bool {
return param == nil || (*[2]uintptr)(unsafe.Pointer(¶m))[1] == 0
}
// eventInterface is an interface that is used to match the generic Hook function of events during the linking process.
type eventInterface[TriggerFunc any] interface {
Hook(callback TriggerFunc, opts ...Option) *Hook[TriggerFunc]
}