@quenty/rx 13.7.0 → 13.8.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 +13 -0
- package/package.json +10 -10
- package/src/Shared/Observable.lua +1 -1
- package/src/Shared/ObservableSubscriptionTable.lua +8 -4
- package/src/Shared/Rx.lua +51 -41
- package/src/Shared/Subscription.lua +26 -18
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
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
|
+
# [13.8.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/rx@13.7.0...@quenty/rx@13.8.0) (2024-10-04)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Allow cleanup to be done in a safer way if the object is already cleaned up ([20b3ef1](https://github.com/Quenty/NevermoreEngine/commit/20b3ef1802e4bf92d0f46de99f3ec85660f17002))
|
|
12
|
+
* Do not fire observables that are cancelled ([2098b28](https://github.com/Quenty/NevermoreEngine/commit/2098b2809f40c9a813200b4f2789340901c6baee))
|
|
13
|
+
* Use nil instead of empty string for source here to save a bit of memory ([f1edd7f](https://github.com/Quenty/NevermoreEngine/commit/f1edd7f823ec0307517f1cba2717de147445608f))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
6
19
|
# [13.7.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/rx@13.6.0...@quenty/rx@13.7.0) (2024-09-25)
|
|
7
20
|
|
|
8
21
|
**Note:** Version bump only for package @quenty/rx
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/rx",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.8.0",
|
|
4
4
|
"description": "Quenty's reactive library for Roblox",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -28,18 +28,18 @@
|
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@quenty/cancellabledelay": "^3.5.0",
|
|
31
|
-
"@quenty/canceltoken": "^11.
|
|
32
|
-
"@quenty/ducktype": "^5.
|
|
33
|
-
"@quenty/loader": "^10.
|
|
34
|
-
"@quenty/maid": "^3.
|
|
35
|
-
"@quenty/promise": "^10.
|
|
36
|
-
"@quenty/signal": "^7.
|
|
37
|
-
"@quenty/symbol": "^3.
|
|
31
|
+
"@quenty/canceltoken": "^11.7.0",
|
|
32
|
+
"@quenty/ducktype": "^5.6.0",
|
|
33
|
+
"@quenty/loader": "^10.6.0",
|
|
34
|
+
"@quenty/maid": "^3.4.0",
|
|
35
|
+
"@quenty/promise": "^10.6.0",
|
|
36
|
+
"@quenty/signal": "^7.7.0",
|
|
37
|
+
"@quenty/symbol": "^3.2.0",
|
|
38
38
|
"@quenty/table": "^3.5.0",
|
|
39
|
-
"@quenty/throttle": "^10.
|
|
39
|
+
"@quenty/throttle": "^10.7.0"
|
|
40
40
|
},
|
|
41
41
|
"publishConfig": {
|
|
42
42
|
"access": "public"
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "035abfa088c854a73e1c65b350267eaa17669646"
|
|
45
45
|
}
|
|
@@ -107,7 +107,7 @@ function Observable.new(onSubscribe)
|
|
|
107
107
|
assert(type(onSubscribe) == "function", "Bad onSubscribe")
|
|
108
108
|
|
|
109
109
|
return setmetatable({
|
|
110
|
-
_source = ENABLE_STACK_TRACING
|
|
110
|
+
_source = if ENABLE_STACK_TRACING then debug.traceback() else nil;
|
|
111
111
|
_onSubscribe = onSubscribe;
|
|
112
112
|
}, Observable)
|
|
113
113
|
end
|
|
@@ -35,7 +35,9 @@ function ObservableSubscriptionTable:Fire(key, ...)
|
|
|
35
35
|
|
|
36
36
|
-- Make a copy so we don't have to worry about our last changing
|
|
37
37
|
for _, sub in pairs(table.clone(subs)) do
|
|
38
|
-
|
|
38
|
+
if sub:IsPending() then
|
|
39
|
+
task.spawn(sub.Fire, sub, ...)
|
|
40
|
+
end
|
|
39
41
|
end
|
|
40
42
|
end
|
|
41
43
|
|
|
@@ -49,7 +51,9 @@ function ObservableSubscriptionTable:Complete(key, ...)
|
|
|
49
51
|
self._subMap[key] = nil
|
|
50
52
|
|
|
51
53
|
for _, sub in pairs(subsToComplete) do
|
|
52
|
-
|
|
54
|
+
if sub:IsPending() then
|
|
55
|
+
task.spawn(sub.Complete, sub, ...)
|
|
56
|
+
end
|
|
53
57
|
end
|
|
54
58
|
end
|
|
55
59
|
|
|
@@ -74,11 +78,11 @@ function ObservableSubscriptionTable:Observe(key, retrieveInitialValue)
|
|
|
74
78
|
end
|
|
75
79
|
|
|
76
80
|
return function()
|
|
77
|
-
|
|
81
|
+
local current = self._subMap[key]
|
|
82
|
+
if not current then
|
|
78
83
|
return
|
|
79
84
|
end
|
|
80
85
|
|
|
81
|
-
local current = self._subMap[key]
|
|
82
86
|
local index = table.find(current, sub)
|
|
83
87
|
if not index then
|
|
84
88
|
return
|
package/src/Shared/Rx.lua
CHANGED
|
@@ -1444,20 +1444,19 @@ end
|
|
|
1444
1444
|
function Rx.combineLatest(observables)
|
|
1445
1445
|
assert(type(observables) == "table", "Bad observables")
|
|
1446
1446
|
|
|
1447
|
-
local initialPending = 0
|
|
1448
|
-
local defaultLatest = {}
|
|
1449
|
-
for key, value in pairs(observables) do
|
|
1450
|
-
if Observable.isObservable(value) then
|
|
1451
|
-
initialPending = initialPending + 1
|
|
1452
|
-
defaultLatest[key] = UNSET_VALUE
|
|
1453
|
-
else
|
|
1454
|
-
defaultLatest[key] = value
|
|
1455
|
-
end
|
|
1456
|
-
end
|
|
1457
|
-
|
|
1458
1447
|
return Observable.new(function(sub)
|
|
1459
|
-
local pending =
|
|
1460
|
-
local latest =
|
|
1448
|
+
local pending = 0
|
|
1449
|
+
local latest = {}
|
|
1450
|
+
|
|
1451
|
+
-- Instead of caching this, use extra compute here
|
|
1452
|
+
for key, value in pairs(observables) do
|
|
1453
|
+
if Observable.isObservable(value) then
|
|
1454
|
+
pending = pending + 1
|
|
1455
|
+
latest[key] = UNSET_VALUE
|
|
1456
|
+
else
|
|
1457
|
+
latest[key] = value
|
|
1458
|
+
end
|
|
1459
|
+
end
|
|
1461
1460
|
|
|
1462
1461
|
if pending == 0 then
|
|
1463
1462
|
sub:Fire(latest)
|
|
@@ -1474,7 +1473,19 @@ function Rx.combineLatest(observables)
|
|
|
1474
1473
|
end
|
|
1475
1474
|
end
|
|
1476
1475
|
|
|
1477
|
-
sub:Fire(table.clone(latest))
|
|
1476
|
+
sub:Fire(table.freeze(table.clone(latest)))
|
|
1477
|
+
end
|
|
1478
|
+
|
|
1479
|
+
local function failOnFirst(...)
|
|
1480
|
+
pending = pending - 1
|
|
1481
|
+
sub:Fail(...)
|
|
1482
|
+
end
|
|
1483
|
+
|
|
1484
|
+
local function completeOnAllPendingDone()
|
|
1485
|
+
pending = pending - 1
|
|
1486
|
+
if pending == 0 then
|
|
1487
|
+
sub:Complete()
|
|
1488
|
+
end
|
|
1478
1489
|
end
|
|
1479
1490
|
|
|
1480
1491
|
for key, observer in pairs(observables) do
|
|
@@ -1484,16 +1495,8 @@ function Rx.combineLatest(observables)
|
|
|
1484
1495
|
latest[key] = value
|
|
1485
1496
|
fireIfAllSet()
|
|
1486
1497
|
end,
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
sub:Fail(...)
|
|
1490
|
-
end,
|
|
1491
|
-
function()
|
|
1492
|
-
pending = pending - 1
|
|
1493
|
-
if pending == 0 then
|
|
1494
|
-
sub:Complete()
|
|
1495
|
-
end
|
|
1496
|
-
end))
|
|
1498
|
+
failOnFirst,
|
|
1499
|
+
completeOnAllPendingDone))
|
|
1497
1500
|
end
|
|
1498
1501
|
end
|
|
1499
1502
|
|
|
@@ -1859,30 +1862,37 @@ function Rx.throttleDefer()
|
|
|
1859
1862
|
assert(Observable.isObservable(source), "Bad observable")
|
|
1860
1863
|
|
|
1861
1864
|
return Observable.new(function(sub)
|
|
1862
|
-
local
|
|
1865
|
+
local lastResult = nil
|
|
1866
|
+
local currentQueue = nil
|
|
1863
1867
|
|
|
1864
|
-
local
|
|
1865
|
-
|
|
1866
|
-
maid:GiveTask(source:Subscribe(function(...)
|
|
1867
|
-
if not lastResult then
|
|
1868
|
+
local sourceSub = source:Subscribe(function(...)
|
|
1869
|
+
if lastResult then
|
|
1868
1870
|
lastResult = table.pack(...)
|
|
1871
|
+
return
|
|
1872
|
+
end
|
|
1869
1873
|
|
|
1870
|
-
|
|
1871
|
-
maid._currentQueue = task.defer(function()
|
|
1872
|
-
local current = lastResult
|
|
1873
|
-
lastResult = nil
|
|
1874
|
+
lastResult = table.pack(...)
|
|
1874
1875
|
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1876
|
+
-- Queue up our result
|
|
1877
|
+
currentQueue = task.defer(function()
|
|
1878
|
+
local current = lastResult
|
|
1879
|
+
lastResult = nil
|
|
1880
|
+
currentQueue = nil
|
|
1880
1881
|
|
|
1881
|
-
|
|
1882
|
+
if sub:IsPending() then
|
|
1883
|
+
sub:Fire(table.unpack(current, 1, current.n))
|
|
1884
|
+
end
|
|
1885
|
+
end)
|
|
1886
|
+
end, sub:GetFailComplete())
|
|
1887
|
+
|
|
1888
|
+
return function()
|
|
1889
|
+
if currentQueue then
|
|
1890
|
+
task.cancel(currentQueue)
|
|
1891
|
+
currentQueue = nil
|
|
1882
1892
|
end
|
|
1883
|
-
end, sub:GetFailComplete()))
|
|
1884
1893
|
|
|
1885
|
-
|
|
1894
|
+
sourceSub:Destroy()
|
|
1895
|
+
end
|
|
1886
1896
|
end)
|
|
1887
1897
|
end
|
|
1888
1898
|
end
|
|
@@ -24,7 +24,7 @@ local Subscription = {}
|
|
|
24
24
|
Subscription.ClassName = "Subscription"
|
|
25
25
|
Subscription.__index = Subscription
|
|
26
26
|
|
|
27
|
-
local
|
|
27
|
+
local SubscriptionStateTypes = {
|
|
28
28
|
PENDING = "pending";
|
|
29
29
|
FAILED = "failed";
|
|
30
30
|
COMPLETE = "complete";
|
|
@@ -46,8 +46,8 @@ function Subscription.new(fireCallback, failCallback, completeCallback, observab
|
|
|
46
46
|
assert(type(completeCallback) == "function" or completeCallback == nil, "Bad completeCallback")
|
|
47
47
|
|
|
48
48
|
return setmetatable({
|
|
49
|
-
_state =
|
|
50
|
-
_source = ENABLE_STACK_TRACING
|
|
49
|
+
_state = SubscriptionStateTypes.PENDING;
|
|
50
|
+
_source = if ENABLE_STACK_TRACING then debug.traceback() else nil;
|
|
51
51
|
_observableSource = observableSource;
|
|
52
52
|
_fireCallback = fireCallback;
|
|
53
53
|
_failCallback = failCallback;
|
|
@@ -61,11 +61,11 @@ end
|
|
|
61
61
|
@param ... any
|
|
62
62
|
]=]
|
|
63
63
|
function Subscription:Fire(...)
|
|
64
|
-
if self._state ==
|
|
64
|
+
if self._state == SubscriptionStateTypes.PENDING then
|
|
65
65
|
if self._fireCallback then
|
|
66
66
|
self._fireCallback(...)
|
|
67
67
|
end
|
|
68
|
-
elseif self._state ==
|
|
68
|
+
elseif self._state == SubscriptionStateTypes.CANCELLED then
|
|
69
69
|
warn("[Subscription.Fire] - We are cancelled, but events are still being pushed")
|
|
70
70
|
|
|
71
71
|
if ENABLE_STACK_TRACING then
|
|
@@ -80,11 +80,11 @@ end
|
|
|
80
80
|
Fails the subscription, preventing anything else from emitting.
|
|
81
81
|
]=]
|
|
82
82
|
function Subscription:Fail()
|
|
83
|
-
if self._state ~=
|
|
83
|
+
if self._state ~= SubscriptionStateTypes.PENDING then
|
|
84
84
|
return
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
self._state =
|
|
87
|
+
self._state = SubscriptionStateTypes.FAILED
|
|
88
88
|
|
|
89
89
|
if self._failCallback then
|
|
90
90
|
self._failCallback()
|
|
@@ -152,11 +152,11 @@ end
|
|
|
152
152
|
emitted.
|
|
153
153
|
]=]
|
|
154
154
|
function Subscription:Complete()
|
|
155
|
-
if self._state ~=
|
|
155
|
+
if self._state ~= SubscriptionStateTypes.PENDING then
|
|
156
156
|
return
|
|
157
157
|
end
|
|
158
158
|
|
|
159
|
-
self._state =
|
|
159
|
+
self._state = SubscriptionStateTypes.COMPLETE
|
|
160
160
|
if self._completeCallback then
|
|
161
161
|
self._completeCallback()
|
|
162
162
|
end
|
|
@@ -169,26 +169,34 @@ end
|
|
|
169
169
|
@return boolean
|
|
170
170
|
]=]
|
|
171
171
|
function Subscription:IsPending()
|
|
172
|
-
return self._state ==
|
|
172
|
+
return self._state == SubscriptionStateTypes.PENDING
|
|
173
173
|
end
|
|
174
174
|
|
|
175
175
|
function Subscription:_assignCleanup(task)
|
|
176
|
-
assert(
|
|
176
|
+
assert(self._cleanupTask == nil, "Already have _cleanupTask")
|
|
177
177
|
|
|
178
|
-
if task then
|
|
179
|
-
if self._state ~=
|
|
178
|
+
if MaidTaskUtils.isValidTask(task) then
|
|
179
|
+
if self._state ~= SubscriptionStateTypes.PENDING then
|
|
180
180
|
MaidTaskUtils.doTask(task)
|
|
181
181
|
return
|
|
182
182
|
end
|
|
183
183
|
|
|
184
184
|
self._cleanupTask = task
|
|
185
|
+
elseif task ~= nil then
|
|
186
|
+
error("Bad cleanup task")
|
|
185
187
|
end
|
|
186
188
|
end
|
|
187
189
|
|
|
188
190
|
function Subscription:_doCleanup()
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
191
|
+
local task = self._cleanupTask
|
|
192
|
+
if not task then
|
|
193
|
+
return
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
self._cleanupTask = nil
|
|
197
|
+
|
|
198
|
+
-- The validity can change
|
|
199
|
+
if MaidTaskUtils.isValidTask(task) then
|
|
192
200
|
MaidTaskUtils.doTask(task)
|
|
193
201
|
end
|
|
194
202
|
end
|
|
@@ -202,8 +210,8 @@ end
|
|
|
202
210
|
:::
|
|
203
211
|
]=]
|
|
204
212
|
function Subscription:Destroy()
|
|
205
|
-
if self._state ==
|
|
206
|
-
self._state =
|
|
213
|
+
if self._state == SubscriptionStateTypes.PENDING then
|
|
214
|
+
self._state = SubscriptionStateTypes.CANCELLED
|
|
207
215
|
end
|
|
208
216
|
|
|
209
217
|
self:_doCleanup()
|