Files
onepilot/frogpilot/third_party/reactivex/operators/_delay.py
T
firestar5683 d0e1db6766 StarPilot
2026-03-22 03:15:05 -05:00

142 lines
4.6 KiB
Python

from datetime import datetime
from typing import Any, Callable, List, Optional, TypeVar
from reactivex import Notification, Observable, abc
from reactivex import operators as ops
from reactivex import typing
from reactivex.disposable import (
CompositeDisposable,
MultipleAssignmentDisposable,
SerialDisposable,
)
from reactivex.internal.constants import DELTA_ZERO
from reactivex.notification import OnError
from reactivex.scheduler import TimeoutScheduler
from ._timestamp import Timestamp
_T = TypeVar("_T")
def observable_delay_timespan(
source: Observable[_T],
duetime: typing.RelativeTime,
scheduler: Optional[abc.SchedulerBase] = None,
) -> Observable[_T]:
def subscribe(
observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None
):
nonlocal duetime
_scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton()
if isinstance(duetime, datetime):
duetime_ = _scheduler.to_datetime(duetime) - _scheduler.now
else:
duetime_ = _scheduler.to_timedelta(duetime)
cancelable = SerialDisposable()
exception: Optional[Exception] = None
active = [False]
running = [False]
queue: List[Timestamp[Notification[_T]]] = []
def on_next(notification: Timestamp[Notification[_T]]) -> None:
nonlocal exception
should_run = False
with source.lock:
if isinstance(notification.value, OnError):
del queue[:]
queue.append(notification)
exception = notification.value.exception
should_run = not running[0]
else:
queue.append(
Timestamp(
value=notification.value,
timestamp=notification.timestamp + duetime_,
)
)
should_run = not active[0]
active[0] = True
if should_run:
if exception:
observer.on_error(exception)
else:
mad = MultipleAssignmentDisposable()
cancelable.disposable = mad
def action(scheduler: abc.SchedulerBase, state: Any = None):
if exception:
return
with source.lock:
running[0] = True
while True:
result = None
if queue and queue[0].timestamp <= scheduler.now:
result = queue.pop(0).value
if result:
result.accept(observer)
if not result:
break
should_continue = False
recurse_duetime: typing.RelativeTime = 0
if queue:
should_continue = True
diff = queue[0].timestamp - scheduler.now
recurse_duetime = max(DELTA_ZERO, diff)
else:
active[0] = False
ex = exception
running[0] = False
if ex:
observer.on_error(ex)
elif should_continue:
mad.disposable = scheduler.schedule_relative(
recurse_duetime, action
)
mad.disposable = _scheduler.schedule_relative(duetime_, action)
subscription = source.pipe(
ops.materialize(),
ops.timestamp(),
).subscribe(on_next, scheduler=_scheduler)
return CompositeDisposable(subscription, cancelable)
return Observable(subscribe)
def delay_(
duetime: typing.RelativeTime, scheduler: Optional[abc.SchedulerBase] = None
) -> Callable[[Observable[_T]], Observable[_T]]:
def delay(source: Observable[_T]) -> Observable[_T]:
"""Time shifts the observable sequence.
A partially applied delay operator function.
Examples:
>>> res = delay(source)
Args:
source: The observable sequence to delay.
Returns:
A time-shifted observable sequence.
"""
return observable_delay_timespan(source, duetime, scheduler)
return delay
__all__ = ["delay_"]