{"action":"created","issue":{"url":"https://api.github.com/repos/scalaz/scalaz-stream/issues/320","labels_url":"https://api.github.com/repos/scalaz/scalaz-stream/issues/320/labels{/name}","comments_url":"https://api.github.com/repos/scalaz/scalaz-stream/issues/320/comments","events_url":"https://api.github.com/repos/scalaz/scalaz-stream/issues/320/events","html_url":"https://github.com/scalaz/scalaz-stream/pull/320","id":57834364,"number":320,"title":"Implemented io.toInputStream: Process[Task, Array[Byte]] => InputStream","user":{"login":"djspiewak","id":752,"avatar_url":"https://avatars.githubusercontent.com/u/752?v=3","gravatar_id":"","url":"https://api.github.com/users/djspiewak","html_url":"https://github.com/djspiewak","followers_url":"https://api.github.com/users/djspiewak/followers","following_url":"https://api.github.com/users/djspiewak/following{/other_user}","gists_url":"https://api.github.com/users/djspiewak/gists{/gist_id}","starred_url":"https://api.github.com/users/djspiewak/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/djspiewak/subscriptions","organizations_url":"https://api.github.com/users/djspiewak/orgs","repos_url":"https://api.github.com/users/djspiewak/repos","events_url":"https://api.github.com/users/djspiewak/events{/privacy}","received_events_url":"https://api.github.com/users/djspiewak/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-02-16T17:57:17Z","updated_at":"2015-02-16T18:15:16Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/scalaz/scalaz-stream/pulls/320","html_url":"https://github.com/scalaz/scalaz-stream/pull/320","diff_url":"https://github.com/scalaz/scalaz-stream/pull/320.diff","patch_url":"https://github.com/scalaz/scalaz-stream/pull/320.patch"},"body":"Hurray for Java! There are a couple of very nice things about this implementation:\r\n\r\n- Support for early termination via `close()` (all finalizers will run)\r\n- In theory, somewhat faster than implementations on top of `toTask`\r\n- ROAR TESTS!\r\n- Somewhat more flexible chunking support\r\n- Implemented not-naively, so chunked reads will work as `InputStream` expects\r\n\r\nThe actual signature of the method is as follows:\r\n\r\n```scala\r\ndef toInputStream[A](p: Process[Task, A])(chunk: A => Array[Byte]): InputStream\r\n```\r\n\r\nThis gives some wiggle room in terms of the types within the process, allowing for things like `ByteBuffer` and such.  An even *more* interesting type signature signature would be the following:\r\n\r\n```scala\r\ndef toInputStream[A](p: Process[Task, A])(copy: (A, Array[Byte], Int, Int]) => Unit): InputStream\r\n```\r\n\r\nThis type signature is nice because it eliminates garbage intermediate chunk storage.  If your stream does not contain byte arrays, and you have no need to manipulate byte arrays (e.g. when your stream actually contains direct `ByteBuffer`(s)), then this signature will allow one-copy streaming into the resulting `InputStream`.  I can't bring myself to type that signature with a straight face though, because it really is awful.\r\n\r\nIn other news, this addresses the only major `toTask` use-case raised in #317."},"comment":{"url":"https://api.github.com/repos/scalaz/scalaz-stream/issues/comments/74550806","html_url":"https://github.com/scalaz/scalaz-stream/pull/320#issuecomment-74550806","issue_url":"https://api.github.com/repos/scalaz/scalaz-stream/issues/320","id":74550806,"user":{"login":"djspiewak","id":752,"avatar_url":"https://avatars.githubusercontent.com/u/752?v=3","gravatar_id":"","url":"https://api.github.com/users/djspiewak","html_url":"https://github.com/djspiewak","followers_url":"https://api.github.com/users/djspiewak/followers","following_url":"https://api.github.com/users/djspiewak/following{/other_user}","gists_url":"https://api.github.com/users/djspiewak/gists{/gist_id}","starred_url":"https://api.github.com/users/djspiewak/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/djspiewak/subscriptions","organizations_url":"https://api.github.com/users/djspiewak/orgs","repos_url":"https://api.github.com/users/djspiewak/repos","events_url":"https://api.github.com/users/djspiewak/events{/privacy}","received_events_url":"https://api.github.com/users/djspiewak/received_events","type":"User","site_admin":false},"created_at":"2015-02-16T18:15:16Z","updated_at":"2015-02-16T18:15:16Z","body":"The problem that I have with `ByteVector` is the native implementation is very inefficient, while the direct `ByteBuffer` implementation is inapplicable to some problems.  There are a lot of use cases where you would want to stream a process out to an `InputStream`, and the elements of that process *logically* represent byte chunks, but actually reifying those chunks as `Array[Byte]` or (equivalently) as `ByteVector` would require an extra copy step.\r\n\r\nGranted, my `A => Array[Byte]` signature doesn't really fix that problem.  :-)  If you don't experience violent revulsion and tingling in the extremities at the sight of the `copy` type signature, I'll take a crack at switching over to that, since it *is* much more efficient."}}