In general I'm not totally sure the best way of handling this. You are doing a sort of inversion of control, converting between control belonging to streams and stream transducers, and the normal java io world, where the user of the InputStream has control. Generally, the more idiomatic thing is to move your logic into the stream world, if possible (i.e., consume the stream with another stream transducer, sink, or channel from scalaz-stream). If that's not possible (sounds like it's not in your case), here are some ideas:
* Send your Process[Task,Byte] to a BlockingQueue[Array[Byte]]. (As Pavel mentioned, using a Process[Task,Seq[Byte]] or Process[Task,Array[Byte]] would be more efficient, and we will be implementing
a solution for this sort of use case.)
* Similarly, use PipedInput/OutputStream
* Use `toTask`. (See below). It is kind of a hack, and it would be nice to have a more principled 'Step' type that could be used for these situations.
Another thing you can do is call `toTask`.
val p: Process[Task,Byte] = ...
val t: Task[Byte] = p.toTask
You can call `t.attemptRun: Throwable \/ Byte` repeatedly. If you get back `Process.End`, that indicates normal termination. It's a hack because it's not resource safe - if you stop examining the `Task` before it completes, finalizers for the stream are not guaranteed to be run. I've created
an issue to track this.
The `toTask` function uses a mutable variable internally, but it's actually pattern matching on the `Process`, so it's not O(n^2) like the repeated `take` and `drop`.