thrownewError"The provided source must be either a readable stream or a Buffer, or a callback providing either of those. If it is currently a string, you need to convert it to a Buffer yourself and ensure that the encoding is correct."
# If the 'source' is a function, then it's actually a callback that will *return* the source. We call the callback, and supply it with a `next` function that will post-process the source, and eventually trigger the actual read.
# It's a regular source, so we immediately continue.
debug"source %s is already resolved",source[0].toString().replace(/\n/g,"\\n").replace(/\r/g,"\\r")
resolvesource
_initiateRead: ->
Promise.try=>
@_reading = true
@_resolveAllSources()
.then(actualSources) =>
@_sources = actualSources
Promise.resolve()
_read: (size) ->
Promise.try=>
if@_reading==false
@_initiateRead()
else
Promise.resolve()
.then=>
@_doReadsize
_doRead: (size) ->
# FIXME: We should probably try to do something with `size` ourselves. Just passing it on for now, but it'd be nice to implement it properly in the future - this might help efficiency in some cases.
Promise.try=>
if@_currentSource==null
# We're not currently actively reading from any sources. Set a new source to be the current source.
@_nextSourcesize
else
# We haven't changed our source - immediately continue with the actual read.
# We've depleted the stream (ie. we've read 'null') The current source should be set to `null`, so that on the next read a new source will be picked. We'll also immediately trigger the next read - the stream will be expecting to receive *some* kind of data before calling the next read itself.
@_currentSource = null
@_doReadreadSize# FIXME: This should probably use the last-requested read size, not the one that was requested when *setting up* the `end` event.
@_currentSource.on"readable",=>
debug"received readable event, setting sourceDataAvailable to true"
@_sourceDataAvailable = true
if@_wantData
debug"wantData queued, reading"
@_doStreamRead()
Promise.resolve()
# We're wrapping the actual reading code in a separate function, so as to facilitate source-returning callbacks in the sources list.
_doActualRead: (size) =>
# FIXME: Apparently, it may be possible to push more than one chunk in a single _read call. The implementation specifics of this should probably be looked into - that could perhaps make our stream a bit more efficient. On the other hand, shouldn't we leave this for the Writable to decide?
newPromise(resolve, reject) =>
if@_currentIsStream
# This is a readable stream of some sort - we'll do a read, and pass on the result. We'll pass on the `size` parameter, but there's no guarantee that anything will actually be done with it.
if@_sourceDataAvailable
@_doStreamRead()
returnresolve()
else
debug"want data, but no readable event fired yet, setting wantData to true"
@_wantData = true
returnresolve()# We haven't actually read anything yet, but whatever.
else
# This is a Buffer - we'll push it as is, and immediately mark it as completed.
chunk = @_currentSource
# We need to unset it *before* pushing the chunk, because otherwise V8 will sometimes not give control back to this function, and a second read may occur before the source can be unset.
# Since Node.js v0.12, a stream will apparently return null when it is finished... we need to filter this out, to prevent it from ending our combined stream prematurely.