@@ -109,30 +109,30 @@ private[fs2] trait ioplatform {
109109 /** `Pipe` that converts a stream of bytes to a stream that will emit a single `Readable`,
110110 * that ends whenever the resulting stream terminates.
111111 */
112- def toReadable [F [_]](implicit F : Async [F ]): Pipe [F , Byte , Readable ] =
113- in =>
114- Stream
115- .resource(mkDuplex(in))
116- .flatMap { case (duplex, out) =>
117- Stream
118- .emit(duplex)
119- .merge(out.drain)
120- .concurrently(
121- Stream .eval(
122- F .async_[Unit ](cb =>
123- duplex.end { e =>
124- cb(e.filterNot(_ == null ).toLeft(()).leftMap(js.JavaScriptException ))
125- }
126- )
127- )
128- )
129- }
130- .adaptError { case IOException (ex) => ex }
112+ def toReadable [F [_]: Async ]: Pipe [F , Byte , Readable ] =
113+ in => Stream .resource(toReadableResource(in))
131114
132115 /** Like [[toReadable ]] but returns a `Resource` rather than a single element stream.
133116 */
134- def toReadableResource [F [_]: Async ](s : Stream [F , Byte ]): Resource [F , Readable ] =
135- s.through(toReadable).compile.resource.lastOrError
117+ def toReadableResource [F [_]](s : Stream [F , Byte ])(implicit F : Async [F ]): Resource [F , Readable ] =
118+ mkDuplex(s)
119+ .flatMap { case (duplex, out) =>
120+ out
121+ .concurrently(
122+ Stream .eval(
123+ F .async_[Unit ](cb =>
124+ duplex.end { e =>
125+ cb(e.filterNot(_ == null ).toLeft(()).leftMap(js.JavaScriptException ))
126+ }
127+ )
128+ )
129+ )
130+ .compile
131+ .drain
132+ .background
133+ .as(duplex)
134+ }
135+ .adaptError { case IOException (ex) => ex }
136136
137137 /** Writes all bytes to the specified `Writable`.
138138 */
@@ -206,7 +206,7 @@ private[fs2] trait ioplatform {
206206 errorDispatcher <- Dispatcher .sequential[F ]
207207 readQueue <- Queue .bounded[F , Option [Chunk [Byte ]]](1 ).toResource
208208 writeChannel <- Channel .synchronous[F , Chunk [Byte ]].toResource
209- error <- F .deferred[Throwable ].toResource
209+ interrupt <- F .deferred[Either [ Throwable , Unit ] ].toResource
210210 duplex <- Resource .make {
211211 F .delay {
212212 new facade.stream.Duplex (
@@ -236,10 +236,9 @@ private[fs2] trait ioplatform {
236236
237237 var destroy = { (_, err, cb) =>
238238 errorDispatcher.unsafeRunAndForget {
239- error
239+ interrupt
240240 .complete(
241- Option (err)
242- .fold[Exception ](new StreamDestroyedException )(js.JavaScriptException (_))
241+ Option (err).map(js.JavaScriptException (_)).toLeft(())
243242 ) *> F .delay(cb(null ))
244243 }
245244 }
@@ -254,10 +253,9 @@ private[fs2] trait ioplatform {
254253 }
255254 drainIn = in.enqueueNoneTerminatedChunks(readQueue).drain
256255 out = writeChannel.stream.unchunks
257- .concurrently(Stream .eval(error.get.flatMap(F .raiseError[Unit ])))
258256 } yield (
259257 duplex,
260- drainIn.merge(out).adaptError { case IOException (ex) => ex }
258+ drainIn.merge(out).interruptWhen(interrupt). adaptError { case IOException (ex) => ex }
261259 )
262260
263261 /** Stream of bytes read asynchronously from standard input. */
0 commit comments