You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
90 lines
3.2 KiB
90 lines
3.2 KiB
//
|
|
// pausableBuffered.swift
|
|
// RxSwiftExt
|
|
//
|
|
// Created by Tanguy Helesbeux on 24/05/2017.
|
|
// Copyright © 2017 RxSwift Community. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import RxSwift
|
|
|
|
extension ObservableType {
|
|
|
|
/**
|
|
Pauses the elements of the source observable sequence based on the latest element from the second observable sequence.
|
|
|
|
While paused, elements from the source are buffered, limited to a maximum number of element.
|
|
|
|
When resumed, all bufered elements are flushed as single events in a contiguous stream.
|
|
|
|
- seealso: [pausable operator on reactivex.io](http://reactivex.io/documentation/operators/backpressure.html)
|
|
|
|
- parameter pauser: The observable sequence used to pause the source observable sequence.
|
|
- parameter limit: The maximum number of element buffered. Pass `nil` to buffer all elements without limit. Default 1.
|
|
- parameter flushOnCompleted: If `true` bufered elements will be flushed when the source completes. Default `true`.
|
|
- parameter flushOnError: If `true` bufered elements will be flushed when the source errors. Default `true`.
|
|
- returns: The observable sequence which is paused and resumed based upon the pauser observable sequence.
|
|
*/
|
|
public func pausableBuffered<P: ObservableType> (_ pauser: P, limit: Int? = 1, flushOnCompleted: Bool = true, flushOnError: Bool = true) -> Observable<E> where P.E == Bool {
|
|
|
|
return Observable<E>.create { observer in
|
|
var buffer: [E] = []
|
|
if let limit = limit {
|
|
buffer.reserveCapacity(limit)
|
|
}
|
|
|
|
var paused = true
|
|
let lock = NSRecursiveLock()
|
|
|
|
let flush = {
|
|
for value in buffer {
|
|
observer.onNext(value)
|
|
}
|
|
buffer.removeAll(keepingCapacity: limit != nil)
|
|
}
|
|
|
|
let boundaryDisposable = pauser.subscribe { event in
|
|
lock.lock(); defer { lock.unlock() }
|
|
switch event {
|
|
case .next(let resume):
|
|
paused = !resume
|
|
|
|
if resume && buffer.count > 0 {
|
|
flush()
|
|
}
|
|
case .completed:
|
|
observer.onCompleted()
|
|
case .error(let error):
|
|
observer.onError(error)
|
|
}
|
|
}
|
|
|
|
let disposable = self.subscribe { event in
|
|
lock.lock(); defer { lock.unlock() }
|
|
switch event {
|
|
case .next(let element):
|
|
if paused {
|
|
buffer.append(element)
|
|
if let limit = limit, buffer.count > limit {
|
|
buffer.remove(at: 0)
|
|
}
|
|
} else {
|
|
observer.onNext(element)
|
|
}
|
|
|
|
case .completed:
|
|
if flushOnCompleted { flush() }
|
|
observer.onCompleted()
|
|
|
|
case .error(let error):
|
|
if flushOnError { flush() }
|
|
observer.onError(error)
|
|
}
|
|
}
|
|
|
|
return Disposables.create([disposable, boundaryDisposable])
|
|
}
|
|
}
|
|
|
|
}
|