148 lines
4.4 KiB
GDScript
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)
|