TestGame/addons/reactivex/observable/generatewithrelativetime.gd

78 lines
2.4 KiB
GDScript3
Raw Normal View History

2024-12-27 21:00:07 +01:00
## Generates an observable sequence by iterating a state from an
## initial state until the condition fails.
## [br]
## [b]Example:[/b]
## [codeblock]
## var res = GDRx.obs.generate_with_relative_time(
## 0, func(x): return true, func(x): return x + 1, func(x): return 0.5
## )
## [/codeblock]
## [br]
## [b]Args:[/b]
## [br]
## [code]initial_state[/code] Initial state.
## [br]
## [code]condition[/code] Condition to terminate generation (upon returning
## false).
## [br]
## [code]iterate[/code] Iteration step function.
## [br]
## [code]time_mapper[/code] Time mapper function to control the speed of
## values being produced each iteration, returning relative
## times, i.e. either floats denoting seconds or instances of
## timedelta.
## [br][br]
## [b]Returns:[/b]
## [br]
## The generated sequence.
static func generate_with_relative_time_(
initial_state,
condition : Callable = GDRx.basic.default_condition,
iterate : Callable = GDRx.basic.identity,
time_mapper : Callable = func(_state) -> float: return 1.0
) -> Observable:
var subscribe = func(
observer : ObserverBase,
scheduler : SchedulerBase = null
) -> DisposableBase:
var _scheduler : SchedulerBase = scheduler if scheduler != null else SceneTreeTimeoutScheduler.singleton()
var mad = MultipleAssignmentDisposable.new()
var state = RefValue.Set(initial_state)
var has_result = RefValue.Set(false)
var result = RefValue.Null()
var first = RefValue.Set(true)
var time = RefValue.Null()
var action = func(scheduler : SchedulerBase, __, action_ : Callable):
if has_result.v:
observer.on_next(result.v)
if GDRx.try(func():
if first.v:
first.v = false
else:
state.v = iterate.call(state.v)
has_result.v = condition.call(state.v)
if has_result.v:
result.v = state.v
time.v = time_mapper.call(state.v)
) \
.catch("Error", func(e):
observer.on_error(e)
) \
.end_try_catch(): return
if has_result.v:
if GDRx.assert_(time.v != null): return
mad.disposable = scheduler.scheduler_relative(time.v, action_.bind(action_))
else:
observer.on_completed()
mad.disposable = _scheduler.schedule_relative(0, action.bind(action))
return mad
return Observable.new(subscribe)