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

148 lines
4.4 KiB
GDScript

extends ReactiveSignalBase
class_name ReactiveSignal
const MAX_ARGS : int = 8
signal _signal0
signal _signal1(arg0)
signal _signal2(arg0, arg1)
signal _signal3(arg0, arg1, arg2)
signal _signal4(arg0, arg1, arg2, arg3)
signal _signal5(arg0, arg1, arg2, arg3, arg4)
signal _signal6(arg0, arg1, arg2, arg3, arg4, arg5)
signal _signal7(arg0, arg1, arg2, arg3, arg4, arg5, arg6)
signal _signal8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
var is_disposed : bool
var _signal : Signal
var _n_args : int
var _observers : Array[ObserverBase]
var _connections : Array[Callable]
func _init(n_args : int = 1):
if n_args > MAX_ARGS:
GDRx.raise(TooManyArgumentsError.new(
"Only up to 8 signal parameters supported! Use lists instead!"))
super._init(func(__, ___ = null): return Disposable.new())
return
self.is_disposed = false
self._n_args = n_args
self._observers = []
match self._n_args:
0: self._signal = self._signal0
1: self._signal = self._signal1
2: self._signal = self._signal2
3: self._signal = self._signal3
4: self._signal = self._signal4
5: self._signal = self._signal5
6: self._signal = self._signal6
7: self._signal = self._signal7
8: self._signal = self._signal8
_: assert(false) # "should not happen"
var wself = weakref(self)
var subscribe_ = func(observer : ObserverBase, scheduler_ : SchedulerBase = null) -> DisposableBase:
var rself : ReactiveSignal = wself.get_ref()
if rself == null:
return Disposable.new()
var scheduler : GodotSignalScheduler = scheduler_ if scheduler_ is GodotSignalScheduler else GodotSignalScheduler.singleton()
rself._observers.push_back(observer)
var on_dispose = func():
var _rself : ReactiveSignal = wself.get_ref()
if _rself == null:
return
_rself._observers.erase(observer)
var action : Callable
match n_args:
0:
action = func():
observer.on_next(Tuple.new([]))
1:
action = func(arg1):
if arg1 is Array:
observer.on_next(Tuple.new(arg1))
else:
observer.on_next(arg1)
2:
action = func(arg1, arg2):
observer.on_next(Tuple.new([arg1, arg2]))
3:
action = func(arg1, arg2, arg3):
observer.on_next(Tuple.new([arg1, arg2, arg3]))
4:
action = func(arg1, arg2, arg3, arg4):
observer.on_next(Tuple.new([arg1, arg2, arg3, arg4]))
5:
action = func(arg1, arg2, arg3, arg4, arg5):
observer.on_next(Tuple.new([arg1, arg2, arg3, arg4, arg5]))
6:
action = func(arg1, arg2, arg3, arg4, arg5, arg6):
observer.on_next(Tuple.new([arg1, arg2, arg3, arg4, arg5, arg6]))
7:
action = func(arg1, arg2, arg3, arg4, arg5, arg6, arg7):
observer.on_next(Tuple.new([arg1, arg2, arg3, arg4, arg5, arg6, arg7]))
8:
action = func(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8):
observer.on_next(Tuple.new([arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8]))
_:
GDRx.raise(TooManyArgumentsError.new(
"Only up to 8 signal parameters supported! Use lists instead!"))
return Disposable.new()
var sub = scheduler.schedule_signal(rself._signal, rself._n_args, action)
var cd = CompositeDisposable.new([sub, Disposable.new(on_dispose)])
return cd
super._init(subscribe_)
func _emit(args = []):
if self.is_disposed:
return
var args_ = []
GDRx.iter(args).foreach(func(arg):
args_.push_back(arg))
match self._n_args:
0: self._signal.emit()
1: self._signal.emit(args_[0])
2: self._signal.emit(args_[0], args_[1])
3: self._signal.emit(args_[0], args_[1], args_[2])
4: self._signal.emit(args_[0], args_[1], args_[2], args_[3])
5: self._signal.emit(args_[0], args_[1], args_[2], args_[3], args_[4])
6: self._signal.emit(args_[0], args_[1], args_[2], args_[3], args_[4], args_[5])
7: self._signal.emit(args_[0], args_[1], args_[2], args_[3], args_[4], args_[5], args_[6])
8: self._signal.emit(args_[0], args_[1], args_[2], args_[3], args_[4], args_[5], args_[6], args_[7])
_: assert(false) # "should not happen"
func attach(cb : Callable):
if self.is_disposed:
return
if not cb in self._connections:
self._signal.connect(cb)
self._connections.push_back(cb)
func detach(cb : Callable):
if self.is_disposed:
return
if cb in self._connections:
self._signal.disconnect(cb)
self._connections.erase(cb)
func dispose():
if this.is_disposed:
return
this.is_disposed = true
for observer in this._observers:
observer.on_completed()
for conn in this._connections:
self._signal.disconnect(conn)