-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEventEmitter.lua
144 lines (118 loc) · 4.13 KB
/
EventEmitter.lua
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
local patched_xpcall = require("overloads").xpcall
--- Event emitter.
--- @class mousebase.EventEmitter:Class
--- @field protected _crucialListeners table
--- @field protected _listeners table
local EventEmitter = require("@mousetool/class"):extend("EventEmitter")
local onFunc = function(events, eventName, listener, options)
if not events[eventName] then
events[eventName] = { _sz = 0 }
events._sz = events._sz + 1
end
local event = events[eventName]
event._sz = event._sz + 1
event[event._sz] = { listener, options }
end
local emitFunc = function(listeners, eventName, ...)
if not listeners then return end
local listenersIndexToRemove = { _sz = 0 }
for i = 1, listeners._sz do
local listener, options = listeners[i][1], listeners[i][2]
patched_xpcall(listener, function(err)
print("Runtime Error : Event " .. eventName .. ": ".. tostring(err) .. "\n" .. debug.traceback(nil, 2))
end, ...)
if options and options.once then
listeners[i] = nil
end
end
-- Compact listeners list
do
local found_spot = false
local last_empty = nil
for i = 1, listeners._sz do
if not found_spot then
if listeners[i] == nil then
last_empty = i
found_spot = true
end
elseif listeners[i] then
listeners[last_empty] = listeners[i]
listeners[i] = nil
last_empty = last_empty + 1
end
end
if last_empty then
listeners._sz = last_empty - 1
end
end
end
--- Creates a new event emitter.
--- @return mousebase.EventEmitter @The instance of the EventEmitter
EventEmitter._init = function(self)
self._listeners = { _sz = 0 }
self._crucialListeners = { _sz = 0 }
end
--- Adds the listener function to the end of the listeners array for the event named eventName.
--- No checks are made to see if the listener has already been added.
--- @param eventName string The name of the event
--- @param listener function The callback function
--- @param options table
--- @return mousebase.EventEmitter
EventEmitter.on = function(self, eventName, listener, options)
onFunc(self._listeners, eventName, listener, options)
return self
end
EventEmitter.addListener = EventEmitter.on
EventEmitter.once = function(self, eventName, listener, options)
options = options or {}
options.once = true
return self:on(eventName, listener, options)
end
EventEmitter.off = function(self, eventName, listener)
local listeners = self._listeners[eventName]
if not listeners then return end
for i = 1, listeners._sz do
if listeners[i][1] == listener then
table.remove(listeners, i)
listeners._sz = listeners._sz - 1
break
end
end
if listeners._sz <= 0 then
self._listeners[eventName] = nil
end
return self
end
EventEmitter.removeListener = EventEmitter.off
EventEmitter.emit = function(self, eventName, ...)
-- Emit crucial events first
emitFunc(self._crucialListeners[eventName], eventName, ...)
emitFunc(self._listeners[eventName], eventName, ...)
end
EventEmitter.onCrucial = function(self, eventName, listener, options)
onFunc(self._crucialListeners, eventName, listener, options)
return self
end
EventEmitter.addCrucialListener = EventEmitter.onCrucial
EventEmitter.onceCrucial = function(self, eventName, listener, options)
options = options or {}
options.once = true
return self:onCrucial(eventName, listener, options)
end
EventEmitter.offCrucial = function(self, eventName, listener)
local listeners = self._crucialListeners[eventName]
if not listeners then return end
for i = 1, listeners._sz do
if listeners[i][1] == listener then
table.remove(listeners, i)
listeners._sz = listeners._sz - 1
break
end
end
if listeners._sz <= 0 then
self._crucialListeners[eventName] = nil
end
return self
end
EventEmitter.removeCrucialListener = EventEmitter.offCrucial
return EventEmitter