All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
monifu.reactive.internals.operators.window.scala Maven / Gradle / Ivy
/*
* Copyright (c) 2014-2015 by its authors. Some rights reserved.
* See the project homepage at: http://www.monifu.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package monifu.reactive.internals.operators
import monifu.reactive.Ack.{Cancel, Continue}
import monifu.reactive.internals._
import monifu.reactive.subjects.ReplaySubject
import monifu.reactive.{Ack, Observable, Observer}
import scala.collection.mutable
import scala.concurrent.Future
import scala.concurrent.duration.{Duration, FiniteDuration}
private[reactive] object window {
/** Implementation for [[Observable.window]] */
def skipped[T](source: Observable[T], count: Int, skip: Int): Observable[Observable[T]] = {
require(count > 0, "count must be strictly positive")
require(skip > 0, "skip must be strictly positive")
if (count == skip)
sizedFixed(source, count)
else if (skip < count)
sizedOverlap(source, count, skip)
else // skip > count
sizedDrop(source, count, skip)
}
private def sizedFixed[T](source: Observable[T], count: Int) = {
require(count > 0, "count must be strictly positive")
Observable.create[Observable[T]] { subscriber =>
implicit val s = subscriber.scheduler
val observer = subscriber.observer
source.onSubscribe(new Observer[T] {
private[this] var isDone = false
private[this] var buffer = ReplaySubject[T]()
private[this] var ack = observer.onNext(buffer)
private[this] var leftToPush = count
def onNext(elem: T): Future[Ack] =
if (isDone) Cancel
else {
if (leftToPush > 0) {
leftToPush -= 1
buffer.onNext(elem)
}
else {
buffer.onComplete()
buffer = ReplaySubject(elem)
leftToPush = count - 1
val previousAck = ack
ack = ack.onContinueStreamOnNext(observer, buffer)
previousAck
}
}
def onError(ex: Throwable): Unit = {
if (!isDone) {
isDone = true
buffer.onComplete()
ack.onContinueSignalError(observer, ex)
buffer = null
}
}
def onComplete(): Unit = {
if (!isDone) {
isDone = true
buffer.onComplete()
ack.onContinueSignalComplete(observer)
buffer = null
}
}
})
}
}
def sizedOverlap[T](source: Observable[T], count: Int, skip: Int): Observable[Observable[T]] = {
require(count > 0, "count must be strictly positive")
require(skip > 0, "skip must be strictly positive")
assert(skip < count, "skip < count")
Observable.create { subscriber =>
implicit val s = subscriber.scheduler
val observer = subscriber.observer
source.onSubscribe(new Observer[T] {
private[this] var isDone = false
private[this] var buffer = ReplaySubject[T]()
private[this] var ack = observer.onNext(buffer)
private[this] var leftToPush = count
private[this] val overlap = count - skip
private[this] val queue = mutable.ArrayBuffer.empty[T]
def onNext(elem: T): Future[Ack] =
if (isDone) Cancel else {
if (leftToPush > 0) {
if (leftToPush <= overlap) queue += elem
leftToPush -= 1
buffer.onNext(elem)
}
else {
buffer.onComplete()
queue += elem
buffer = ReplaySubject(queue:_*)
queue.clear()
leftToPush = count - (overlap + 1)
if (leftToPush <= overlap) queue += elem
val previousAck = ack
ack = ack.onContinueStreamOnNext(observer, buffer)
previousAck
}
}
def onError(ex: Throwable): Unit = {
if (!isDone) {
isDone = true
buffer.onComplete()
ack.onContinueSignalError(observer, ex)
buffer = null
}
}
def onComplete(): Unit = {
if (!isDone) {
isDone = true
buffer.onComplete()
ack.onContinueSignalComplete(observer)
buffer = null
}
}
})
}
}
private def sizedDrop[T](source: Observable[T], count: Int, skip: Int): Observable[Observable[T]] = {
require(count > 0, "count must be strictly positive")
require(skip > 0, "skip must be strictly positive")
assert(skip > count, "skip > drop")
Observable.create { subscriber =>
implicit val s = subscriber.scheduler
val observer = subscriber.observer
source.onSubscribe(new Observer[T] {
private[this] var isDone = false
private[this] var buffer = ReplaySubject[T]()
private[this] var ack = observer.onNext(buffer)
private[this] var leftToPush = count
private[this] var leftToDrop = 0
def onNext(elem: T): Future[Ack] =
if (isDone) Cancel else {
if (leftToDrop > 0) {
leftToDrop -= 1
Continue
}
else if (leftToPush > 0) {
leftToPush -= 1
buffer.onNext(elem)
}
else {
buffer.onComplete()
leftToDrop = skip - count - 1
leftToPush = count
buffer = ReplaySubject()
val previousAck = ack
ack = ack.onContinueStreamOnNext(observer, buffer)
previousAck
}
}
def onError(ex: Throwable): Unit = {
if (!isDone) {
isDone = true
buffer.onComplete()
ack.onContinueSignalError(observer, ex)
buffer = null
}
}
def onComplete(): Unit = {
if (!isDone) {
isDone = true
buffer.onComplete()
ack.onContinueSignalComplete(observer)
buffer = null
}
}
})
}
}
/**
* Implementation for [[Observable.window]].
*/
def timed[T](source: Observable[T], timespan: FiniteDuration, maxCount: Int): Observable[Observable[T]] = {
require(timespan >= Duration.Zero, "timespan must be positive")
require(maxCount >= 0, "maxCount must be positive")
Observable.create { subscriber =>
implicit val s = subscriber.scheduler
val observer = subscriber.observer
source.onSubscribe(new Observer[T] {
private[this] val timespanMillis = timespan.toMillis
private[this] var expiresAt = s.currentTimeMillis() + timespanMillis
private[this] var size = 0
private[this] var isDone = false
private[this] var buffer = ReplaySubject[T]()
private[this] var ack = observer.onNext(buffer)
def onNext(elem: T): Future[Ack] =
if (isDone) Cancel else {
val rightNow = s.currentTimeMillis()
val hasExpired = expiresAt <= rightNow ||
(maxCount > 0 && size >= maxCount)
if (!hasExpired) {
size += 1
buffer.onNext(elem)
}
else {
buffer.onComplete()
buffer = ReplaySubject(elem)
expiresAt = rightNow + timespanMillis
size = 1
val previousAck = ack
ack = ack.onContinueStreamOnNext(observer, buffer)
previousAck
}
}
def onError(ex: Throwable): Unit = {
if (!isDone) {
isDone = true
buffer.onComplete()
ack.onContinueSignalError(observer, ex)
buffer = null
}
}
def onComplete(): Unit = {
if (!isDone) {
isDone = true
buffer.onComplete()
ack.onContinueSignalComplete(observer)
buffer = null
}
}
})
}
}
}