Buffers a stream of futures and provides the results as a new stream. 
 
 Futures are collected as fast as possible without the sum of concurrently running futures and available results
 exceeding 
bufferSize.
 
 The new stream contains the results in the completion order of the futures. It blocks while no results are available
 and there are still futures to wait for.
 
 
Exceptional completion of futures
 When one or more of the futures inside the stream complete exceptionally, the new stream will throw that exception
 when an attempt is made to consume the next result. The exception is thrown as is (i.e. not wrapped in
 
ExecutionException as with 
Future.get()). Basically, the new stream behaves as
 if all computations were performed in a synchronous manner.
 
 
Exceptions thrown by the original stream
 If the original stream throws an exception instead of producing a future, the new stream will behave the same way
 as with exceptional completion of futures: the exception will be thrown when an attempt is made to consume the next
 result.
 
 
Usage examples
 
 Stream<Completable<V>> completables;
 Stream<V> values2 = BufferedStreamAdapter.completable().adapt(completables, bufferSize, executorService);
 
 Stream<ListenableFuture<V>> listenables;
 Stream<V> values1 = BufferedStreamAdapter.listenable().adapt(listenables, bufferSize, executorService);