class ScheduledItem(Generic[typing.TState]):  # pylint: disable=unsubscriptable-object
    def __init__(self, scheduler: SchedulerBase, state: Optional[typing.TState], action: typing.ScheduledAction,
                 duetime: typing.AbsoluteTime):
        self.scheduler = scheduler
        self.state = state
        self.action = action
        self.duetime = duetime
        self.disposable = SingleAssignmentDisposable()

    def invoke(self) -> None:
        ret = self.scheduler.invoke_action(self.action, self.state)
        self.disposable.disposable = ret

    def cancel(self) -> None:
        """Cancels the work item by disposing the resource returned by
        invoke_core as soon as possible."""

        self.disposable.dispose()

    def is_cancelled(self) -> bool:
        return self.disposable.is_disposed

    def __lt__(self, other):
        return self.duetime < other.duetime

    def __gt__(self, other):
        return self.duetime > other.duetime

    def __eq__(self, other):
        return self.duetime == other.duetime
Exemple #2
0
class ScheduledItem(Generic[typing.TState]):  # pylint: disable=unsubscriptable-object
    def __init__(self, scheduler: SchedulerBase,
                 state: Optional[typing.TState],
                 action: typing.ScheduledAction, duetime: typing.AbsoluteTime):
        self.scheduler = scheduler
        self.state = state
        self.action = action
        self.duetime = duetime
        self.disposable = SingleAssignmentDisposable()

    def invoke(self) -> None:
        ret = self.scheduler.invoke_action(self.action, self.state)
        self.disposable.disposable = ret

    def cancel(self) -> None:
        """Cancels the work item by disposing the resource returned by
        invoke_core as soon as possible."""

        self.disposable.dispose()

    def is_cancelled(self) -> bool:
        return self.disposable.is_disposed

    def __lt__(self, other):
        return self.duetime < other.duetime

    def __gt__(self, other):
        return self.duetime > other.duetime

    def __eq__(self, other):
        return self.duetime == other.duetime
Exemple #3
0
  class Sink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(SampleWithObservable.Sink, self).__init__(observer, cancel)
      self.parent = parent

    def run(self):
      self.gate = RLock()
      self.atEnd = False
      self.hasValue = False
      self.value = None
      self.sourceSubscription = SingleAssignmentDisposable()
      self.sourceSubscription.disposable = self.parent.source.subscribeSafe(self)

      samplerSubscription = self.parent.sampler.subscribeSafe(self.SamplerObserver(self))

      return CompositeDisposable(self.sourceSubscription, samplerSubscription)

    def onNext(self, value):
      with self.gate:
        self.hasValue = True
        self.value = value

    def onError(self, exception):
      with self.gate:
        self.observer.onError(exception)
        self.dispose()

    def onCompleted(self):
      with self.gate:
        self.atEnd = True
        self.sourceSubscription.dispose()

    class SamplerObserver(Observer):
      def __init__(self, parent):
        self.parent = parent

      def onNext(self, value):
        with self.parent.gate:
          if self.parent.hasValue:
            self.parent.hasValue = False
            self.parent.observer.onNext(self.parent.value)

          if self.parent.atEnd:
            self.parent.observer.onCompleted()
            self.parent.dispose()

      def onError(self, exception):
        with self.parent.gate:
          self.parent.observer.onError(exception)
          self.parent.dispose()

      def onCompleted(self):
        with self.parent.gate:
          if self.parent.hasValue:
            self.parent.hasValue = False
            self.parent.observer.onNext(self.parent.value)

          if self.parent.atEnd:
            self.parent.observer.onCompleted()
            self.parent.dispose()
Exemple #4
0
        class O(Observer):
            def __init__(self, parent, sourceObserver):
                self.parent = parent
                self.sourceObserver = sourceObserver
                self.subscription = SingleAssignmentDisposable()

            def setdisposable(self, value):
                self.subscription.disposable = value

            disposable = property(None, setdisposable)

            def onNext(self, value):
                with self.parent.gate:
                    self.parent.observer.onCompleted()
                    self.parent.dispose()

            def onError(self, exception):
                with self.parent.gate:
                    self.parent.observer.onError(exception)
                    self.parent.dispose()

            def onCompleted(self):
                with self.parent.gate:
                    self.sourceObserver.open = True
                    self.subscription.dispose()
Exemple #5
0
class AutoDetachObserver(typing.Observer):

    def __init__(self,
                 on_next: Optional[typing.OnNext] = None,
                 on_error: Optional[typing.OnError] = None,
                 on_completed: Optional[typing.OnCompleted] = None
                 ) -> Any:
        self._on_next = on_next or noop
        self._on_error = on_error or default_error
        self._on_completed = on_completed or noop

        self._subscription = SingleAssignmentDisposable()
        self.is_stopped = False

    def on_next(self, value: Any) -> None:
        if self.is_stopped:
            return

        try:
            self._on_next(value)
        except Exception:
            self.dispose()
            raise

    def on_error(self, error) -> None:
        if self.is_stopped:
            return
        self.is_stopped = True

        try:
            self._on_error(error)
        finally:
            self.dispose()

    def on_completed(self) -> None:
        if self.is_stopped:
            return
        self.is_stopped = True

        try:
            self._on_completed()
        finally:
            self.dispose()

    def set_disposable(self, value: typing.Disposable):
        self._subscription.disposable = value

    subscription = property(fset=set_disposable)

    def dispose(self) -> None:
        self.is_stopped = True
        self._subscription.dispose()

    def fail(self, exn: Exception) -> bool:
        if self.is_stopped:
            return False

        self.is_stopped = True
        self._on_error(exn)
        return True
class AutoDetachObserver(Observer):

    def __init__(self, on_next=None, on_error=None, on_completed=None):
        self._on_next = on_next or noop
        self._on_error = on_error or default_error
        self._on_completed = on_completed or noop

        self._subscription = SingleAssignmentDisposable()
        self.is_stopped = False

    def on_next(self, value: Any) -> None:
        if self.is_stopped:
            return

        try:
            self._on_next(value)
        except Exception:
            self.dispose()
            raise

    def on_error(self, error) -> None:
        if self.is_stopped:
            return
        self.is_stopped = True

        try:
            self._on_error(error)
        finally:
            self.dispose()

    def on_completed(self) -> None:
        if self.is_stopped:
            return
        self.is_stopped = True

        try:
            self._on_completed()
        finally:
            self.dispose()

    def set_disposable(self, value):
        self._subscription.disposable = value

    subscription = property(fset=set_disposable)

    def dispose(self) -> None:
        self.is_stopped = True
        self._subscription.dispose()

    def fail(self, exn: Exception) -> bool:
        if self.is_stopped:
            return False

        self.is_stopped = True
        self._on_error(exn)
        return True
Exemple #7
0
    class Sink(rx.linq.sink.Sink):
        def __init__(self, parent, observer, cancel):
            super(TakeLastCount.Sink, self).__init__(observer, cancel)
            self.parent = parent
            self.queue = deque()

        def run(self):
            self.subscription = SingleAssignmentDisposable()
            self.loopDisposable = SingleAssignmentDisposable()

            self.subscription.disposable = self.parent.source.subscribeSafe(
                self)

            return CompositeDisposable(self.subscription, self.loopDisposable)

        def onNext(self, value):
            self.queue.append(value)

            if len(self.queue) > self.parent.count:
                self.queue.popleft()

        def onError(self, exception):
            self.observer.onError(exception)
            self.dispose()

        def onCompleted(self):
            self.subscription.dispose()

            scheduler = self.parent.scheduler
            if scheduler.isLongRunning:
                self.loopDisposable.disposable = scheduler.scheduleLongRunning(
                    self.loop)
            else:
                self.loopDisposable.disposable = scheduler.scheduleRecursive(
                    self.loopRec)

        def loopRec(self, recurse):
            if len(self.queue) > 0:
                self.observer.onNext(self.queue.popleft())
                recurse()
            else:
                self.observer.onCompleted()
                self.dispose()

        def loop(self, cancel):
            while not cancel.isDisposed:
                if len(self.queue) == 0:
                    self.observer.onCompleted()
                    break
                else:
                    self.observer.onNext(self.queue.popleft())

            self.dispose()
Exemple #8
0
    class Sink(rx.linq.sink.Sink):
        def __init__(self, parent, observer, cancel):
            super(TakeLastCount.Sink, self).__init__(observer, cancel)
            self.parent = parent
            self.queue = deque()

        def run(self):
            self.subscription = SingleAssignmentDisposable()
            self.loopDisposable = SingleAssignmentDisposable()

            self.subscription.disposable = self.parent.source.subscribeSafe(self)

            return CompositeDisposable(self.subscription, self.loopDisposable)

        def onNext(self, value):
            self.queue.append(value)

            if len(self.queue) > self.parent.count:
                self.queue.popleft()

        def onError(self, exception):
            self.observer.onError(exception)
            self.dispose()

        def onCompleted(self):
            self.subscription.dispose()

            scheduler = self.parent.scheduler
            if scheduler.isLongRunning:
                self.loopDisposable.disposable = scheduler.scheduleLongRunning(self.loop)
            else:
                self.loopDisposable.disposable = scheduler.scheduleRecursive(self.loopRec)

        def loopRec(self, recurse):
            if len(self.queue) > 0:
                self.observer.onNext(self.queue.popleft())
                recurse()
            else:
                self.observer.onCompleted()
                self.dispose()

        def loop(self, cancel):
            while not cancel.isDisposed:
                if len(self.queue) == 0:
                    self.observer.onCompleted()
                    break
                else:
                    self.observer.onNext(self.queue.popleft())

            self.dispose()
def test_futuredisposable_disposeafterset():
    d = SingleAssignmentDisposable()
    disposed = [False]

    def action():
        disposed[0] = True

    dd = Disposable(action)
    d.disposable = dd
    assert dd == d.disposable
    assert not disposed[0]

    d.dispose()
    assert disposed[0]
    d.dispose()
    assert disposed[0]
Exemple #10
0
def test_futuredisposable_disposeafterset():
    d = SingleAssignmentDisposable()
    disposed = [False]

    def action():
        disposed[0] = True

    dd = Disposable(action)
    d.disposable = dd
    assert dd == d.disposable
    assert not disposed[0]

    d.dispose()
    assert disposed[0]
    d.dispose()
    assert disposed[0]
Exemple #11
0
    class Sink(rx.linq.sink.Sink):
        def __init__(self, parent, observer, cancel):
            super(TakeLastBufferTime.Sink, self).__init__(observer, cancel)
            self.parent = parent

        def run(self):
            self.subscription = SingleAssignmentDisposable()
            self.loop = SingleAssignmentDisposable()

            self.startTime = self.parent.scheduler.now()
            self.subscription.disposable = self.parent.source.subscribeSafe(
                self)

            return CompositeDisposable(self.subscription, self.loop)

        def elapsed(self):
            return self.parent.scheduler.now() - self.startTime

        def trim(self, now):
            while len(self.queue) > 0:
                current = self.queue.popleft()

                if current.interval < self.parent.duration:
                    self.queue.appendleft(current)
                    break

        def onNext(self, value):
            now = self.elapsed()

            self.queue.append(Struct(value=value, interval=now))
            self.trim(now)

        def onError(self, exception):
            self.observer.onError(exception)
            self.dispose()

        def onCompleted(self):
            self.subscription.dispose()

            now = self.elapsed()
            self.trim(now)

            res = list([x.value for x in self.queue])

            self.observer.onNext(res)
            self.observer.onCompleted()
            self.dispose()
def test_futuredisposable_disposebeforeset():
    disposed = [False]

    def dispose():
        disposed[0] = True

    d = SingleAssignmentDisposable()
    dd = Disposable(dispose)

    assert not disposed[0]
    d.dispose()
    assert not disposed[0]
    d.disposable = dd
    assert d.disposable == None
    assert disposed[0]
    d.dispose()
    assert disposed[0]
Exemple #13
0
def test_futuredisposable_disposebeforeset():
    disposed = [False]

    def dispose():
        disposed[0] = True

    d = SingleAssignmentDisposable()
    dd = Disposable(dispose)

    assert not disposed[0]
    d.dispose()
    assert not disposed[0]
    d.disposable = dd
    assert d.disposable == None
    assert disposed[0]
    d.dispose()
    assert disposed[0]
Exemple #14
0
  class Sink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(TakeLastBufferTime.Sink, self).__init__(observer, cancel)
      self.parent = parent

    def run(self):
      self.subscription = SingleAssignmentDisposable()
      self.loop = SingleAssignmentDisposable()

      self.startTime = self.parent.scheduler.now()
      self.subscription.disposable = self.parent.source.subscribeSafe(self)

      return CompositeDisposable(self.subscription, self.loop)

    def elapsed(self):
      return self.parent.scheduler.now() - self.startTime

    def trim(self, now):
      while len(self.queue) > 0:
        current = self.queue.popleft()

        if current.interval < self.parent.duration:
          self.queue.appendleft(current)
          break

    def onNext(self, value):
      now = self.elapsed()

      self.queue.append(Struct(value=value,interval=now))
      self.trim(now)

    def onError(self, exception):
      self.observer.onError(exception)
      self.dispose()

    def onCompleted(self):
      self.subscription.dispose()

      now = self.elapsed()
      self.trim(now)

      res = list([x.value for x in self.queue])

      self.observer.onNext(res)
      self.observer.onCompleted()
      self.dispose()
Exemple #15
0
class AutoDetachObserver(ObserverBase):
  def __init__(self, observer, disposable = None):
    super(AutoDetachObserver, self).__init__()
    self.observer = observer
    self.m = SingleAssignmentDisposable()

    if disposable != None:
      self.m.disposable = disposable

  def onNextCore(self, value):
    noError = False

    try:
      self.observer.onNext(value)
      noError = True
    finally:
      if not noError:
        self.dispose()

  def onErrorCore(self, ex):
    try:
      self.observer.onError(ex)
    finally:
      self.dispose()

  def onCompletedCore(self):
    try:
      self.observer.onCompleted()
    finally:
      self.dispose()

  def disposable():
      doc = "The disposable property."
      def fget(self):
          self.m.disposable
      def fset(self, value):
          self.m.disposable = value
      return locals()
  disposable = property(**disposable())

  def dispose(self):
    with self.lock:
      super(AutoDetachObserver, self).dispose()
      self.m.dispose()
Exemple #16
0
class AutoDetachObserver(ObserverBase):
  def __init__(self, observer, disposable = None):
    super(AutoDetachObserver, self).__init__()
    self.observer = observer
    self.m = SingleAssignmentDisposable()

    if disposable != None:
      self.m.disposable = disposable

  def onNextCore(self, value):
    noError = False

    try:
      self.observer.onNext(value)
      noError = True
    finally:
      if not noError:
        self.dispose()

  def onErrorCore(self, ex):
    try:
      self.observer.onError(ex)
    finally:
      self.dispose()

  def onCompletedCore(self):
    try:
      self.observer.onCompleted()
    finally:
      self.dispose()

  def disposable():
      """The disposable property."""
      def fget(self):
          self.m.disposable
      def fset(self, value):
          self.m.disposable = value
      return locals()
  disposable = property(**disposable())

  def dispose(self):
    with self.lock:
      super(AutoDetachObserver, self).dispose()
      self.m.dispose()
Exemple #17
0
    class O(Observer):
      def __init__(self, parent, sourceObserver):
        self.parent = parent
        self.sourceObserver = sourceObserver
        self.subscription = SingleAssignmentDisposable()

      def setdisposable(self, value):
        self.subscription.disposable = value
      disposable = property(None, setdisposable)

      def onNext(self, value):
        self.sourceObserver.observer = self.parent.observer
        self.subscription.dispose()

      def onError(self, exception):
        self.parent.observer.onError(exception)
        self.parent.dispose()

      def onCompleted(self):
        self.subscription.dispose()
Exemple #18
0
    class T(Observer):
      def __init__(self, parent):
        self.parent = parent
        self.observer = NoopObserver()
        self.subscription = SingleAssignmentDisposable()

      def setdisposable(self, value):
        self.subscription.disposable = value
      disposable = property(None, setdisposable)

      def onNext(self, value):
        self.observer.onNext(value)

      def onError(self, exception):
        self.parent.observer.onError(exception)
        self.parent.dispose()

      def onCompleted(self):
        self.observer.onCompleted()
        # We can't cancel the other stream yet, it may be on its way
        # to dispatch an OnError message and we don't want to have a race.
        self.subscription.dispose()
Exemple #19
0
  class SerialSink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(Merge.SerialSink, self).__init__(observer, cancel)
      self.parent = parent

    def run(self):
      self.gate = RLock()
      self.isStopped = False
      self.group = CompositeDisposable()

      self.sourceSubscription = SingleAssignmentDisposable()
      self.group.add(self.sourceSubscription)
      self.sourceSubscription.disposable = self.parent.sources.subscribeSafe(self)

      return self.group

    def onNext(self, value):
      innerSubscription = SingleAssignmentDisposable()
      self.group.add(innerSubscription)
      innerSubscription.disposable = value.subscribeSafe(self.LockObserver(self, innerSubscription))

    def onError(self, exception):
      with self.gate:
        self.observer.onError(exception)
        self.dispose()

    def onCompleted(self):
      self.isStopped = True

      if self.group.length == 1:
        #
        # Notice there can be a race between OnCompleted of the source and any
        # of the inner sequences, where both see _group.Count == 1, and one is
        # waiting for the lock. There won't be a double OnCompleted observation
        # though, because the call to Dispose silences the observer by swapping
        # in a NopObserver<T>.
        #
        with self.gate:
          self.observer.onCompleted()
          self.dispose()
      else:
        self.sourceSubscription.dispose()

    class LockObserver(Observer):
      def __init__(self, parent, subscription):
        self.parent = parent
        self.subscription = subscription

      def onNext(self, value):
        with self.parent.gate:
          self.parent.observer.onNext(value)

      def onError(self, exception):
        with self.parent.gate:
          self.parent.observer.onError(exception)
          self.parent.dispose()

      def onCompleted(self):
        self.parent.group.remove(self.subscription)

        if self.parent.isStopped and self.parent.group.length == 1:
          #
          # Notice there can be a race between OnCompleted of the source and any
          # of the inner sequences, where both see _group.Count == 1, and one is
          # waiting for the lock. There won't be a double OnCompleted observation
          # though, because the call to Dispose silences the observer by swapping
          # in a NopObserver<T>.
          #
          with self.parent.gate:
            self.parent.observer.onCompleted()
            self.parent.dispose()
Exemple #20
0
  class Sink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(Switch.Sink, self).__init__(observer, cancel)
      self.parent = parent

    def run(self):
      self.gate = RLock()
      self.innerSubscription = SerialDisposable()
      self.isStopped = False
      self.latest = 0
      self.hasLatest = False

      self.subscription = SingleAssignmentDisposable()
      self.subscription.disposable = self.parent.sources.subscribeSafe(self)

      return CompositeDisposable(self.subscription, self.innerSubscription)

    def onNext(self, value):
      observerId = 0

      with self.gate:
        self.latest += 1
        observerId = self.latest
        self.hasLatest = True

      d = SingleAssignmentDisposable()
      self.innerSubscription.disposable = d
      d.disposable = value.subscribeSafe(self.IdObserver(self, observerId, d))

    def onError(self, exception):
      with self.gate:
        self.observer.onError(exception)

      self.dispose()

    def onCompleted(self):
      with self.gate:
        self.subscription.dispose()
        self.isStopped = True

        if not self.hasLatest:
          self.observer.onCompleted()
          self.dispose()

    class IdObserver(Observer):
      def __init__(self, parent, observerId, cancelSelf):
        self.parent = parent
        self.observerId = observerId
        self.cancelSelf = cancelSelf

      def onNext(self, value):
        with self.parent.gate:
          if self.parent.latest == self.observerId:
            self.parent.observer.onNext(value)

      def onError(self, exception):
        with self.parent.gate:
          self.cancelSelf.dispose()

          if self.parent.latest == self.observerId:
            self.parent.observer.onError(exception)
            self.parent.dispose()

      def onCompleted(self):
        with self.parent.gate:
          self.cancelSelf.dispose()

          if self.parent.latest == self.observerId:
            self.parent.hasLatest = False

            if self.parent.isStopped:
              self.parent.observer.onCompleted()
              self.parent.dispose()
Exemple #21
0
    class Sink(rx.linq.sink.Sink):
        def __init__(self, parent, observer, cancel):
            super(TakeLastTime.Sink, self).__init__(observer, cancel)
            self.parent = parent

        def run(self):
            self.subscription = SingleAssignmentDisposable()
            self.loop = SingleAssignmentDisposable()

            self.startTime = self.parent.scheduler.now()
            self.subscription.disposable = self.parent.source.subscribeSafe(
                self)

            return CompositeDisposable(self.subscription, self.loop)

        def elapsed(self):
            return self.parent.scheduler.now() - self.startTime

        def trim(self, now):
            while len(self.queue) > 0:
                current = self.queue.popleft()

                if current.interval < self.parent.duration:
                    self.queue.appendleft(current)
                    break

        def onNext(self, value):
            now = self.elapsed()

            self.queue.append(Struct(value=value, interval=now))
            self.trim(now)

        def onError(self, exception):
            self.observer.onError(exception)
            self.dispose()

        def onCompleted(self):
            self.subscription.dispose()

            now = self.elapsed()
            self.trim(now)

            scheduler = self.parent.scheduler
            if scheduler.isLongRunning:
                self.loop.disposable = scheduler.scheduleLongRunning(self.loop)
            else:
                self.loop.disposable = scheduler.scheduleRecursive(
                    self.loopRec)

        def loopRec(self, recurse):
            if len(self.queue) > 0:
                self.observer.onNext(self.queue.popleft().value)
                recurse()
            else:
                self.observer.onCompleted()
                self.dispose()

        def loop(self, cancel):
            while not cancel.isDisposed:
                if len(self.queue) == 0:
                    self.observer.onCompleted()
                    break
                else:
                    self.observer.onNext(self.queue.popleft().value)

            self.dispose()
Exemple #22
0
    class Sink(rx.linq.sink.Sink):
        def __init__(self, parent, observer, cancel):
            super(Switch.Sink, self).__init__(observer, cancel)
            self.parent = parent

        def run(self):
            self.gate = RLock()
            self.innerSubscription = SerialDisposable()
            self.isStopped = False
            self.latest = 0
            self.hasLatest = False

            self.subscription = SingleAssignmentDisposable()
            self.subscription.disposable = self.parent.sources.subscribeSafe(
                self)

            return CompositeDisposable(self.subscription,
                                       self.innerSubscription)

        def onNext(self, value):
            observerId = 0

            with self.gate:
                self.latest += 1
                observerId = self.latest
                self.hasLatest = True

            d = SingleAssignmentDisposable()
            self.innerSubscription.disposable = d
            d.disposable = value.subscribeSafe(
                self.IdObserver(self, observerId, d))

        def onError(self, exception):
            with self.gate:
                self.observer.onError(exception)

            self.dispose()

        def onCompleted(self):
            with self.gate:
                self.subscription.dispose()
                self.isStopped = True

                if not self.hasLatest:
                    self.observer.onCompleted()
                    self.dispose()

        class IdObserver(Observer):
            def __init__(self, parent, observerId, cancelSelf):
                self.parent = parent
                self.observerId = observerId
                self.cancelSelf = cancelSelf

            def onNext(self, value):
                with self.parent.gate:
                    if self.parent.latest == self.observerId:
                        self.parent.observer.onNext(value)

            def onError(self, exception):
                with self.parent.gate:
                    self.cancelSelf.dispose()

                    if self.parent.latest == self.observerId:
                        self.parent.observer.onError(exception)
                        self.parent.dispose()

            def onCompleted(self):
                with self.parent.gate:
                    self.cancelSelf.dispose()

                    if self.parent.latest == self.observerId:
                        self.parent.hasLatest = False

                        if self.parent.isStopped:
                            self.parent.observer.onCompleted()
                            self.parent.dispose()
Exemple #23
0
  class LongrunningSink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(DelayTime.LongrunningSink, self).__init__(observer, cancel)
      self.parent = parent

    def run(self):
      self.scheduler = self.parent.scheduler

      self.cancelTimer = SerialDisposable()

      self.gate = RLock()
      self.evt = Semaphore(0)
      self.stopped = False
      self.stop = Event()
      self.queue = deque()
      self.hasCompleted = False
      self.completeAt = 0
      self.hasFailed = False
      self.exception = None

      self.delay = 0
      self.startTime = self.scheduler.now()

      if self.parent.isAbsolute:
        self.cancelTimer.disposable = self.scheduler.scheduleAbsolute(
          self.parent.dueTime,
          self.start
        )
      else:
        self.delay = Scheduler.normalize(self.parent.dueTime)
        self.scheduleDrain()

      self.sourceSubscription = SingleAssignmentDisposable()
      self.sourceSubscription.disposable = self.parent.source.subscribeSafe(self)

      return CompositeDisposable(self.sourceSubscription, self.cancelTimer)

    def elapsed(self):
      return self.scheduler.now() - self.startTime

    def start(self):
      with self.gate:
        self.delay = self.elapsed()

        for item in self.queue:
          item.interval += self.delay

      self.scheduleDrain()

    def scheduleDrain(self):
      def cancel():
        self.stopped = True
        self.stop.set()
        self.evt.release()

      self.stop.clear()
      self.cancelTimer.disposable = Disposable.create(cancel)
      self.scheduler.scheduleLongRunning(self.drainQueue)

    def onNext(self, value):
      next = self.elapsed() + self.delay

      with self.gate:
        self.queue.append(Struct(value=value, interval=next))
        self.evt.release()

    def onError(self, exception):
      self.sourceSubscription.dispose()

      with self.gate:
        self.queue.clear()

        self.exception = exception
        self.hasFailed = True

        self.evt.release()

    def onCompleted(self):
      self.sourceSubscription.dispose()

      next = self.elapsed() + self.delay

      with self.gate:
        self.completeAt = next
        self.hasCompleted = True

        self.evt.release()

    def drainQueue(self, cancel):
      while True:
        self.evt.acquire()
        if self.stopped:
          return

        hasFailed = False
        error = NotImplementedError

        hasValue = False
        value = NotImplementedError
        hasCompleted = False

        shouldWait = False
        waitTime = 0

        with self.gate:
          if self.hasFailed:
            error = self.exception
            hasFailed = True
          else:
            now = self.elapsed()

            if len(self.queue) > 0:
              next = self.queue.popleft()

              hasValue = True
              value = next.value

              nextDue = next.interval
              if nextDue > now:
                shouldWait = True
                waitTime = Scheduler.normalize(nextDue - now)
            elif self.hasCompleted:
              hasCompleted = True

              if self.completeAt > now:
                shouldWait = True
                waitTime = Scheduler.normalize(self.completeAt - now)
        # end with self.gate

        if shouldWait:
          timer = Event()
          self.scheduler.scheduleWithRelative(waitTime, lambda: timer.set())
          timer.wait()

        if hasValue:
          self.observer.onNext(value)
        else:
          if hasCompleted:
            self.observer.onCompleted()
            self.dispose()
          elif hasFailed:
            self.observer.onError(error)
            self.dispose()

          return
Exemple #24
0
    class Sink(rx.linq.sink.Sink):
        def __init__(self, parent, observer, cancel):
            super(TakeLastTime.Sink, self).__init__(observer, cancel)
            self.parent = parent

        def run(self):
            self.subscription = SingleAssignmentDisposable()
            self.loop = SingleAssignmentDisposable()

            self.startTime = self.parent.scheduler.now()
            self.subscription.disposable = self.parent.source.subscribeSafe(self)

            return CompositeDisposable(self.subscription, self.loop)

        def elapsed(self):
            return self.parent.scheduler.now() - self.startTime

        def trim(self, now):
            while len(self.queue) > 0:
                current = self.queue.popleft()

                if current.interval < self.parent.duration:
                    self.queue.appendleft(current)
                    break

        def onNext(self, value):
            now = self.elapsed()

            self.queue.append(Struct(value=value, interval=now))
            self.trim(now)

        def onError(self, exception):
            self.observer.onError(exception)
            self.dispose()

        def onCompleted(self):
            self.subscription.dispose()

            now = self.elapsed()
            self.trim(now)

            scheduler = self.parent.scheduler
            if scheduler.isLongRunning:
                self.loop.disposable = scheduler.scheduleLongRunning(self.loop)
            else:
                self.loop.disposable = scheduler.scheduleRecursive(self.loopRec)

        def loopRec(self, recurse):
            if len(self.queue) > 0:
                self.observer.onNext(self.queue.popleft().value)
                recurse()
            else:
                self.observer.onCompleted()
                self.dispose()

        def loop(self, cancel):
            while not cancel.isDisposed:
                if len(self.queue) == 0:
                    self.observer.onCompleted()
                    break
                else:
                    self.observer.onNext(self.queue.popleft().value)

            self.dispose()
Exemple #25
0
    class LongrunningSink(rx.linq.sink.Sink):
        def __init__(self, parent, observer, cancel):
            super(DelayTime.LongrunningSink, self).__init__(observer, cancel)
            self.parent = parent

        def run(self):
            self.scheduler = self.parent.scheduler

            self.cancelTimer = SerialDisposable()

            self.gate = RLock()
            self.evt = Semaphore(0)
            self.stopped = False
            self.stop = Event()
            self.queue = deque()
            self.hasCompleted = False
            self.completeAt = 0
            self.hasFailed = False
            self.exception = None

            self.delay = 0
            self.startTime = self.scheduler.now()

            if self.parent.isAbsolute:
                self.cancelTimer.disposable = self.scheduler.scheduleAbsolute(
                    self.parent.dueTime, self.start)
            else:
                self.delay = Scheduler.normalize(self.parent.dueTime)
                self.scheduleDrain()

            self.sourceSubscription = SingleAssignmentDisposable()
            self.sourceSubscription.disposable = self.parent.source.subscribeSafe(
                self)

            return CompositeDisposable(self.sourceSubscription,
                                       self.cancelTimer)

        def elapsed(self):
            return self.scheduler.now() - self.startTime

        def start(self):
            with self.gate:
                self.delay = self.elapsed()

                for item in self.queue:
                    item.interval += self.delay

            self.scheduleDrain()

        def scheduleDrain(self):
            def cancel():
                self.stopped = True
                self.stop.set()
                self.evt.release()

            self.stop.clear()
            self.cancelTimer.disposable = Disposable.create(cancel)
            self.scheduler.scheduleLongRunning(self.drainQueue)

        def onNext(self, value):
            next = self.elapsed() + self.delay

            with self.gate:
                self.queue.append(Struct(value=value, interval=next))
                self.evt.release()

        def onError(self, exception):
            self.sourceSubscription.dispose()

            with self.gate:
                self.queue.clear()

                self.exception = exception
                self.hasFailed = True

                self.evt.release()

        def onCompleted(self):
            self.sourceSubscription.dispose()

            next = self.elapsed() + self.delay

            with self.gate:
                self.completeAt = next
                self.hasCompleted = True

                self.evt.release()

        def drainQueue(self, cancel):
            while True:
                self.evt.acquire()
                if self.stopped:
                    return

                hasFailed = False
                error = NotImplementedError

                hasValue = False
                value = NotImplementedError
                hasCompleted = False

                shouldWait = False
                waitTime = 0

                with self.gate:
                    if self.hasFailed:
                        error = self.exception
                        hasFailed = True
                    else:
                        now = self.elapsed()

                        if len(self.queue) > 0:
                            next = self.queue.popleft()

                            hasValue = True
                            value = next.value

                            nextDue = next.interval
                            if nextDue > now:
                                shouldWait = True
                                waitTime = Scheduler.normalize(nextDue - now)
                        elif self.hasCompleted:
                            hasCompleted = True

                            if self.completeAt > now:
                                shouldWait = True
                                waitTime = Scheduler.normalize(
                                    self.completeAt - now)
                # end with self.gate

                if shouldWait:
                    timer = Event()
                    self.scheduler.scheduleWithRelative(
                        waitTime, lambda: timer.set())
                    timer.wait()

                if hasValue:
                    self.observer.onNext(value)
                else:
                    if hasCompleted:
                        self.observer.onCompleted()
                        self.dispose()
                    elif hasFailed:
                        self.observer.onError(error)
                        self.dispose()

                    return
Exemple #26
0
        def invokeStart(self, scheduler, state):
            #
            # Notice the first call to OnNext will introduce skew if it takes significantly long when
            # using the following naive implementation:
            #
            #    Code:  base._observer.OnNext(0L);
            #           return self.SchedulePeriodicEmulated(1L, _period, (Func<long, long>)Tick);
            #
            # What we're saying here is that Observable.Timer(dueTime, period) is pretty much the same
            # as writing Observable.Timer(dueTime).Concat(Observable.Interval(period)).
            #
            #    Expected:  dueTime
            #                  |
            #                  0--period--1--period--2--period--3--period--4--...
            #                  |
            #                  +-OnNext(0L)-|
            #
            #    Actual:    dueTime
            #                  |
            #                  0------------#--period--1--period--2--period--3--period--4--...
            #                  |
            #                  +-OnNext(0L)-|
            #
            # Different solutions for this behavior have different problems:
            #
            # 1. Scheduling the periodic job first and using an AsyncLock to serialize the OnNext calls
            #    has the drawback that InvokeStart may never return. This happens when every callback
            #    doesn't meet the period's deadline, hence the periodic job keeps queueing stuff up. In
            #    this case, InvokeStart stays the owner of the AsyncLock and the call to Wait will never
            #    return, thus not allowing any interleaving of work on this scheduler's logical thread.
            #
            # 2. Scheduling the periodic job first and using a (blocking) synchronization primitive to
            #    signal completion of the OnNext(0L) call to the Tick call requires quite a bit of state
            #    and careful handling of the case when OnNext(0L) throws. What's worse is the blocking
            #    behavior inside Tick.
            #
            # In order to avoid blocking behavior, we need a scheme much like SchedulePeriodic emulation
            # where work to dispatch OnNext(n + 1) is delegated to a catch up loop in case OnNext(n) was
            # still running. Because SchedulePeriodic emulation exhibits such behavior in all cases, we
            # only need to deal with the overlap of OnNext(0L) with future periodic OnNext(n) dispatch
            # jobs. In the worst case where every callback takes longer than the deadline implied by the
            # period, the periodic job will just queue up work that's dispatched by the tail-recursive
            # catch up loop. In the best case, all work will be dispatched on the periodic scheduler.
            #

            #
            # We start with one tick pending because we're about to start doing OnNext(0L).
            #

            self.pendingTickCount.value = 1

            d = SingleAssignmentDisposable()
            self.periodic = d
            d.disposable = scheduler.schedulePeriodicWithState(
                1, self.parent.period, self.tock)

            try:
                self.observer.onNext(0)
            except Exception as e:
                d.dispose()
                raise e

            #
            # If the periodic scheduling job already ran before we finished dispatching the OnNext(0L)
            # call, we'll find pendingTickCount to be > 1. In this case, we need to catch up by dispatching
            # subsequent calls to OnNext as fast as possible, but without running a loop in order to ensure
            # fair play with the scheduler. So, we run a tail-recursive loop in CatchUp instead.
            #

            if self.pendingTickCount.dec() > 0:
                c = SingleAssignmentDisposable()
                c.disposable = scheduler.scheduleRecursiveWithState(
                    1, self.catchUp)

                return CompositeDisposable(d, c)

            return d
Exemple #27
0
    class Sink(rx.linq.sink.Sink):
        def __init__(self, parent, observer, cancel):
            super(DelayTime.Sink, self).__init__(observer, cancel)
            self.parent = parent

        def run(self):
            self.scheduler = self.parent.scheduler

            self.cancelTimer = SerialDisposable()

            self.gate = RLock()
            self.active = False  # as soon as a value arrived
            self.running = False  # on relative: True, on absolute: True after absolute time
            self.queue = deque()
            self.hasCompleted = False
            self.completeAt = 0
            self.hasFailed = False
            self.exception = None

            self.delay = 0
            self.startTime = self.scheduler.now()

            if self.parent.isAbsolute:
                self.ready = False
                self.cancelTimer.disposable = self.scheduler.scheduleWithAbsolute(
                    self.parent.dueTime, self.start)
            else:
                self.ready = True
                self.delay = Scheduler.normalize(self.parent.dueTime)

            self.sourceSubscription = SingleAssignmentDisposable()
            self.sourceSubscription.disposable = self.parent.source.subscribeSafe(
                self)

            return CompositeDisposable(self.sourceSubscription,
                                       self.cancelTimer)

        def elapsed(self):
            return self.scheduler.now() - self.startTime

        def start(self):
            next = 0
            shouldRun = False

            with self.gate:
                self.delay = self.elapsed()

                if len(self.queue) > 0:
                    next = self.queue[0].interval

                    for item in self.queue:
                        item.interval += self.delay

                    shouldRun = True
                    self.active = True

                self.ready = True

            if shouldRun:
                self.cancelTimer.disposable = self.scheduler.scheduleRecursiveWithRelative(
                    next, self.drainQueue)

        def onNext(self, value):
            next = self.elapsed() + self.delay
            shouldRun = False

            with self.gate:
                self.queue.append(Struct(value=value, interval=next))
                shouldRun = self.ready and (not self.active)
                self.active = True

            if shouldRun:
                self.cancelTimer.disposable = self.scheduler.scheduleRecursiveWithRelative(
                    self.delay, self.drainQueue)

        def onError(self, exception):
            self.sourceSubscription.dispose()

            shouldRun = False

            with self.gate:
                self.queue.clear()

                self.exception = exception
                self.hasFailed = True

                shouldRun = not self.running

            if shouldRun:
                self.observer.onError(exception)
                self.dispose()

        def onCompleted(self):
            self.sourceSubscription.dispose()

            next = self.elapsed() + self.delay
            shouldRun = False

            with self.gate:
                self.completeAt = next
                self.hasCompleted = True

                shouldRun = self.ready and (not self.active)
                self.active = True

            if shouldRun:
                self.cancelTimer.disposable = self.scheduler.scheduleRecursiveWithRelative(
                    self.delay, self.drainQueue)

        def drainQueue(self, recurse):
            with self.gate:
                if self.hasFailed:
                    return
                self.running = True

            #
            # The shouldYield flag was added to address TFS 487881: "Delay can be unfair". In the old
            # implementation, the loop below kept running while there was work for immediate dispatch,
            # potentially causing a long running work item on the target scheduler. With the addition
            # of long-running scheduling in Rx v2.0, we can check whether the scheduler supports this
            # interface and perform different processing (see LongRunningSink). To reduce the code churn in the old
            # loop code here, we set the shouldYield flag to true after the first dispatch iteration,
            # in order to break from the loop and enter the recursive scheduling path.

            shouldYield = False

            while True:
                hasFailed = False
                error = None

                value = None
                hasValue = False

                hasCompleted = False

                shouldRecurse = False
                recurseDueTime = 0

                with self.gate:
                    if self.hasFailed:
                        error = self.exception
                        hasFailed = True
                        self.running = False
                    else:
                        now = self.elapsed()

                        if len(self.queue) > 0:
                            nextDue = self.queue[0].interval

                            if nextDue <= now and not shouldYield:
                                value = self.queue.popleft().value
                                hasValue = True
                            else:
                                shouldRecurse = True
                                recurseDueTime = Scheduler.normalize(nextDue -
                                                                     now)
                                self.running = False
                        elif self.hasCompleted:
                            if self.completeAt <= now and not shouldYield:
                                hasCompleted = True
                            else:
                                shouldRecurse = True
                                recurseDueTime = Scheduler.normalize(
                                    self.completeAt - now)
                                self.running = False
                        else:
                            self.running = False
                            self.active = False
                # end with self.gate

                if hasValue:
                    self.observer.onNext(value)
                    shouldYield = True
                else:
                    if hasCompleted:
                        self.observer.onCompleted()
                        self.dispose()
                    elif hasFailed:
                        self.observer.onError(error)
                        self.dispose()
                    elif shouldRecurse:
                        recurse(recurseDueTime)

                    return
Exemple #28
0
  class Sink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(SelectMany.Sink, self).__init__(observer, cancel)
      self.parent = parent
      self.index = -1

    def run(self):
      self.gate = RLock()
      self.isStopped = False
      self.group = CompositeDisposable()

      self.sourceSubscription = SingleAssignmentDisposable()
      self.group.add(self.sourceSubscription)
      self.sourceSubscription.disposable = self.parent.source.subscribeSafe(self)

      return self.group

    def onNext(self, value):
      inner = None

      try:
        if self.parent.withIndex:
          self.index += 1
          inner = self.parent.selectorOnNext(value, self.index)
        else:
          inner = self.parent.selectorOnNext(value)
      except Exception as e:
        with self.gate:
          self.observer.onError(e)
          self.dispose()

      if isinstance(inner, Observable):
        self.subscribeInner(inner)
        return

      # iterable
      try:
        for current in inner:
          self.observer.onNext(current)
      except Exception as e:
        self.observer.onError(e)
        self.dispose()

    def onError(self, exception):
      if self.parent.selectorOnError != None:
        try:
          inner = None

          if self.parent.withIndex:
            self.index += 1
            inner = self.parent.selectorOnError(exception, self.index)
          else:
            inner = self.parent.selectorOnError(exception)
        except Exception as e:
          with self.gate:
            self.observer.onError(e)
            self.dispose()
        else:
          self.subscribeInner(inner)
          self.final()
      else:
        with self.gate:
          self.observer.onError(exception)
          self.dispose()

    def onCompleted(self):
      if self.parent.selectorOnCompleted != None:
        try:
          inner = None

          if self.parent.withIndex:
            inner = self.parent.selectorOnCompleted(self.index)
          else:
            inner = self.parent.selectorOnCompleted()
        except Exception as e:
          with self.gate:
            self.observer.onError(e)
            self.dispose()
            return
        else:
          self.subscribeInner(inner)

      self.final()

    def final(self):
      self.isStopped = True

      if self.group.length == 1:
        #
        # Notice there can be a race between OnCompleted of the source and any
        # of the inner sequences, where both see _group.Count == 1, and one is
        # waiting for the lock. There won't be a double OnCompleted observation
        # though, because the call to Dispose silences the observer by swapping
        # in a NopObserver<T>.
        #
        with self.gate:
          self.observer.onCompleted()
          self.dispose()
      else:
        self.sourceSubscription.dispose()

    def subscribeInner(self, inner):
      innerSubscription = SingleAssignmentDisposable()
      self.group.add(innerSubscription)
      innerSubscription.disposable = inner.subscribeSafe(self.LockingObserver(self, innerSubscription))

    class LockingObserver(Observer):
      def __init__(self, parent, subscription):
        self.parent = parent
        self.subscription = subscription

      def onNext(self, value):
        with self.parent.gate:
          self.parent.observer.onNext(value)

      def onError(self, exception):
        with self.parent.gate:
          self.parent.observer.onError(exception)
          self.parent.dispose()

      def onCompleted(self):
        self.parent.group.remove(self.subscription)

        if self.parent.isStopped and self.parent.group.length == 1:
          #
          # Notice there can be a race between OnCompleted of the source and any
          # of the inner sequences, where both see _group.Count == 1, and one is
          # waiting for the lock. There won't be a double OnCompleted observation
          # though, because the call to Dispose silences the observer by swapping
          # in a NopObserver<T>.
          #
          with self.parent.gate:
            self.parent.observer.onCompleted()
            self.parent.dispose()
Exemple #29
0
    class Sink(rx.linq.sink.Sink):
        def __init__(self, parent, observer, cancel):
            super(SelectMany.Sink, self).__init__(observer, cancel)
            self.parent = parent
            self.index = -1

        def run(self):
            self.gate = RLock()
            self.isStopped = False
            self.group = CompositeDisposable()

            self.sourceSubscription = SingleAssignmentDisposable()
            self.group.add(self.sourceSubscription)
            self.sourceSubscription.disposable = self.parent.source.subscribeSafe(
                self)

            return self.group

        def onNext(self, value):
            inner = None

            try:
                if self.parent.withIndex:
                    self.index += 1
                    inner = self.parent.selectorOnNext(value, self.index)
                else:
                    inner = self.parent.selectorOnNext(value)
            except Exception as e:
                with self.gate:
                    self.observer.onError(e)
                    self.dispose()

            if isinstance(inner, Observable):
                self.subscribeInner(inner)
                return

            # iterable
            try:
                for current in inner:
                    self.observer.onNext(current)
            except Exception as e:
                self.observer.onError(e)
                self.dispose()

        def onError(self, exception):
            if self.parent.selectorOnError != None:
                try:
                    inner = None

                    if self.parent.withIndex:
                        self.index += 1
                        inner = self.parent.selectorOnError(
                            exception, self.index)
                    else:
                        inner = self.parent.selectorOnError(exception)
                except Exception as e:
                    with self.gate:
                        self.observer.onError(e)
                        self.dispose()
                else:
                    self.subscribeInner(inner)
                    self.final()
            else:
                with self.gate:
                    self.observer.onError(exception)
                    self.dispose()

        def onCompleted(self):
            if self.parent.selectorOnCompleted != None:
                try:
                    inner = None

                    if self.parent.withIndex:
                        inner = self.parent.selectorOnCompleted(self.index)
                    else:
                        inner = self.parent.selectorOnCompleted()
                except Exception as e:
                    with self.gate:
                        self.observer.onError(e)
                        self.dispose()
                        return
                else:
                    self.subscribeInner(inner)

            self.final()

        def final(self):
            self.isStopped = True

            if self.group.length == 1:
                #
                # Notice there can be a race between OnCompleted of the source and any
                # of the inner sequences, where both see _group.Count == 1, and one is
                # waiting for the lock. There won't be a double OnCompleted observation
                # though, because the call to Dispose silences the observer by swapping
                # in a NopObserver<T>.
                #
                with self.gate:
                    self.observer.onCompleted()
                    self.dispose()
            else:
                self.sourceSubscription.dispose()

        def subscribeInner(self, inner):
            innerSubscription = SingleAssignmentDisposable()
            self.group.add(innerSubscription)
            innerSubscription.disposable = inner.subscribeSafe(
                self.LockingObserver(self, innerSubscription))

        class LockingObserver(Observer):
            def __init__(self, parent, subscription):
                self.parent = parent
                self.subscription = subscription

            def onNext(self, value):
                with self.parent.gate:
                    self.parent.observer.onNext(value)

            def onError(self, exception):
                with self.parent.gate:
                    self.parent.observer.onError(exception)
                    self.parent.dispose()

            def onCompleted(self):
                self.parent.group.remove(self.subscription)

                if self.parent.isStopped and self.parent.group.length == 1:
                    #
                    # Notice there can be a race between OnCompleted of the source and any
                    # of the inner sequences, where both see _group.Count == 1, and one is
                    # waiting for the lock. There won't be a double OnCompleted observation
                    # though, because the call to Dispose silences the observer by swapping
                    # in a NopObserver<T>.
                    #
                    with self.parent.gate:
                        self.parent.observer.onCompleted()
                        self.parent.dispose()
Exemple #30
0
class GetIterator(Observer):
  def __init__(self):
    self.queue = Queue()
    self.gate = Semaphore(0)
    self.subscription = SingleAssignmentDisposable()
    self.error = None
    self.done = False
    self.disposed = False

  def run(self, source):
    # [OK] Use of unsafe Subscribe: non-pretentious exact mirror with the dual GetEnumerator method.
    self.subscription.disposable = source.subscribe(self)
    return self

  def onNext(self, value):
    self.queue.put(value)
    self.gate.release()

  def onError(self, exception):
    self.error = exception
    self.subscription.dispose()
    self.gate.release()

  def onCompleted(self):
    self.done = True
    self.subscription.dispose()
    self.gate.release()

  def __iter__(self):
    return self

  def __next__(self):
    self.gate.acquire()

    if self.disposed:
      raise DisposedException()

    try:
      return self.queue.get(True, 0)
    except Empty:
      pass

    if self.error != None:
      raise self.error

    assert self.done

    self.gate.release()

    raise StopIteration()

  def dispose(self):
    self.subscription.dispose()
    self.disposed = True
    self.gate.release()

  class Sink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(GetIterator.Sink, self).__init__(observer, cancel)
      self.parent = parent
      self.currentKey = None
      self.hasCurrentKey = False

    def onNext(self, value):
      try:
        key = self.parent.keySelector(value)
      except Exception as e:
        self.observer.onError(e)
        self.dispose()
      else:
        equal = False

        if self.hasCurrentKey:
          try:
            equal = self.currentKey == key
          except Exception as e:
            self.observer.onError(e)
            self.dispose()

        if not self.hasCurrentKey or not equal:
          self.hasCurrentKey = True
          self.currentKey = key
          self.observer.onNext(value)

    def onError(self, exception):
      self.observer.onError(exception)
      self.dispose()

    def onCompleted(self):
      self.observer.onCompleted()
      self.dispose()
Exemple #31
0
class GetIterator(Observer):
    def __init__(self):
        self.queue = Queue()
        self.gate = Semaphore(0)
        self.subscription = SingleAssignmentDisposable()
        self.error = None
        self.done = False
        self.disposed = False

    def run(self, source):
        # [OK] Use of unsafe Subscribe: non-pretentious exact mirror with the dual GetEnumerator method.
        self.subscription.disposable = source.subscribe(self)
        return self

    def onNext(self, value):
        self.queue.put(value)
        self.gate.release()

    def onError(self, exception):
        self.error = exception
        self.subscription.dispose()
        self.gate.release()

    def onCompleted(self):
        self.done = True
        self.subscription.dispose()
        self.gate.release()

    def __iter__(self):
        return self

    def __next__(self):
        self.gate.acquire()

        if self.disposed:
            raise DisposedException()

        try:
            return self.queue.get(True, 0)
        except Empty:
            pass

        if self.error != None:
            raise self.error

        assert self.done

        self.gate.release()

        raise StopIteration()

    def dispose(self):
        self.subscription.dispose()
        self.disposed = True
        self.gate.release()

    class Sink(rx.linq.sink.Sink):
        def __init__(self, parent, observer, cancel):
            super(GetIterator.Sink, self).__init__(observer, cancel)
            self.parent = parent
            self.currentKey = None
            self.hasCurrentKey = False

        def onNext(self, value):
            try:
                key = self.parent.keySelector(value)
            except Exception as e:
                self.observer.onError(e)
                self.dispose()
            else:
                equal = False

                if self.hasCurrentKey:
                    try:
                        equal = self.currentKey == key
                    except Exception as e:
                        self.observer.onError(e)
                        self.dispose()

                if not self.hasCurrentKey or not equal:
                    self.hasCurrentKey = True
                    self.currentKey = key
                    self.observer.onNext(value)

        def onError(self, exception):
            self.observer.onError(exception)
            self.dispose()

        def onCompleted(self):
            self.observer.onCompleted()
            self.dispose()
Exemple #32
0
  class ConcurrentSink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(Merge.ConcurrentSink, self).__init__(observer, cancel)
      self.parent = parent

    def run(self):
      self.gate = RLock()
      self.q = Queue()
      self.isStopped = False
      self.activeCount = 0

      self.group = CompositeDisposable()
      self.sourceSubscription = SingleAssignmentDisposable()
      self.group.add(self.sourceSubscription)
      self.sourceSubscription.disposable = self.parent.sources.subscribeSafe(self)

      return self.group

    def onNext(self, value):
      with self.gate:
        if self.activeCount < self.parent.maxConcurrency:
          self.activeCount += 1
          self.subscribe(value)
        else:
          self.q.put_nowait(value)

    def onError(self, exception):
      with self.gate:
        self.observer.onError(exception)
        self.dispose()

    def onCompleted(self):
      with self.gate:
        self.isStopped = True

        if self.activeCount == 0:
          self.observer.onCompleted()
          self.dispose()
        else:
          self.sourceSubscription.dispose()

    def subscribe(self, innerSource):
      subscription = SingleAssignmentDisposable()
      self.group.add(subscription)
      subscription.disposable = innerSource.subscribeSafe(self.LockObserver(self, subscription))

    class LockObserver(Observer):
      def __init__(self, parent, subscription):
        self.parent = parent
        self.subscription = subscription

      def onNext(self, value):
        with self.parent.gate:
          self.parent.observer.onNext(value)

      def onError(self, exception):
        with self.parent.gate:
          self.parent.observer.onError(exception)
          self.parent.dispose()

      def onCompleted(self):
        self.parent.group.remove(self.subscription)

        with self.parent.gate:
          if self.parent.q.qsize() > 0:
            s = self.q.get()
            self.parent.subscribe(s)
          else:
            self.parent.activeCount -= 1

            if self.parent.isStopped and self.parent.activeCount == 0:
              self.parent.observer.onCompleted()
              self.parent.dispose()
Exemple #33
0
  class Sink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(DelayTime.Sink, self).__init__(observer, cancel)
      self.parent = parent

    def run(self):
      self.scheduler = self.parent.scheduler

      self.cancelTimer = SerialDisposable()

      self.gate = RLock()
      self.active = False # as soon as a value arrived
      self.running = False # on relative: True, on absolute: True after absolute time
      self.queue = deque()
      self.hasCompleted = False
      self.completeAt = 0
      self.hasFailed = False
      self.exception = None

      self.delay = 0
      self.startTime = self.scheduler.now()

      if self.parent.isAbsolute:
        self.ready = False
        self.cancelTimer.disposable = self.scheduler.scheduleWithAbsolute(
          self.parent.dueTime,
          self.start
        )
      else:
        self.ready = True
        self.delay = Scheduler.normalize(self.parent.dueTime)

      self.sourceSubscription = SingleAssignmentDisposable()
      self.sourceSubscription.disposable = self.parent.source.subscribeSafe(self)

      return CompositeDisposable(self.sourceSubscription, self.cancelTimer)

    def elapsed(self):
      return self.scheduler.now() - self.startTime

    def start(self):
      next = 0
      shouldRun = False

      with self.gate:
        self.delay = self.elapsed()

        if len(self.queue) > 0:
          next = self.queue[0].interval

          for item in self.queue:
            item.interval += self.delay

          shouldRun = True
          self.active = True

        self.ready = True

      if shouldRun:
        self.cancelTimer.disposable = self.scheduler.scheduleRecursiveWithRelative(
          next,
          self.drainQueue
        )

    def onNext(self, value):
      next = self.elapsed() + self.delay
      shouldRun = False

      with self.gate:
        self.queue.append(Struct(value=value, interval=next))
        shouldRun = self.ready and (not self.active)
        self.active = True

      if shouldRun:
        self.cancelTimer.disposable = self.scheduler.scheduleRecursiveWithRelative(
          self.delay,
          self.drainQueue
        )

    def onError(self, exception):
      self.sourceSubscription.dispose()

      shouldRun = False

      with self.gate:
        self.queue.clear()

        self.exception = exception
        self.hasFailed = True

        shouldRun = not self.running

      if shouldRun:
        self.observer.onError(exception)
        self.dispose()

    def onCompleted(self):
      self.sourceSubscription.dispose()

      next = self.elapsed() + self.delay
      shouldRun = False

      with self.gate:
        self.completeAt = next
        self.hasCompleted = True

        shouldRun = self.ready and (not self.active)
        self.active = True

      if shouldRun:
        self.cancelTimer.disposable = self.scheduler.scheduleRecursiveWithRelative(
          self.delay,
          self.drainQueue
        )

    def drainQueue(self, recurse):
      with self.gate:
        if self.hasFailed:
          return
        self.running = True


      #
      # The shouldYield flag was added to address TFS 487881: "Delay can be unfair". In the old
      # implementation, the loop below kept running while there was work for immediate dispatch,
      # potentially causing a long running work item on the target scheduler. With the addition
      # of long-running scheduling in Rx v2.0, we can check whether the scheduler supports this
      # interface and perform different processing (see LongRunningSink). To reduce the code churn in the old
      # loop code here, we set the shouldYield flag to true after the first dispatch iteration,
      # in order to break from the loop and enter the recursive scheduling path.

      shouldYield = False

      while True:
        hasFailed = False
        error = None

        value = None
        hasValue = False

        hasCompleted = False

        shouldRecurse = False
        recurseDueTime = 0

        with self.gate:
          if self.hasFailed:
            error = self.exception
            hasFailed = True
            self.running = False
          else:
            now = self.elapsed()

            if len(self.queue) > 0:
              nextDue = self.queue[0].interval

              if nextDue <= now and not shouldYield:
                value = self.queue.popleft().value
                hasValue = True
              else:
                shouldRecurse = True
                recurseDueTime = Scheduler.normalize(nextDue - now)
                self.running = False
            elif self.hasCompleted:
              if self.completeAt <= now and not shouldYield:
                hasCompleted = True
              else:
                shouldRecurse = True
                recurseDueTime = Scheduler.normalize(self.completeAt - now)
                self.running = False
            else:
              self.running = False
              self.active = False
        # end with self.gate

        if hasValue:
          self.observer.onNext(value)
          shouldYield = True
        else:
          if hasCompleted:
            self.observer.onCompleted()
            self.dispose()
          elif hasFailed:
            self.observer.onError(error)
            self.dispose()
          elif shouldRecurse:
            recurse(recurseDueTime)

          return