Skip to content
This repository has been archived by the owner on Oct 28, 2023. It is now read-only.

Commit

Permalink
Merge pull request typelevel#3264 from kamilkloch/from-queue-untermin…
Browse files Browse the repository at this point in the history
…ated

Add variant of `Stream.fromQueueUnterminated` for Monad.
  • Loading branch information
diesalbla authored Jul 30, 2023
2 parents 14ecd85 + e992e36 commit 62ba4a1
Showing 1 changed file with 31 additions and 7 deletions.
38 changes: 31 additions & 7 deletions core/shared/src/main/scala/fs2/Stream.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3495,15 +3495,39 @@ object Stream extends StreamLowPriority {
* All elements that are available, up to the specified limit,
* are dequeued and emitted as a single chunk.
*/
def fromQueueUnterminated[F[_]: Functor, A](
def fromQueueUnterminated[F[_], A](
queue: QueueSource[F, A],
limit: Int = Int.MaxValue
): Stream[F, A] =
fromQueueNoneTerminatedSingletons_[F, A](
queue.take.map(a => Some(a)),
queue.tryTake.map(_.map(a => Some(a))),
limit
)
)(implicit F: Functor[F]): Stream[F, A] =
F match {
case f0: Monad[F] =>
if (limit > 1) {

/** use non-blocking tryTakeN, which is possibly more performant than n * take */

val someLimit = Some(limit)
val someLimitLess1 = Some(limit - 1)

/** First, try non-blocking batch dequeue.
* Only if the result is an empty list, semantically block to get one element,
* then attempt 2nd tryTakeN to get any other elements that are immediately available.
*/
val asf = f0.flatMap(queue.tryTakeN(someLimit)(f0)) {
case Nil => f0.map2(queue.take, queue.tryTakeN(someLimitLess1)(f0))(_ :: _)
case as => f0.pure(as)
}

Stream.evalSeq(asf).repeat

} else Stream.repeatEval(queue.take)

case _ =>
fromQueueNoneTerminatedSingletons_[F, A](
queue.take.map(a => Some(a)),
queue.tryTake.map(_.map(a => Some(a))),
limit
)
}

/** Returns a stream of elements from the supplied queue.
*
Expand Down

0 comments on commit 62ba4a1

Please sign in to comment.