@quenty/observablecollection 12.7.0 → 12.8.1
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 +26 -0
- package/package.json +14 -14
- package/src/Shared/ObservableList.lua +4 -4
- package/src/Shared/ObservableMap.lua +8 -10
- package/src/Shared/ObservableMapList.lua +51 -14
- package/src/Shared/ObservableMapSet.lua +72 -180
- package/src/Shared/ObservableSet.lua +1 -1
- package/src/Shared/ObservableSortedList.lua +56 -38
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,32 @@
|
|
|
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
|
+
## [12.8.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@12.8.0...@quenty/observablecollection@12.8.1) (2024-10-04)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @quenty/observablecollection
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# [12.8.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@12.7.0...@quenty/observablecollection@12.8.0) (2024-10-04)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* Add ObservableSortedList:Contains(value) ([049c9df](https://github.com/Quenty/NevermoreEngine/commit/049c9df1df0cc765124c624a1276a456ff3e7700))
|
|
20
|
+
* ObservableSortedList can take non rx-value and still be performant ([e5c1d4f](https://github.com/Quenty/NevermoreEngine/commit/e5c1d4fb272f22d2559fba6f1a533686a730fca8))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Performance Improvements
|
|
24
|
+
|
|
25
|
+
* Predeclare size of lists to allocate for lists ([b662bbb](https://github.com/Quenty/NevermoreEngine/commit/b662bbb814f91a1853a549b217fa8af8a9f74d3d))
|
|
26
|
+
* Use switchToBrio() and table.create ([f73644e](https://github.com/Quenty/NevermoreEngine/commit/f73644e56a9ffd0991833bd147c705c210553539))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
6
32
|
# [12.7.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@12.6.0...@quenty/observablecollection@12.7.0) (2024-09-25)
|
|
7
33
|
|
|
8
34
|
**Note:** Version bump only for package @quenty/observablecollection
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/observablecollection",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.8.1",
|
|
4
4
|
"description": "A set of observable collections, such as sets, maps, sorted lists, and more.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -27,23 +27,23 @@
|
|
|
27
27
|
"Quenty"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@quenty/baseobject": "^10.
|
|
31
|
-
"@quenty/brio": "^14.
|
|
32
|
-
"@quenty/ducktype": "^5.
|
|
33
|
-
"@quenty/loader": "^10.
|
|
34
|
-
"@quenty/maid": "^3.
|
|
35
|
-
"@quenty/promise": "^10.
|
|
36
|
-
"@quenty/rx": "^13.
|
|
37
|
-
"@quenty/signal": "^7.
|
|
38
|
-
"@quenty/steputils": "^3.5.
|
|
39
|
-
"@quenty/symbol": "^3.
|
|
40
|
-
"@quenty/valueobject": "^13.
|
|
30
|
+
"@quenty/baseobject": "^10.6.0",
|
|
31
|
+
"@quenty/brio": "^14.8.1",
|
|
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/rx": "^13.8.0",
|
|
37
|
+
"@quenty/signal": "^7.7.0",
|
|
38
|
+
"@quenty/steputils": "^3.5.1",
|
|
39
|
+
"@quenty/symbol": "^3.2.0",
|
|
40
|
+
"@quenty/valueobject": "^13.8.1"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@quenty/blend": "^12.
|
|
43
|
+
"@quenty/blend": "^12.8.1"
|
|
44
44
|
},
|
|
45
45
|
"publishConfig": {
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "539802fea720a92f81ad48d6d5579605d8844d0a"
|
|
49
49
|
}
|
|
@@ -205,7 +205,7 @@ end
|
|
|
205
205
|
@return Observable<number>
|
|
206
206
|
]=]
|
|
207
207
|
function ObservableList:ObserveIndexByKey(key)
|
|
208
|
-
assert(
|
|
208
|
+
assert(Symbol.isSymbol(key), "Bad key")
|
|
209
209
|
|
|
210
210
|
return self._keyIndexObservables:Observe(key, function(sub)
|
|
211
211
|
sub:Fire(self:GetIndexByKey(key))
|
|
@@ -417,9 +417,9 @@ end
|
|
|
417
417
|
@return { T }
|
|
418
418
|
]=]
|
|
419
419
|
function ObservableList:GetList()
|
|
420
|
-
local list =
|
|
421
|
-
for
|
|
422
|
-
|
|
420
|
+
local list = table.create(#self._keyList)
|
|
421
|
+
for index, key in pairs(self._keyList) do
|
|
422
|
+
list[index] = self._contents[key]
|
|
423
423
|
end
|
|
424
424
|
return list
|
|
425
425
|
end
|
|
@@ -184,10 +184,9 @@ function ObservableMap:ObserveAtKeyBrio(key)
|
|
|
184
184
|
assert(key ~= nil, "Bad key")
|
|
185
185
|
|
|
186
186
|
return self:ObserveAtKey(key):Pipe({
|
|
187
|
-
RxBrioUtils.
|
|
188
|
-
RxBrioUtils.where(function(value)
|
|
187
|
+
RxBrioUtils.switchToBrio(function(value)
|
|
189
188
|
return value ~= nil
|
|
190
|
-
end)
|
|
189
|
+
end);
|
|
191
190
|
})
|
|
192
191
|
end
|
|
193
192
|
|
|
@@ -275,7 +274,7 @@ end
|
|
|
275
274
|
@return { TValue }
|
|
276
275
|
]=]
|
|
277
276
|
function ObservableMap:GetValueList()
|
|
278
|
-
local list =
|
|
277
|
+
local list = table.create(self._countValue.Value)
|
|
279
278
|
for _, value in pairs(self._map) do
|
|
280
279
|
table.insert(list, value)
|
|
281
280
|
end
|
|
@@ -287,7 +286,7 @@ end
|
|
|
287
286
|
@return { TKey }
|
|
288
287
|
]=]
|
|
289
288
|
function ObservableMap:GetKeyList()
|
|
290
|
-
local list =
|
|
289
|
+
local list = table.create(self._countValue.Value)
|
|
291
290
|
for key, _ in pairs(self._map) do
|
|
292
291
|
table.insert(list, key)
|
|
293
292
|
end
|
|
@@ -303,7 +302,10 @@ function ObservableMap:ObserveKeyList()
|
|
|
303
302
|
local topMaid = Maid.new()
|
|
304
303
|
|
|
305
304
|
-- TODO: maybe don't allocate as much here?
|
|
306
|
-
local keyList =
|
|
305
|
+
local keyList = table.create(self._countValue.Value)
|
|
306
|
+
for key, _ in pairs(self._map) do
|
|
307
|
+
table.insert(keyList, key)
|
|
308
|
+
end
|
|
307
309
|
|
|
308
310
|
topMaid:GiveTask(self.KeyAdded:Connect(function(addedKey)
|
|
309
311
|
table.insert(keyList, addedKey)
|
|
@@ -318,10 +320,6 @@ function ObservableMap:ObserveKeyList()
|
|
|
318
320
|
sub:Fire(table.clone(keyList))
|
|
319
321
|
end))
|
|
320
322
|
|
|
321
|
-
for key, _ in pairs(self._map) do
|
|
322
|
-
table.insert(keyList, key)
|
|
323
|
-
end
|
|
324
|
-
|
|
325
323
|
sub:Fire(table.clone(keyList))
|
|
326
324
|
|
|
327
325
|
return topMaid
|
|
@@ -27,6 +27,29 @@ function ObservableMapList.new()
|
|
|
27
27
|
self._maid = Maid.new()
|
|
28
28
|
self._observableMapOfLists = self._maid:Add(ObservableMap.new())
|
|
29
29
|
|
|
30
|
+
--[=[
|
|
31
|
+
Fires when an item is added
|
|
32
|
+
@readonly
|
|
33
|
+
@prop ListAdded Signal<TKey>
|
|
34
|
+
@within ObservableMapSet
|
|
35
|
+
]=]
|
|
36
|
+
self.ListAdded = assert(self._observableMapOfLists.KeyAdded, "Bad KeyAdded") -- :Fire(key, set)
|
|
37
|
+
|
|
38
|
+
--[=[
|
|
39
|
+
Fires when an item is removed
|
|
40
|
+
@readonly
|
|
41
|
+
@prop ListRemoved Signal<TKey>
|
|
42
|
+
@within ObservableMapSet
|
|
43
|
+
]=]
|
|
44
|
+
self.ListRemoved = assert(self._observableMapOfLists.KeyRemoved, "Bad KeyRemoved") -- :Fire(key)
|
|
45
|
+
|
|
46
|
+
--[=[
|
|
47
|
+
Fires when the count changes.
|
|
48
|
+
@prop CountChanged RBXScriptSignal
|
|
49
|
+
@within ObservableMap
|
|
50
|
+
]=]
|
|
51
|
+
self.CountChanged = assert(self._observableMapOfLists.CountChanged, "Bad CountChanged")
|
|
52
|
+
|
|
30
53
|
return self
|
|
31
54
|
end
|
|
32
55
|
|
|
@@ -46,19 +69,19 @@ function ObservableMapList:Push(observeKey, entry)
|
|
|
46
69
|
assert(observeKey ~= nil, "Bad observeKey")
|
|
47
70
|
assert(entry ~= nil, "Bad entry")
|
|
48
71
|
|
|
49
|
-
if not Observable.isObservable(observeKey) then
|
|
50
|
-
observeKey = Rx.of(observeKey)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
72
|
local maid = Maid.new()
|
|
54
73
|
|
|
55
|
-
|
|
56
|
-
maid
|
|
74
|
+
if Observable.isObservable(observeKey) then
|
|
75
|
+
maid:GiveTask(observeKey:Subscribe(function(key)
|
|
76
|
+
maid._currentAddValue = nil
|
|
57
77
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
78
|
+
if key ~= nil then
|
|
79
|
+
maid._currentAddValue = self:_addToList(key, entry)
|
|
80
|
+
end
|
|
81
|
+
end))
|
|
82
|
+
else
|
|
83
|
+
maid:GiveTask(self:_addToList(observeKey, entry))
|
|
84
|
+
end
|
|
62
85
|
|
|
63
86
|
-- Ensure self-cleanup when map cleans up
|
|
64
87
|
self._maid[maid] = maid
|
|
@@ -221,18 +244,36 @@ function ObservableMapList:GetListForKey(key)
|
|
|
221
244
|
return self._observableMapOfLists:Get(key)
|
|
222
245
|
end
|
|
223
246
|
|
|
247
|
+
--[=[
|
|
248
|
+
Observes the observable list for the given key
|
|
249
|
+
|
|
250
|
+
@param key TKey
|
|
251
|
+
@return Observable<ObservableList<TValue>>
|
|
252
|
+
]=]
|
|
224
253
|
function ObservableMapList:ObserveList(key)
|
|
225
254
|
assert(key ~= nil, "Bad key")
|
|
226
255
|
|
|
227
256
|
return self._observableMapOfLists:ObserveAtKey(key)
|
|
228
257
|
end
|
|
229
258
|
|
|
259
|
+
--[=[
|
|
260
|
+
Observes the observable list for the given key
|
|
261
|
+
|
|
262
|
+
@param key TKey
|
|
263
|
+
@return Observable<Brio<ObservableList<TValue>>>
|
|
264
|
+
]=]
|
|
230
265
|
function ObservableMapList:ObserveListBrio(key)
|
|
231
266
|
assert(key ~= nil, "Bad key")
|
|
232
267
|
|
|
233
268
|
return self._observableMapOfLists:ObserveAtKeyBrio(key)
|
|
234
269
|
end
|
|
235
270
|
|
|
271
|
+
--[=[
|
|
272
|
+
Observes the number of entries for the given key
|
|
273
|
+
|
|
274
|
+
@param key TKey
|
|
275
|
+
@return Observable<number>
|
|
276
|
+
]=]
|
|
236
277
|
function ObservableMapList:ObserveCountForKey(key)
|
|
237
278
|
assert(key ~= nil, "Bad key")
|
|
238
279
|
|
|
@@ -249,10 +290,6 @@ function ObservableMapList:_addToList(key, entry)
|
|
|
249
290
|
return list:Add(entry)
|
|
250
291
|
end
|
|
251
292
|
|
|
252
|
-
function ObservableMapList:_removeList(list)
|
|
253
|
-
self._maid[list] = nil
|
|
254
|
-
end
|
|
255
|
-
|
|
256
293
|
function ObservableMapList:_getOrCreateList(key)
|
|
257
294
|
local existing = self._observableMapOfLists:Get(key)
|
|
258
295
|
if existing then
|
|
@@ -9,12 +9,10 @@ local require = require(script.Parent.loader).load(script)
|
|
|
9
9
|
|
|
10
10
|
local Maid = require("Maid")
|
|
11
11
|
local Observable = require("Observable")
|
|
12
|
+
local ObservableMap = require("ObservableMap")
|
|
12
13
|
local ObservableSet = require("ObservableSet")
|
|
13
|
-
local Signal = require("Signal")
|
|
14
|
-
local Brio = require("Brio")
|
|
15
|
-
local RxBrioUtils = require("RxBrioUtils")
|
|
16
|
-
local ValueObject = require("ValueObject")
|
|
17
14
|
local Rx = require("Rx")
|
|
15
|
+
local RxBrioUtils = require("RxBrioUtils")
|
|
18
16
|
|
|
19
17
|
local ObservableMapSet = {}
|
|
20
18
|
ObservableMapSet.ClassName = "ObservableMapSet"
|
|
@@ -28,7 +26,7 @@ function ObservableMapSet.new()
|
|
|
28
26
|
local self = setmetatable({}, ObservableMapSet)
|
|
29
27
|
|
|
30
28
|
self._maid = Maid.new()
|
|
31
|
-
self.
|
|
29
|
+
self._observableMapOfSets = self._maid:Add(ObservableMap.new())
|
|
32
30
|
|
|
33
31
|
--[=[
|
|
34
32
|
Fires when an item is added
|
|
@@ -36,7 +34,7 @@ function ObservableMapSet.new()
|
|
|
36
34
|
@prop SetAdded Signal<TKey>
|
|
37
35
|
@within ObservableMapSet
|
|
38
36
|
]=]
|
|
39
|
-
self.SetAdded = self.
|
|
37
|
+
self.SetAdded = assert(self._observableMapOfSets.KeyAdded, "Bad KeyAdded") -- :Fire(key, set)
|
|
40
38
|
|
|
41
39
|
--[=[
|
|
42
40
|
Fires when an item is removed
|
|
@@ -44,9 +42,14 @@ function ObservableMapSet.new()
|
|
|
44
42
|
@prop SetRemoved Signal<TKey>
|
|
45
43
|
@within ObservableMapSet
|
|
46
44
|
]=]
|
|
47
|
-
self.SetRemoved = self.
|
|
45
|
+
self.SetRemoved = assert(self._observableMapOfSets.KeyRemoved, "Bad KeyRemoved") -- :Fire(key)
|
|
48
46
|
|
|
49
|
-
|
|
47
|
+
--[=[
|
|
48
|
+
Fires when the count changes.
|
|
49
|
+
@prop CountChanged RBXScriptSignal
|
|
50
|
+
@within ObservableMap
|
|
51
|
+
]=]
|
|
52
|
+
self.CountChanged = assert(self._observableMapOfSets.CountChanged, "Bad CountChanged")
|
|
50
53
|
|
|
51
54
|
return self
|
|
52
55
|
end
|
|
@@ -68,31 +71,19 @@ function ObservableMapSet:Push(observeKey, entry)
|
|
|
68
71
|
assert(observeKey ~= nil, "Bad observeKey")
|
|
69
72
|
assert(entry ~= nil, "Bad entry")
|
|
70
73
|
|
|
71
|
-
if not Observable.isObservable(observeKey) then
|
|
72
|
-
observeKey = Rx.of(observeKey)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
74
|
local maid = Maid.new()
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
self:_removeFromObservableSet(lastKey, entry)
|
|
81
|
-
end
|
|
82
|
-
lastKey = nil
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
maid:GiveTask(observeKey:Subscribe(function(key)
|
|
86
|
-
removeLastEntry()
|
|
76
|
+
if Observable.isObservable(observeKey) then
|
|
77
|
+
maid:GiveTask(observeKey:Subscribe(function(key)
|
|
78
|
+
maid._currentAddValue = nil
|
|
87
79
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
maid:GiveTask(removeLastEntry)
|
|
80
|
+
if key ~= nil then
|
|
81
|
+
maid._currentAddValue = self:_addToSet(key, entry)
|
|
82
|
+
end
|
|
83
|
+
end))
|
|
84
|
+
else
|
|
85
|
+
maid:GiveTask(self:_addToSet(observeKey, entry))
|
|
86
|
+
end
|
|
96
87
|
|
|
97
88
|
-- Ensure self-cleanup when map cleans up
|
|
98
89
|
self._maid[maid] = maid
|
|
@@ -131,12 +122,8 @@ end
|
|
|
131
122
|
Gets a list of all keys.
|
|
132
123
|
@return { TKey }
|
|
133
124
|
]=]
|
|
134
|
-
function ObservableMapSet:
|
|
135
|
-
|
|
136
|
-
for key, _ in pairs(self._observableSetMap) do
|
|
137
|
-
table.insert(list, key)
|
|
138
|
-
end
|
|
139
|
-
return list
|
|
125
|
+
function ObservableMapSet:ObserveKeyList()
|
|
126
|
+
return self._observableMapOfSets:GetKeyList()
|
|
140
127
|
end
|
|
141
128
|
|
|
142
129
|
--[=[
|
|
@@ -144,33 +131,15 @@ end
|
|
|
144
131
|
@return Observable<{ TKey }>
|
|
145
132
|
]=]
|
|
146
133
|
function ObservableMapSet:ObserveKeyList()
|
|
147
|
-
return
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
-- TODO: maybe don't allocate as much here?
|
|
151
|
-
local keyList = {}
|
|
152
|
-
|
|
153
|
-
topMaid:GiveTask(self.SetAdded:Connect(function(addedKey)
|
|
154
|
-
table.insert(keyList, addedKey)
|
|
155
|
-
sub:Fire(table.clone(keyList))
|
|
156
|
-
end))
|
|
157
|
-
|
|
158
|
-
topMaid:GiveTask(self.SetRemoved:Connect(function(removedKey)
|
|
159
|
-
local index = table.find(keyList, removedKey)
|
|
160
|
-
if index then
|
|
161
|
-
table.remove(keyList, index)
|
|
162
|
-
end
|
|
163
|
-
sub:Fire(table.clone(keyList))
|
|
164
|
-
end))
|
|
165
|
-
|
|
166
|
-
for key, _ in pairs(self._observableSetMap) do
|
|
167
|
-
table.insert(keyList, key)
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
sub:Fire(table.clone(keyList))
|
|
134
|
+
return self._observableMapOfSets:ObserveKeyList()
|
|
135
|
+
end
|
|
171
136
|
|
|
172
|
-
|
|
173
|
-
|
|
137
|
+
--[=[
|
|
138
|
+
Observes all keys in the map
|
|
139
|
+
@return Observable<Brio<TKey>>
|
|
140
|
+
]=]
|
|
141
|
+
function ObservableMapSet:ObserveKeysBrio()
|
|
142
|
+
return self._observableMapOfSets:ObserveKeysBrio()
|
|
174
143
|
end
|
|
175
144
|
|
|
176
145
|
--[=[
|
|
@@ -178,7 +147,7 @@ end
|
|
|
178
147
|
@return number
|
|
179
148
|
]=]
|
|
180
149
|
function ObservableMapSet:GetSetCount()
|
|
181
|
-
return self.
|
|
150
|
+
return self._observableMapOfSets:GetCount()
|
|
182
151
|
end
|
|
183
152
|
|
|
184
153
|
--[=[
|
|
@@ -186,7 +155,7 @@ end
|
|
|
186
155
|
@return Observable<number>
|
|
187
156
|
]=]
|
|
188
157
|
function ObservableMapSet:ObserveSetCount()
|
|
189
|
-
return self.
|
|
158
|
+
return self._observableMapOfSets:ObserveCount()
|
|
190
159
|
end
|
|
191
160
|
|
|
192
161
|
--[=[
|
|
@@ -197,49 +166,26 @@ end
|
|
|
197
166
|
function ObservableMapSet:ObserveItemsForKeyBrio(key)
|
|
198
167
|
assert(key ~= nil, "Bad key")
|
|
199
168
|
|
|
200
|
-
return
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
local function connect()
|
|
204
|
-
local maid = Maid.new()
|
|
205
|
-
|
|
206
|
-
local set = self._observableSetMap[key]
|
|
169
|
+
return self._observableMapOfSets:ObserveAtKeyBrio(key):Pipe({
|
|
170
|
+
RxBrioUtils.switchMapBrio(function(set)
|
|
207
171
|
if set then
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
172
|
+
return set:ObserveItemsBrio()
|
|
173
|
+
else
|
|
174
|
+
return Rx.EMPTY
|
|
211
175
|
end
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
topMaid:GiveTask(self.SetAdded:Connect(function(addedKey)
|
|
217
|
-
if addedKey == key then
|
|
218
|
-
connect()
|
|
219
|
-
end
|
|
220
|
-
end))
|
|
221
|
-
|
|
222
|
-
topMaid:GiveTask(self.SetRemoved:Connect(function(removedKey)
|
|
223
|
-
if removedKey == key then
|
|
224
|
-
connect()
|
|
225
|
-
end
|
|
226
|
-
end))
|
|
227
|
-
|
|
228
|
-
connect()
|
|
229
|
-
|
|
230
|
-
return topMaid
|
|
231
|
-
end)
|
|
176
|
+
end);
|
|
177
|
+
})
|
|
232
178
|
end
|
|
233
179
|
|
|
234
180
|
--[=[
|
|
235
181
|
Gets the first item for the given key
|
|
236
182
|
@param key TKey
|
|
237
|
-
@return TValue
|
|
183
|
+
@return TValue | nil
|
|
238
184
|
]=]
|
|
239
185
|
function ObservableMapSet:GetFirstItemForKey(key)
|
|
240
186
|
assert(key ~= nil, "Bad key")
|
|
241
187
|
|
|
242
|
-
local observableSet = self
|
|
188
|
+
local observableSet = self:GetObservableSetForKey(key)
|
|
243
189
|
if not observableSet then
|
|
244
190
|
return nil
|
|
245
191
|
end
|
|
@@ -255,7 +201,7 @@ end
|
|
|
255
201
|
function ObservableMapSet:GetListForKey(key)
|
|
256
202
|
assert(key ~= nil, "Bad key")
|
|
257
203
|
|
|
258
|
-
local observableSet = self
|
|
204
|
+
local observableSet = self:GetObservableSetForKey(key)
|
|
259
205
|
if not observableSet then
|
|
260
206
|
return {}
|
|
261
207
|
end
|
|
@@ -271,45 +217,27 @@ end
|
|
|
271
217
|
function ObservableMapSet:GetObservableSetForKey(key)
|
|
272
218
|
assert(key ~= nil, "Bad key")
|
|
273
219
|
|
|
274
|
-
return self.
|
|
220
|
+
return self._observableMapOfSets:Get(key)
|
|
275
221
|
end
|
|
276
222
|
|
|
223
|
+
--[=[
|
|
224
|
+
Observes the observable set for the given key
|
|
225
|
+
|
|
226
|
+
@param key TKey
|
|
227
|
+
@return Observable<Brio<ObservableSet<TValue>>>
|
|
228
|
+
]=]
|
|
277
229
|
function ObservableMapSet:ObserveSetBrio(key)
|
|
278
230
|
assert(key ~= nil, "Bad key")
|
|
279
231
|
|
|
280
|
-
return
|
|
281
|
-
local topMaid = Maid.new()
|
|
282
|
-
|
|
283
|
-
local function connect()
|
|
284
|
-
local brio
|
|
285
|
-
|
|
286
|
-
local set = self._observableSetMap[key]
|
|
287
|
-
if set then
|
|
288
|
-
brio = Brio.new(set)
|
|
289
|
-
sub:Fire(brio)
|
|
290
|
-
end
|
|
291
|
-
|
|
292
|
-
topMaid._current = brio
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
topMaid:GiveTask(self.SetAdded:Connect(function(addedKey)
|
|
296
|
-
if addedKey == key then
|
|
297
|
-
connect()
|
|
298
|
-
end
|
|
299
|
-
end))
|
|
300
|
-
|
|
301
|
-
topMaid:GiveTask(self.SetRemoved:Connect(function(removedKey)
|
|
302
|
-
if removedKey == key then
|
|
303
|
-
connect()
|
|
304
|
-
end
|
|
305
|
-
end))
|
|
306
|
-
|
|
307
|
-
connect()
|
|
308
|
-
|
|
309
|
-
return topMaid
|
|
310
|
-
end)
|
|
232
|
+
return self._observableMapOfSets:ObserveAtKeyBrio(key)
|
|
311
233
|
end
|
|
312
234
|
|
|
235
|
+
--[=[
|
|
236
|
+
Observes the number of entries for the given key
|
|
237
|
+
|
|
238
|
+
@param key TKey
|
|
239
|
+
@return Observable<number>
|
|
240
|
+
]=]
|
|
313
241
|
function ObservableMapSet:ObserveCountForKey(key)
|
|
314
242
|
assert(key ~= nil, "Bad key")
|
|
315
243
|
|
|
@@ -321,66 +249,30 @@ function ObservableMapSet:ObserveCountForKey(key)
|
|
|
321
249
|
})
|
|
322
250
|
end
|
|
323
251
|
|
|
324
|
-
function ObservableMapSet:_addToObservableSet(key, entry)
|
|
325
|
-
local set = self:_getOrCreateObservableSet(key)
|
|
326
|
-
set:Add(entry)
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
function ObservableMapSet:_removeFromObservableSet(key, entry)
|
|
330
|
-
local set = self._observableSetMap[key]
|
|
331
|
-
if not set then
|
|
332
|
-
return
|
|
333
|
-
end
|
|
334
|
-
|
|
335
|
-
-- This happens when we're cleaning up sometimes
|
|
336
|
-
if not set.Destroy then
|
|
337
|
-
return
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
if set:Contains(entry) then
|
|
341
|
-
set:Remove(entry)
|
|
342
|
-
if set:GetCount() == 0 then
|
|
343
|
-
self:_removeObservableSet(key)
|
|
344
|
-
end
|
|
345
|
-
end
|
|
346
|
-
end
|
|
347
|
-
|
|
348
|
-
function ObservableMapSet:_removeObservableSet(key)
|
|
349
|
-
local set = self._observableSetMap[key]
|
|
350
|
-
if set then
|
|
351
|
-
self._observableSetMap[key] = nil
|
|
352
252
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
if self.SetRemoved.Destroy then
|
|
357
|
-
self.SetRemoved:Fire(key)
|
|
358
|
-
end
|
|
359
|
-
|
|
360
|
-
if self._setCount.Destroy then
|
|
361
|
-
self._setCount.Value = self._setCount.Value - 1
|
|
362
|
-
end
|
|
363
|
-
end
|
|
253
|
+
function ObservableMapSet:_addToSet(key, entry)
|
|
254
|
+
local set = self:_getOrCreateSet(key)
|
|
255
|
+
return set:Add(entry)
|
|
364
256
|
end
|
|
365
257
|
|
|
366
|
-
function ObservableMapSet:
|
|
367
|
-
|
|
368
|
-
|
|
258
|
+
function ObservableMapSet:_getOrCreateSet(key)
|
|
259
|
+
local existing = self._observableMapOfSets:Get(key)
|
|
260
|
+
if existing then
|
|
261
|
+
return existing
|
|
369
262
|
end
|
|
370
263
|
|
|
371
264
|
local maid = Maid.new()
|
|
372
|
-
local set = ObservableSet.new()
|
|
373
|
-
maid:GiveTask(set)
|
|
374
|
-
|
|
375
|
-
self._observableSetMap[key] = set
|
|
265
|
+
local set = maid:Add(ObservableSet.new(nil))
|
|
376
266
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
end
|
|
267
|
+
maid:GiveTask(set.CountChanged:Connect(function(count)
|
|
268
|
+
if count <= 0 then
|
|
269
|
+
self._maid[set] = nil
|
|
270
|
+
end
|
|
271
|
+
end))
|
|
382
272
|
|
|
273
|
+
maid:GiveTask(self._observableMapOfSets:Set(key, set))
|
|
383
274
|
self._maid[set] = maid
|
|
275
|
+
|
|
384
276
|
return set
|
|
385
277
|
end
|
|
386
278
|
|
|
@@ -58,11 +58,8 @@ function ObservableSortedList.new(isReversed, compare)
|
|
|
58
58
|
|
|
59
59
|
self._keyList = {} -- { [number]: Symbol } -- immutable
|
|
60
60
|
|
|
61
|
-
self._indexObservers = ObservableSubscriptionTable.new()
|
|
62
|
-
self._maid:
|
|
63
|
-
|
|
64
|
-
self._contentIndexObservers = ObservableSubscriptionTable.new()
|
|
65
|
-
self._maid:GiveTask(self._contentIndexObservers)
|
|
61
|
+
self._indexObservers = self._maid:Add(ObservableSubscriptionTable.new())
|
|
62
|
+
self._contentIndexObservers = self._maid:Add(ObservableSubscriptionTable.new())
|
|
66
63
|
|
|
67
64
|
self._sortValue = {} -- { [Symbol]: number }
|
|
68
65
|
self._contents = {} -- { [Symbol]: T }
|
|
@@ -127,6 +124,16 @@ function ObservableSortedList:Observe()
|
|
|
127
124
|
})
|
|
128
125
|
end
|
|
129
126
|
|
|
127
|
+
function ObservableSortedList:Contains(value)
|
|
128
|
+
-- TODO: Binary search
|
|
129
|
+
for _, item in pairs(self._contents) do
|
|
130
|
+
if item == value then
|
|
131
|
+
return true
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
return false
|
|
136
|
+
end
|
|
130
137
|
|
|
131
138
|
--[=[
|
|
132
139
|
Returns whether the value is an observable list
|
|
@@ -230,7 +237,7 @@ end
|
|
|
230
237
|
@return Observable<number>
|
|
231
238
|
]=]
|
|
232
239
|
function ObservableSortedList:ObserveIndexByKey(key)
|
|
233
|
-
assert(
|
|
240
|
+
assert(Symbol.isSymbol(key), "Bad key")
|
|
234
241
|
|
|
235
242
|
return Observable.new(function(sub)
|
|
236
243
|
local maid = Maid.new()
|
|
@@ -289,9 +296,9 @@ end
|
|
|
289
296
|
@return { T }
|
|
290
297
|
]=]
|
|
291
298
|
function ObservableSortedList:GetList()
|
|
292
|
-
local list =
|
|
293
|
-
for
|
|
294
|
-
|
|
299
|
+
local list = table.create(#self._keyList)
|
|
300
|
+
for index, key in pairs(self._keyList) do
|
|
301
|
+
list[index] = self._contents[key]
|
|
295
302
|
end
|
|
296
303
|
return list
|
|
297
304
|
end
|
|
@@ -307,41 +314,27 @@ end
|
|
|
307
314
|
--[=[
|
|
308
315
|
Adds the item to the list at the specified index
|
|
309
316
|
@param item T
|
|
310
|
-
@param observeValue Observable<Comparable>
|
|
317
|
+
@param observeValue Observable<Comparable> | Comparable
|
|
311
318
|
@return callback -- Call to remove
|
|
312
319
|
]=]
|
|
313
320
|
function ObservableSortedList:Add(item, observeValue)
|
|
314
321
|
assert(item ~= nil, "Bad item")
|
|
315
|
-
assert(Observable.isObservable(observeValue), "Bad observeValue")
|
|
322
|
+
assert(Observable.isObservable(observeValue) or observeValue ~= nil, "Bad observeValue")
|
|
316
323
|
|
|
317
324
|
local key = Symbol.named("entryKey")
|
|
318
325
|
local maid = Maid.new()
|
|
319
326
|
|
|
320
327
|
self._contents[key] = item
|
|
321
328
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
else
|
|
332
|
-
local observableSubs = self._keyObservables[key]
|
|
333
|
-
|
|
334
|
-
-- calling this also may unsubscribe some observables.
|
|
335
|
-
self:_removeItemByKey(key, item)
|
|
336
|
-
|
|
337
|
-
if observableSubs then
|
|
338
|
-
-- fire nil index
|
|
339
|
-
self:_fireSubs(observableSubs, nil)
|
|
340
|
-
end
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
self:_debugVerifyIntegrity()
|
|
344
|
-
end))
|
|
329
|
+
if Observable.isObservable(observeValue) then
|
|
330
|
+
maid:GiveTask(observeValue:Subscribe(function(sortValue)
|
|
331
|
+
self:_assignSortValue(key, item, sortValue)
|
|
332
|
+
end))
|
|
333
|
+
elseif observeValue ~= nil then
|
|
334
|
+
self:_assignSortValue(key, item, observeValue)
|
|
335
|
+
else
|
|
336
|
+
error("Bad observeValue")
|
|
337
|
+
end
|
|
345
338
|
|
|
346
339
|
maid:GiveTask(function()
|
|
347
340
|
local observableSubs = self._keyObservables[key]
|
|
@@ -365,6 +358,31 @@ function ObservableSortedList:Add(item, observeValue)
|
|
|
365
358
|
end
|
|
366
359
|
end
|
|
367
360
|
|
|
361
|
+
function ObservableSortedList:_assignSortValue(key, item, sortValue)
|
|
362
|
+
self:_debugVerifyIntegrity()
|
|
363
|
+
|
|
364
|
+
if sortValue ~= nil then
|
|
365
|
+
local currentIndex = self._indexes[key]
|
|
366
|
+
local targetIndex = self:_findCorrectIndex(sortValue, currentIndex)
|
|
367
|
+
|
|
368
|
+
self._sortValue[key] = sortValue
|
|
369
|
+
self:_updateIndex(key, item, targetIndex, sortValue)
|
|
370
|
+
else
|
|
371
|
+
local observableSubs = self._keyObservables[key]
|
|
372
|
+
|
|
373
|
+
-- calling this also may unsubscribe some observables.
|
|
374
|
+
self:_removeItemByKey(key, item)
|
|
375
|
+
|
|
376
|
+
if observableSubs then
|
|
377
|
+
-- fire nil index
|
|
378
|
+
self:_fireSubs(observableSubs, nil)
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
self:_debugVerifyIntegrity()
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
|
|
368
386
|
--[=[
|
|
369
387
|
Gets the current item at the index, or nil if it is not defined.
|
|
370
388
|
@param index number
|
|
@@ -446,11 +464,11 @@ function ObservableSortedList:_updateIndex(key, item, newIndex)
|
|
|
446
464
|
error("Bad state")
|
|
447
465
|
end
|
|
448
466
|
|
|
449
|
-
local itemAdded = {
|
|
467
|
+
local itemAdded = table.freeze({
|
|
450
468
|
key = key;
|
|
451
469
|
newIndex = newIndex;
|
|
452
470
|
item = item;
|
|
453
|
-
}
|
|
471
|
+
})
|
|
454
472
|
|
|
455
473
|
-- ensure ourself is considered changed
|
|
456
474
|
table.insert(changed, itemAdded)
|
|
@@ -493,11 +511,11 @@ function ObservableSortedList:_removeItemByKey(key, item)
|
|
|
493
511
|
end
|
|
494
512
|
self._keyList[n] = nil
|
|
495
513
|
|
|
496
|
-
local itemRemoved = {
|
|
514
|
+
local itemRemoved = table.freeze({
|
|
497
515
|
key = key;
|
|
498
516
|
item = item;
|
|
499
517
|
previousIndex = index;
|
|
500
|
-
}
|
|
518
|
+
})
|
|
501
519
|
|
|
502
520
|
-- TODO: Defer item removed as a changed event?
|
|
503
521
|
|