@quenty/signal 7.8.1 → 7.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/package.json +2 -2
- package/src/Shared/EventHandlerUtils.lua +66 -0
- package/src/Shared/GoodSignal.lua +3 -43
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [7.9.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/signal@7.8.1...@quenty/signal@7.9.0) (2024-11-06)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Performance Improvements
|
|
10
|
+
|
|
11
|
+
* Better perf check on category ([594d5bb](https://github.com/Quenty/NevermoreEngine/commit/594d5bb8f56817b501f7c47053615d6cc3f8e313))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
## [7.8.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/signal@7.8.0...@quenty/signal@7.8.1) (2024-11-04)
|
|
7
18
|
|
|
8
19
|
**Note:** Version bump only for package @quenty/signal
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/signal",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.9.0",
|
|
4
4
|
"description": "A simple signal implementation for Roblox",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -32,5 +32,5 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@quenty/loader": "^10.7.1"
|
|
34
34
|
},
|
|
35
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "00e6f71716216dd6ecbc8505ad898a1ab7f72756"
|
|
36
36
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
Utility methods to fire an event in a free thread, reusing threads
|
|
3
|
+
|
|
4
|
+
@class EventHandlerUtils
|
|
5
|
+
]=]
|
|
6
|
+
|
|
7
|
+
local require = require(script.Parent.loader).load(script)
|
|
8
|
+
|
|
9
|
+
local EventHandlerUtils = {}
|
|
10
|
+
|
|
11
|
+
-- The currently idle thread to run the next handler on
|
|
12
|
+
local freeThreads = setmetatable({}, {__mode = "kv"})
|
|
13
|
+
|
|
14
|
+
-- Function which acquires the currently idle handler runner thread, runs the
|
|
15
|
+
-- function fn on it, and then releases the thread, returning it to being the
|
|
16
|
+
-- currently idle one.
|
|
17
|
+
-- If there was a currently idle runner thread already, that's okay, that old
|
|
18
|
+
-- one will just get thrown and eventually GCed.
|
|
19
|
+
function EventHandlerUtils._fireEvent(memoryCategory, fn, ...)
|
|
20
|
+
local acquiredRunnerThread = freeThreads[memoryCategory]
|
|
21
|
+
freeThreads[memoryCategory] = nil
|
|
22
|
+
fn(...)
|
|
23
|
+
-- The handler finished running, this runner thread is free again.
|
|
24
|
+
freeThreads[memoryCategory] = acquiredRunnerThread
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
-- Coroutine runner that we create coroutines of. The coroutine can be
|
|
28
|
+
-- repeatedly resumed with functions to run followed by the argument to run
|
|
29
|
+
-- them with.
|
|
30
|
+
function EventHandlerUtils._initializeThread(memoryCategory)
|
|
31
|
+
if memoryCategory == "" then
|
|
32
|
+
debug.setmemorycategory("signal_unknown")
|
|
33
|
+
else
|
|
34
|
+
debug.setmemorycategory(memoryCategory)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
-- Note: We cannot use the initial set of arguments passed to
|
|
38
|
+
-- initializeThread for a call to the handler, because those
|
|
39
|
+
-- arguments would stay on the stack for the duration of the thread's
|
|
40
|
+
-- existence, temporarily leaking references. Without access to raw bytecode
|
|
41
|
+
-- there's no way for us to clear the "..." references from the stack.
|
|
42
|
+
while true do
|
|
43
|
+
EventHandlerUtils._fireEvent(coroutine.yield())
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
--[=[
|
|
48
|
+
Safely fires an event in the given memory category we're in
|
|
49
|
+
|
|
50
|
+
@param memoryCategory string
|
|
51
|
+
@param callback any
|
|
52
|
+
@param ... any
|
|
53
|
+
]=]
|
|
54
|
+
function EventHandlerUtils.fire(memoryCategory, callback, ...)
|
|
55
|
+
assert(type(memoryCategory) == "string", "Bad memoryCategory")
|
|
56
|
+
assert(type(callback) == "function", "Bad callback")
|
|
57
|
+
|
|
58
|
+
if not freeThreads[memoryCategory] then
|
|
59
|
+
freeThreads[memoryCategory] = coroutine.create(EventHandlerUtils._initializeThread)
|
|
60
|
+
coroutine.resume(freeThreads[memoryCategory], memoryCategory)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
task.spawn(freeThreads[memoryCategory], memoryCategory, callback, ...)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
return EventHandlerUtils
|
|
@@ -43,41 +43,9 @@
|
|
|
43
43
|
@class GoodSignal
|
|
44
44
|
]=]
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
local weakFreeRunnerThreadLookup = setmetatable({}, {__mode = "kv"})
|
|
48
|
-
|
|
49
|
-
-- Function which acquires the currently idle handler runner thread, runs the
|
|
50
|
-
-- function fn on it, and then releases the thread, returning it to being the
|
|
51
|
-
-- currently idle one.
|
|
52
|
-
-- If there was a currently idle runner thread already, that's okay, that old
|
|
53
|
-
-- one will just get thrown and eventually GCed.
|
|
54
|
-
local function acquireRunnerThreadAndCallEventHandler(memoryCategory, fn, ...)
|
|
55
|
-
local acquiredRunnerThread = weakFreeRunnerThreadLookup[memoryCategory]
|
|
56
|
-
weakFreeRunnerThreadLookup[memoryCategory] = nil
|
|
57
|
-
fn(...)
|
|
58
|
-
-- The handler finished running, this runner thread is free again.
|
|
59
|
-
weakFreeRunnerThreadLookup[memoryCategory] = acquiredRunnerThread
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
-- Coroutine runner that we create coroutines of. The coroutine can be
|
|
63
|
-
-- repeatedly resumed with functions to run followed by the argument to run
|
|
64
|
-
-- them with.
|
|
65
|
-
local function runEventHandlerInFreeThread(memoryCategory)
|
|
66
|
-
if #memoryCategory == 0 then
|
|
67
|
-
debug.setmemorycategory("signal_unknown")
|
|
68
|
-
else
|
|
69
|
-
debug.setmemorycategory(memoryCategory)
|
|
70
|
-
end
|
|
46
|
+
local require = require(script.Parent.loader).load(script)
|
|
71
47
|
|
|
72
|
-
|
|
73
|
-
-- runEventHandlerInFreeThread for a call to the handler, because those
|
|
74
|
-
-- arguments would stay on the stack for the duration of the thread's
|
|
75
|
-
-- existence, temporarily leaking references. Without access to raw bytecode
|
|
76
|
-
-- there's no way for us to clear the "..." references from the stack.
|
|
77
|
-
while true do
|
|
78
|
-
acquireRunnerThreadAndCallEventHandler(coroutine.yield())
|
|
79
|
-
end
|
|
80
|
-
end
|
|
48
|
+
local EventHandlerUtils = require("EventHandlerUtils")
|
|
81
49
|
|
|
82
50
|
-- Connection class
|
|
83
51
|
local Connection = {}
|
|
@@ -216,15 +184,7 @@ function Signal:Fire(...)
|
|
|
216
184
|
local nextNode = rawget(connection, "_next")
|
|
217
185
|
|
|
218
186
|
if rawget(connection, "_signal") ~= nil then -- isConnected
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
-- Get the freeRunnerThread to the first yield
|
|
222
|
-
if not weakFreeRunnerThreadLookup[memoryCategory] then
|
|
223
|
-
weakFreeRunnerThreadLookup[memoryCategory] = coroutine.create(runEventHandlerInFreeThread)
|
|
224
|
-
coroutine.resume(weakFreeRunnerThreadLookup[memoryCategory], memoryCategory)
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
task.spawn(weakFreeRunnerThreadLookup[memoryCategory], memoryCategory, connection._fn, ...)
|
|
187
|
+
EventHandlerUtils.fire(connection._memoryCategory, connection._fn, ...)
|
|
228
188
|
end
|
|
229
189
|
|
|
230
190
|
connection = nextNode
|