-
Notifications
You must be signed in to change notification settings - Fork 604
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move j.u.c.Flow
interop methods onto Stream
#3346
Changes from 5 commits
87216d3
bbf9992
2936c84
70d985b
e042dd5
3e89901
b4c9822
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,8 +23,8 @@ package fs2 | |
package interop | ||
package flow | ||
|
||
import cats.effect.kernel.{Async, Outcome} | ||
import cats.effect.syntax.all._ | ||
import cats.effect.kernel.Async | ||
import cats.effect.Resource.ExitCase | ||
import cats.syntax.all._ | ||
|
||
import java.util.concurrent.CancellationException | ||
|
@@ -60,7 +60,7 @@ private[flow] final class StreamSubscription[F[_], A] private ( | |
|
||
// This is a def rather than a val, because it is only used once. | ||
// And having fields increase the instantiation cost and delay garbage collection. | ||
def run: F[Unit] = { | ||
def run: Stream[F, Nothing] = { | ||
val subscriptionPipe: Pipe[F, A, A] = in => { | ||
def go(s: Stream[F, A]): Pull[F, A, Unit] = | ||
Pull.eval(F.delay(requests.get())).flatMap { n => | ||
|
@@ -100,8 +100,14 @@ private[flow] final class StreamSubscription[F[_], A] private ( | |
.through(subscriptionPipe) | ||
.chunks | ||
.foreach(chunk => F.delay(chunk.foreach(sub.onNext))) | ||
.compile | ||
.drain | ||
.onFinalizeCase { | ||
case ExitCase.Succeeded => F.delay(onComplete()) | ||
case ExitCase.Errored(ex) => F.delay(onError(ex)) | ||
case ExitCase.Canceled => | ||
// if the subscriber canceled us, no further action necessary | ||
// if we were externally canceled, this is handled below | ||
F.unit | ||
} | ||
|
||
val cancellation = F.asyncCheckAttempt[Unit] { cb => | ||
F.delay { | ||
|
@@ -115,18 +121,12 @@ private[flow] final class StreamSubscription[F[_], A] private ( | |
} | ||
|
||
events | ||
.race(cancellation) | ||
.guaranteeCase { | ||
case Outcome.Succeeded(result) => | ||
result.flatMap { | ||
case Left(()) => F.delay(onComplete()) // Events finished normally. | ||
case Right(()) => F.unit // Events was canceled. | ||
} | ||
case Outcome.Errored(ex) => F.delay(onError(ex)) | ||
case Outcome.Canceled() => | ||
.mergeHaltBoth(Stream.exec(cancellation)) | ||
.onFinalizeCase { | ||
case ExitCase.Canceled => | ||
F.delay(onError(new CancellationException("StreamSubscription.run was canceled"))) | ||
case _ => F.unit | ||
} | ||
.void | ||
} | ||
|
||
// According to the spec, it's acceptable for a concurrent cancel to not | ||
|
@@ -192,9 +192,8 @@ private[flow] object StreamSubscription { | |
|
||
def subscribe[F[_], A](stream: Stream[F, A], subscriber: Subscriber[A])(implicit | ||
F: Async[F] | ||
): F[Unit] = | ||
apply(stream, subscriber).flatMap { subscription => | ||
F.delay(subscriber.onSubscribe(subscription)) >> | ||
subscription.run | ||
): Stream[F, Nothing] = | ||
Stream.eval(apply(stream, subscriber)).flatMap { subscription => | ||
Stream.eval(F.delay(subscriber.onSubscribe(subscription))) >> subscription.run | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If it's exec, then The two options are: Stream.eval(...) >> subscription.run
Stream.exec(...) ++ subscription.run The former felt more appropriate to me, it establishes the monadic dependence. Not sure what the subtle differences are. |
||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the one I'm most interested in. It is the
Stream
analog ofio.unsafeToFuture()
.The motivation is to facilitate interop with other libraries e.g. raquo/Airstream#114:
EventStream.fromPublisher(fs2Stream.unsafeToPublisher())