2025-01-11 00:25:52 +01:00

294 lines
7.9 KiB
GDScript

extends ReactiveCollectionBase
class_name ReactiveCollection
var _count : int
var _data : Array
var _observers : Dictionary
var _rwlock : ReadWriteLock
var is_disposed : bool
func _get_subscription(event_class, notify_count = false) -> Callable:
var wself : WeakRef = weakref(self)
return func(observer : ObserverBase, _scheduler : SchedulerBase = null) -> DisposableBase:
var prop : ReactiveCollection = wself.get_ref()
if not prop or prop.is_disposed:
observer.on_completed()
return Disposable.new()
if notify_count:
observer.on_next(prop.Count)
if true:
var __ = ReadWriteLockGuard.new(prop._rwlock, false)
if not (event_class in prop._observers):
prop._observers[event_class] = []
prop._observers[event_class].push_back(observer)
var dispose_ = func():
var _prop = wself.get_ref()
if not _prop:
return
var __ = ReadWriteLockGuard.new(prop._rwlock, false)
prop._observers[event_class].erase(observer)
return Disposable.new(dispose_)
func _notify_all(event_class, event):
var observers_ : Array
if true:
var __ = ReadWriteLockGuard.new(self._rwlock, true)
if event_class in self._observers:
observers_ = self._observers[event_class].duplicate()
for observer in observers_:
observer.on_next(event)
func _disconnect_all(event_class):
var observers_ : Array
if true:
var __ = ReadWriteLockGuard.new(this._rwlock, true)
if event_class in this._observers:
observers_ = this._observers[event_class].duplicate()
for observer in observers_:
observer.on_completed()
func _init(collection = []):
super._init()
self._count = 0
self._data = []
self._observers = {}
self._rwlock = ReadWriteLock.new()
self.is_disposed = false
var it : Iterator = GDRx.iter(collection)
while it.has_next():
self._add_item(it.next())
self._observe_add = Observable.new(self._get_subscription(CollectionAddEvent))
self._observe_move = Observable.new(self._get_subscription(CollectionMoveEvent))
self._observe_remove = Observable.new(self._get_subscription(CollectionRemoveEvent))
self._observe_replace = Observable.new(self._get_subscription(CollectionReplaceEvent))
self._observe_reset = Observable.new(self._get_subscription("Reset"))
func ObserveCountChanged(notify_current_count : bool = false) -> Observable:
return Observable.new(self._get_subscription("CountChanged", notify_current_count))
func _add_item(item) -> int:
self._data.append(item)
self._count += 1
return self._count - 1
func add_item(item) -> int:
if self.is_disposed:
DisposedError.raise()
return -1
var index = self._add_item(item)
var event_add = CollectionAddEvent.new(index, item)
self._notify_all(CollectionAddEvent, event_add)
self._notify_all("CountChanged", self._count)
return index
func _remove_item(item) -> int:
var index = self._data.find(item)
if index >= 0:
self._data.remove_at(index)
self._count -= 1
return index
func remove_item(item) -> int:
if self.is_disposed:
DisposedError.raise()
return -1
var index = self._remove_item(item)
if index >= 0:
var event_remove = CollectionRemoveEvent.new(index, item)
self._notify_all(CollectionRemoveEvent, event_remove)
self._notify_all("CountChanged", self._count)
return index
func _remove_at(index : int) -> Variant:
if index >= self._count:
return null
var value = self._data[index]
self._data.remove_at(index)
self._count -= 1
return value
func remove_at(index : int) -> Variant:
if self.is_disposed:
return DisposedError.raise()
var value = self._remove_at(index)
if value != null:
var event_remove = CollectionRemoveEvent.new(index, value)
self._notify_all(CollectionRemoveEvent, event_remove)
self._notify_all("CountChanged", self._count)
return value
func _replace_item(item, with) -> int:
var index = self._data.find(item)
if index >= 0:
self._data[index] = with
return index
func replace_item(item, with) -> int:
if self.is_disposed:
return DisposedError.raise()
if GDRx.eq(item, with):
return self._data.find(item)
var index : int = self._replace_item(item, with)
if index >= 0:
var event_replace = CollectionReplaceEvent.new(index, item, with)
self._notify_all(CollectionReplaceEvent, event_replace)
return index
func _replace_at(index : int, item) -> Variant:
if index >= self._count:
return null
var value = self._data[index]
self._data[index] = item
return value
func replace_at(index : int, item) -> Variant:
if self.is_disposed:
return DisposedError.raise()
var value = self._replace_at(index, item)
if value != null and GDRx.neq(value, item):
var event_replace = CollectionReplaceEvent.new(index, value, item)
self._notify_all(CollectionReplaceEvent, event_replace)
return value
func _swap(idx1 : int, idx2 : int) -> Tuple:
if idx1 >= self._count or idx2 >= self._count:
return null
var tmp = self._data[idx1]
self._data[idx1] = self._data[idx2]
self._data[idx2] = tmp
return Tuple.new([self._data[idx2], self._data[idx1]])
func swap(idx1 : int, idx2 : int) -> Tuple:
if self.is_disposed:
return DisposedError.raise()
if idx1 >= self._count or idx2 >= self._count:
return
var pair = self._swap(idx1, idx2)
if GDRx.eq(pair.at(0), pair.at(1)):
return pair
var event_move1 = CollectionMoveEvent.new(idx1, idx2, pair.at(0))
var event_move2 = CollectionMoveEvent.new(idx2, idx1, pair.at(1))
self._notify_all(CollectionMoveEvent, event_move1)
self._notify_all(CollectionMoveEvent, event_move2)
return pair
func _move_to(curr_index : int, new_index : int):
if curr_index >= self._count or new_index >= self._count:
return
var tmp = self._data[curr_index]
self._data.remove_at(curr_index)
self._data.insert(new_index, tmp)
func move_to(old_index : int, new_index : int):
if self.is_disposed:
return DisposedError.raise()
if old_index >= self._count or new_index >= self._count or old_index == new_index:
return
var moved = self._data[old_index]
self._move_to(old_index, new_index)
var event_move = CollectionMoveEvent.new(old_index, new_index, moved)
self._notify_all(CollectionMoveEvent, event_move)
func _insert_at(index : int, elem):
if index > self._count:
return
self._data.insert(index, elem)
self._count += 1
func insert_at(index : int, elem):
if self.is_disposed:
return DisposedError.raise()
if index > self._count:
return
self._insert_at(index, elem)
var event_add = CollectionAddEvent.new(index, elem)
self._notify_all(CollectionAddEvent, event_add)
self._notify_all("CountChanged", self._count)
func _at(index : int):
return self._data[index]
func at(index : int):
if self.is_disposed:
return DisposedError.raise()
return self._at(index)
func _find(item) -> int:
return self._data.find(item)
func find(item) -> int:
if self.is_disposed:
DisposedError.raise()
return -1
return self._find(item)
func _reset():
self._data.clear()
self._count = 0
func reset():
if self.is_disposed:
return DisposedError.raise()
var c = self._count
self._reset()
self._notify_all("Reset", StreamItem.Unit())
if self._count != c:
self._notify_all("CountChanged", self._count)
func iter() -> Iterator:
if self.is_disposed:
return DisposedError.raise()
return GDRx.iter(self._data)
func _to_list() -> Array:
return self._data.duplicate()
func to_list() -> Array:
if self.is_disposed:
DisposedError.raise()
return []
return self._data.duplicate()
func _size() -> int:
return self._count
func size() -> int:
if self.is_disposed:
DisposedError.raise()
return -1
return self._count
func dispose():
if this.is_disposed:
return
this.is_disposed = true
this._disconnect_all(CollectionAddEvent)
this._disconnect_all(CollectionMoveEvent)
this._disconnect_all(CollectionRemoveEvent)
this._disconnect_all(CollectionReplaceEvent)
this._disconnect_all("Reset")
this._disconnect_all("CountChanged")
this._data = []
this._count = -1
this._observers = {}
func to_readonly() -> ReadOnlyReactiveCollection:
return ReadOnlyReactiveCollection.new(self)
func _to_string() -> String:
if self.is_disposed:
return "<<Disposed ReactiveCollection>>"
return str(self._data)