@quenty/observablecollection 12.20.0 → 12.20.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 +11 -0
- package/package.json +15 -15
- package/src/Shared/ObservableCountingMap.lua +102 -81
- package/src/Shared/ObservableList.lua +91 -70
- package/src/Shared/ObservableMap.lua +100 -78
- package/src/Shared/ObservableMapList.lua +2 -2
- package/src/Shared/ObservableMapSet.lua +83 -41
- package/src/Shared/ObservableSet.lua +61 -34
- package/src/Shared/SortedList/ObservableSortedList.lua +128 -58
- package/src/Shared/SortedList/ObservableSortedList.story.lua +1 -1
- package/src/Shared/SortedList/SortFunctionUtils.lua +25 -8
- package/src/Shared/SortedList/SortedNode.lua +231 -116
- package/src/Shared/SortedList/SortedNodeValue.lua +17 -6
- package/src/Shared/Utils/ListIndexUtils.lua +9 -2
- package/test/scripts/Server/ServerMain.server.lua +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
A list that can be observed for blend and other components
|
|
3
4
|
@class ObservableList
|
|
@@ -15,16 +16,53 @@ local Symbol = require("Symbol")
|
|
|
15
16
|
local ValueObject = require("ValueObject")
|
|
16
17
|
local DuckTypeUtils = require("DuckTypeUtils")
|
|
17
18
|
local ListIndexUtils = require("ListIndexUtils")
|
|
19
|
+
local _SortFunctionUtils = require("SortFunctionUtils")
|
|
18
20
|
|
|
19
21
|
local ObservableList = {}
|
|
20
22
|
ObservableList.ClassName = "ObservableList"
|
|
21
23
|
ObservableList.__index = ObservableList
|
|
22
24
|
|
|
25
|
+
export type ObservableList<T> = typeof(setmetatable(
|
|
26
|
+
{} :: {
|
|
27
|
+
_maid: Maid.Maid,
|
|
28
|
+
_keyList: { Symbol.Symbol },
|
|
29
|
+
_contents: { [Symbol.Symbol]: T },
|
|
30
|
+
_indexes: { [Symbol.Symbol]: number },
|
|
31
|
+
_indexObservers: ObservableSubscriptionTable.ObservableSubscriptionTable<T?>,
|
|
32
|
+
_keyIndexObservables: ObservableSubscriptionTable.ObservableSubscriptionTable<number?>,
|
|
33
|
+
_countValue: ValueObject.ValueObject<number>,
|
|
34
|
+
|
|
35
|
+
--[=[
|
|
36
|
+
Fires when an item is added
|
|
37
|
+
@readonly
|
|
38
|
+
@prop ItemAdded Signal<T, number, Symbol>
|
|
39
|
+
@within ObservableList
|
|
40
|
+
]=]
|
|
41
|
+
ItemAdded: Signal.Signal<T, number, Symbol.Symbol>,
|
|
42
|
+
|
|
43
|
+
--[=[
|
|
44
|
+
Fires when an item is removed.
|
|
45
|
+
@readonly
|
|
46
|
+
@prop ItemRemoved Signal<T, Symbol>
|
|
47
|
+
@within ObservableList
|
|
48
|
+
]=]
|
|
49
|
+
ItemRemoved: Signal.Signal<T, Symbol.Symbol>,
|
|
50
|
+
|
|
51
|
+
--[=[
|
|
52
|
+
Fires when the count changes.
|
|
53
|
+
@prop CountChanged Signal.Signal<number>,
|
|
54
|
+
@within ObservableList
|
|
55
|
+
]=]
|
|
56
|
+
CountChanged: Signal.Signal<number>,
|
|
57
|
+
},
|
|
58
|
+
ObservableList
|
|
59
|
+
))
|
|
60
|
+
|
|
23
61
|
--[=[
|
|
24
62
|
Constructs a new ObservableList
|
|
25
63
|
@return ObservableList<T>
|
|
26
64
|
]=]
|
|
27
|
-
function ObservableList.new()
|
|
65
|
+
function ObservableList.new<T>(): ObservableList<T>
|
|
28
66
|
local self = setmetatable({}, ObservableList)
|
|
29
67
|
|
|
30
68
|
self._maid = Maid.new()
|
|
@@ -37,30 +75,11 @@ function ObservableList.new()
|
|
|
37
75
|
self._keyIndexObservables = self._maid:Add(ObservableSubscriptionTable.new())
|
|
38
76
|
self._countValue = self._maid:Add(ValueObject.new(0, "number"))
|
|
39
77
|
|
|
40
|
-
--[=[
|
|
41
|
-
Fires when an item is added
|
|
42
|
-
@readonly
|
|
43
|
-
@prop ItemAdded Signal<T, number, Symbol>
|
|
44
|
-
@within ObservableList
|
|
45
|
-
]=]
|
|
46
78
|
self.ItemAdded = self._maid:Add(Signal.new())
|
|
47
|
-
|
|
48
|
-
--[=[
|
|
49
|
-
Fires when an item is removed.
|
|
50
|
-
@readonly
|
|
51
|
-
@prop ItemRemoved Signal<T, Symbol>
|
|
52
|
-
@within ObservableList
|
|
53
|
-
]=]
|
|
54
79
|
self.ItemRemoved = self._maid:Add(Signal.new())
|
|
55
|
-
|
|
56
|
-
--[=[
|
|
57
|
-
Fires when the count changes.
|
|
58
|
-
@prop CountChanged RBXScriptSignal
|
|
59
|
-
@within ObservableList
|
|
60
|
-
]=]
|
|
61
80
|
self.CountChanged = self._countValue.Changed
|
|
62
81
|
|
|
63
|
-
return self
|
|
82
|
+
return self :: any
|
|
64
83
|
end
|
|
65
84
|
|
|
66
85
|
--[=[
|
|
@@ -68,7 +87,7 @@ end
|
|
|
68
87
|
@param value any
|
|
69
88
|
@return boolean
|
|
70
89
|
]=]
|
|
71
|
-
function ObservableList.isObservableList(value)
|
|
90
|
+
function ObservableList.isObservableList(value: any): boolean
|
|
72
91
|
return DuckTypeUtils.isImplementation(ObservableList, value)
|
|
73
92
|
end
|
|
74
93
|
|
|
@@ -77,7 +96,7 @@ end
|
|
|
77
96
|
|
|
78
97
|
@return Observable<{ T }>
|
|
79
98
|
]=]
|
|
80
|
-
function ObservableList
|
|
99
|
+
function ObservableList.Observe<T>(self: ObservableList<T>): Observable.Observable<{ T }>
|
|
81
100
|
return Observable.new(function(sub)
|
|
82
101
|
local maid = Maid.new()
|
|
83
102
|
|
|
@@ -96,7 +115,7 @@ function ObservableList:Observe()
|
|
|
96
115
|
maid:GiveTask(self.ItemRemoved:Connect(queueFire))
|
|
97
116
|
|
|
98
117
|
return maid
|
|
99
|
-
end)
|
|
118
|
+
end) :: any
|
|
100
119
|
end
|
|
101
120
|
|
|
102
121
|
--[=[
|
|
@@ -104,7 +123,7 @@ end
|
|
|
104
123
|
|
|
105
124
|
@return (T) -> ((T, nextIndex: any) -> ...any, T?)
|
|
106
125
|
]=]
|
|
107
|
-
function ObservableList
|
|
126
|
+
function ObservableList.__iter<T>(self: ObservableList<T>): _SortFunctionUtils.WrappedIterator<number, T>
|
|
108
127
|
return coroutine.wrap(function()
|
|
109
128
|
for index, value in self._keyList do
|
|
110
129
|
coroutine.yield(index, self._contents[value])
|
|
@@ -116,11 +135,11 @@ end
|
|
|
116
135
|
Observes all items in the list
|
|
117
136
|
@return Observable<Brio<T>>
|
|
118
137
|
]=]
|
|
119
|
-
function ObservableList
|
|
138
|
+
function ObservableList.ObserveItemsBrio<T>(self: ObservableList<T>): Observable.Observable<Brio.Brio<T>>
|
|
120
139
|
return Observable.new(function(sub)
|
|
121
140
|
local maid = Maid.new()
|
|
122
141
|
|
|
123
|
-
local function handleItem(item, _index, includeKey)
|
|
142
|
+
local function handleItem(item: T, _index, includeKey)
|
|
124
143
|
local brio = Brio.new(item, includeKey)
|
|
125
144
|
maid[includeKey] = brio
|
|
126
145
|
sub:Fire(brio)
|
|
@@ -131,18 +150,18 @@ function ObservableList:ObserveItemsBrio()
|
|
|
131
150
|
maid[includeKey] = nil
|
|
132
151
|
end))
|
|
133
152
|
|
|
134
|
-
for index, key in
|
|
153
|
+
for index, key in self._keyList do
|
|
135
154
|
handleItem(self._contents[key], index, key)
|
|
136
155
|
end
|
|
137
156
|
|
|
138
|
-
self._maid[sub] = maid
|
|
157
|
+
self._maid[sub :: any] = maid
|
|
139
158
|
maid:GiveTask(function()
|
|
140
|
-
self._maid[sub] = nil
|
|
159
|
+
self._maid[sub :: any] = nil
|
|
141
160
|
sub:Complete()
|
|
142
161
|
end)
|
|
143
162
|
|
|
144
163
|
return maid
|
|
145
|
-
end)
|
|
164
|
+
end) :: any
|
|
146
165
|
end
|
|
147
166
|
|
|
148
167
|
--[=[
|
|
@@ -150,14 +169,14 @@ end
|
|
|
150
169
|
index is removed.
|
|
151
170
|
|
|
152
171
|
@param indexToObserve number
|
|
153
|
-
@return Observable<number
|
|
172
|
+
@return Observable<number?>
|
|
154
173
|
]=]
|
|
155
|
-
function ObservableList
|
|
174
|
+
function ObservableList.ObserveIndex<T>(self: ObservableList<T>, indexToObserve: number): Observable.Observable<number?>
|
|
156
175
|
assert(type(indexToObserve) == "number", "Bad indexToObserve")
|
|
157
176
|
|
|
158
177
|
local key = self._keyList[indexToObserve]
|
|
159
178
|
if not key then
|
|
160
|
-
error(string.format("No entry at index %
|
|
179
|
+
error(string.format("No entry at index %d, cannot observe changes", indexToObserve))
|
|
161
180
|
end
|
|
162
181
|
|
|
163
182
|
return self:ObserveIndexByKey(key)
|
|
@@ -175,7 +194,7 @@ end
|
|
|
175
194
|
@param indexToObserve number
|
|
176
195
|
@return Observable<T?>
|
|
177
196
|
]=]
|
|
178
|
-
function ObservableList
|
|
197
|
+
function ObservableList.ObserveAtIndex<T>(self: ObservableList<T>, indexToObserve: number): Observable.Observable<T?>
|
|
179
198
|
assert(type(indexToObserve) == "number", "Bad indexToObserve")
|
|
180
199
|
|
|
181
200
|
return self._indexObservers:Observe(indexToObserve, function(sub)
|
|
@@ -190,13 +209,16 @@ end
|
|
|
190
209
|
@param indexToObserve number
|
|
191
210
|
@return Observable<Brio<T>>
|
|
192
211
|
]=]
|
|
193
|
-
function ObservableList
|
|
212
|
+
function ObservableList.ObserveAtIndexBrio<T>(
|
|
213
|
+
self: ObservableList<T>,
|
|
214
|
+
indexToObserve: number
|
|
215
|
+
): Observable.Observable<Brio.Brio<T>>
|
|
194
216
|
assert(type(indexToObserve) == "number", "Bad indexToObserve")
|
|
195
217
|
|
|
196
218
|
return self:ObserveAtIndex(indexToObserve):Pipe({
|
|
197
|
-
RxBrioUtils.toBrio()
|
|
198
|
-
RxBrioUtils.onlyLastBrioSurvives()
|
|
199
|
-
})
|
|
219
|
+
RxBrioUtils.toBrio(),
|
|
220
|
+
RxBrioUtils.onlyLastBrioSurvives(),
|
|
221
|
+
}) :: any
|
|
200
222
|
end
|
|
201
223
|
|
|
202
224
|
--[=[
|
|
@@ -205,8 +227,8 @@ end
|
|
|
205
227
|
@param value T
|
|
206
228
|
@return boolean
|
|
207
229
|
]=]
|
|
208
|
-
function ObservableList
|
|
209
|
-
for key, item in
|
|
230
|
+
function ObservableList.RemoveFirst<T>(self: ObservableList<T>, value: T): boolean
|
|
231
|
+
for key, item in self._contents do
|
|
210
232
|
if item == value then
|
|
211
233
|
self:RemoveByKey(key)
|
|
212
234
|
return true
|
|
@@ -217,11 +239,11 @@ function ObservableList:RemoveFirst(value)
|
|
|
217
239
|
end
|
|
218
240
|
|
|
219
241
|
--[=[
|
|
220
|
-
Returns an
|
|
242
|
+
Returns an ValueObject that represents the CountValue
|
|
221
243
|
|
|
222
|
-
@return
|
|
244
|
+
@return ValueObject<number>
|
|
223
245
|
]=]
|
|
224
|
-
function ObservableList
|
|
246
|
+
function ObservableList.GetCountValue<T>(self: ObservableList<T>): ValueObject.ValueObject<number>
|
|
225
247
|
return self._countValue
|
|
226
248
|
end
|
|
227
249
|
|
|
@@ -230,23 +252,23 @@ end
|
|
|
230
252
|
key is removed.
|
|
231
253
|
|
|
232
254
|
@param key Symbol
|
|
233
|
-
@return Observable<number
|
|
255
|
+
@return Observable<number?>
|
|
234
256
|
]=]
|
|
235
|
-
function ObservableList
|
|
257
|
+
function ObservableList.ObserveIndexByKey<T>(self: ObservableList<T>, key: Symbol.Symbol): Observable.Observable<number?>
|
|
236
258
|
assert(Symbol.isSymbol(key), "Bad key")
|
|
237
259
|
|
|
238
260
|
return self._keyIndexObservables:Observe(key, function(sub)
|
|
239
261
|
sub:Fire(self:GetIndexByKey(key))
|
|
240
|
-
end)
|
|
262
|
+
end) :: any
|
|
241
263
|
end
|
|
242
264
|
|
|
243
265
|
--[=[
|
|
244
266
|
Gets the current index from the key
|
|
245
267
|
|
|
246
268
|
@param key Symbol
|
|
247
|
-
@return number
|
|
269
|
+
@return number?
|
|
248
270
|
]=]
|
|
249
|
-
function ObservableList
|
|
271
|
+
function ObservableList.GetIndexByKey<T>(self: ObservableList<T>, key: Symbol.Symbol): number?
|
|
250
272
|
local currentIndex = self._indexes[key]
|
|
251
273
|
if currentIndex then
|
|
252
274
|
return currentIndex
|
|
@@ -259,7 +281,7 @@ end
|
|
|
259
281
|
Gets the count of items in the list
|
|
260
282
|
@return number
|
|
261
283
|
]=]
|
|
262
|
-
function ObservableList
|
|
284
|
+
function ObservableList.GetCount<T>(self: ObservableList<T>): number
|
|
263
285
|
return self._countValue.Value or 0
|
|
264
286
|
end
|
|
265
287
|
|
|
@@ -269,7 +291,7 @@ ObservableList.__len = ObservableList.GetCount
|
|
|
269
291
|
Observes the count of the list
|
|
270
292
|
@return Observable<number>
|
|
271
293
|
]=]
|
|
272
|
-
function ObservableList
|
|
294
|
+
function ObservableList.ObserveCount<T>(self: ObservableList<T>): Observable.Observable<number>
|
|
273
295
|
return self._countValue:Observe()
|
|
274
296
|
end
|
|
275
297
|
|
|
@@ -278,7 +300,7 @@ end
|
|
|
278
300
|
@param item T
|
|
279
301
|
@return callback -- Call to remove
|
|
280
302
|
]=]
|
|
281
|
-
function ObservableList
|
|
303
|
+
function ObservableList.Add<T>(self: ObservableList<T>, item: T): () -> ()
|
|
282
304
|
return self:InsertAt(item, #self._keyList + 1)
|
|
283
305
|
end
|
|
284
306
|
|
|
@@ -287,7 +309,7 @@ end
|
|
|
287
309
|
@param index number
|
|
288
310
|
@return T?
|
|
289
311
|
]=]
|
|
290
|
-
function ObservableList
|
|
312
|
+
function ObservableList.Get<T>(self: ObservableList<T>, index: number): T?
|
|
291
313
|
assert(type(index) == "number", "Bad index")
|
|
292
314
|
|
|
293
315
|
index = ListIndexUtils.toPositiveIndex(#self._keyList, index)
|
|
@@ -306,7 +328,7 @@ end
|
|
|
306
328
|
@param index number?
|
|
307
329
|
@return callback -- Call to remove
|
|
308
330
|
]=]
|
|
309
|
-
function ObservableList
|
|
331
|
+
function ObservableList.InsertAt<T>(self: ObservableList<T>, item: T, index: number?): () -> ()
|
|
310
332
|
assert(item ~= nil, "Bad item")
|
|
311
333
|
assert(type(index) == "number", "Bad index")
|
|
312
334
|
|
|
@@ -320,14 +342,14 @@ function ObservableList:InsertAt(item, index)
|
|
|
320
342
|
local changed = {}
|
|
321
343
|
|
|
322
344
|
local n = #self._keyList
|
|
323
|
-
for i=n, index, -1 do
|
|
345
|
+
for i = n, index, -1 do
|
|
324
346
|
local nextKey = self._keyList[i]
|
|
325
347
|
self._indexes[nextKey] = i + 1
|
|
326
348
|
self._keyList[i + 1] = nextKey
|
|
327
349
|
|
|
328
350
|
table.insert(changed, {
|
|
329
|
-
key = nextKey
|
|
330
|
-
newIndex = i + 1
|
|
351
|
+
key = nextKey,
|
|
352
|
+
newIndex = i + 1,
|
|
331
353
|
})
|
|
332
354
|
end
|
|
333
355
|
|
|
@@ -340,13 +362,12 @@ function ObservableList:InsertAt(item, index)
|
|
|
340
362
|
-- Fire off add
|
|
341
363
|
self.ItemAdded:Fire(item, index, key)
|
|
342
364
|
|
|
343
|
-
|
|
344
365
|
-- Fire off the index change on the value
|
|
345
366
|
self._keyIndexObservables:Fire(key, index)
|
|
346
367
|
self._indexObservers:Fire(index, item)
|
|
347
368
|
self._indexObservers:Fire(ListIndexUtils.toNegativeIndex(listLength, index), item)
|
|
348
369
|
|
|
349
|
-
for _, data in
|
|
370
|
+
for _, data in changed do
|
|
350
371
|
if self._indexes[data.key] == data.newIndex then
|
|
351
372
|
self._indexObservers:Fire(data.newIndex, self._contents[data.key])
|
|
352
373
|
self._indexObservers:Fire(ListIndexUtils.toNegativeIndex(listLength, index), self._contents[data.key])
|
|
@@ -366,7 +387,7 @@ end
|
|
|
366
387
|
@param index number
|
|
367
388
|
@return T
|
|
368
389
|
]=]
|
|
369
|
-
function ObservableList
|
|
390
|
+
function ObservableList.RemoveAt<T>(self: ObservableList<T>, index: number): T?
|
|
370
391
|
assert(type(index) == "number", "Bad index")
|
|
371
392
|
|
|
372
393
|
local key = self._keyList[index]
|
|
@@ -382,7 +403,7 @@ end
|
|
|
382
403
|
@param key Symbol
|
|
383
404
|
@return T
|
|
384
405
|
]=]
|
|
385
|
-
function ObservableList
|
|
406
|
+
function ObservableList.RemoveByKey<T>(self: ObservableList<T>, key): T?
|
|
386
407
|
assert(key ~= nil, "Bad key")
|
|
387
408
|
|
|
388
409
|
local index = self._indexes[key]
|
|
@@ -402,14 +423,14 @@ function ObservableList:RemoveByKey(key)
|
|
|
402
423
|
|
|
403
424
|
-- shift everything down
|
|
404
425
|
local n = #self._keyList
|
|
405
|
-
for i=index, n - 1 do
|
|
406
|
-
local nextKey = self._keyList[i+1]
|
|
426
|
+
for i = index, n - 1 do
|
|
427
|
+
local nextKey = self._keyList[i + 1]
|
|
407
428
|
self._indexes[nextKey] = i
|
|
408
429
|
self._keyList[i] = nextKey
|
|
409
430
|
|
|
410
431
|
table.insert(changed, {
|
|
411
|
-
key = nextKey
|
|
412
|
-
newIndex = i
|
|
432
|
+
key = nextKey,
|
|
433
|
+
newIndex = i,
|
|
413
434
|
})
|
|
414
435
|
end
|
|
415
436
|
self._keyList[n] = nil
|
|
@@ -431,7 +452,7 @@ function ObservableList:RemoveByKey(key)
|
|
|
431
452
|
end
|
|
432
453
|
|
|
433
454
|
-- Fire off index change on each key list (if the data isn't stale)
|
|
434
|
-
for _, data in
|
|
455
|
+
for _, data in changed do
|
|
435
456
|
if self._indexes[data.key] == data.newIndex then
|
|
436
457
|
self._indexObservers:Fire(data.newIndex, self._contents[data.key])
|
|
437
458
|
self._indexObservers:Fire(ListIndexUtils.toNegativeIndex(listLength, index), self._contents[data.key])
|
|
@@ -446,9 +467,9 @@ end
|
|
|
446
467
|
Gets a list of all entries.
|
|
447
468
|
@return { T }
|
|
448
469
|
]=]
|
|
449
|
-
function ObservableList
|
|
470
|
+
function ObservableList.GetList<T>(self: ObservableList<T>): { T }
|
|
450
471
|
local list = table.create(#self._keyList)
|
|
451
|
-
for index, key in
|
|
472
|
+
for index, key in self._keyList do
|
|
452
473
|
list[index] = self._contents[key]
|
|
453
474
|
end
|
|
454
475
|
return list
|
|
@@ -457,9 +478,9 @@ end
|
|
|
457
478
|
--[=[
|
|
458
479
|
Cleans up the ObservableList and sets the metatable to nil.
|
|
459
480
|
]=]
|
|
460
|
-
function ObservableList
|
|
481
|
+
function ObservableList.Destroy<T>(self: ObservableList<T>)
|
|
461
482
|
self._maid:DoCleaning()
|
|
462
|
-
setmetatable(self, nil)
|
|
483
|
+
setmetatable(self :: any, nil)
|
|
463
484
|
end
|
|
464
485
|
|
|
465
486
|
return ObservableList
|