Re: [streams] Support reading bytes into buffers allocated by user code on platforms where only async read is available (#253)

>> I now prefer async read to pull + sync read, because of the following reasons.

> But it sounds like @tyoshino and you discussed this and it's back to pull + sync read?

I agreed that even when we don't keep 1:1 pull-read correspondence we can define a reasonable locking rule. Hence the second reason listed there is not important to me any more.

To clarify the situation, I would like to list the current options. @tyoshino, @domenic, Please correct me if my understanding is wrong.

**(A) async read**
  `read()` function returns a promise. For ReadableByteStream, `read()` takes an optional ArrayBufferView. When the operation is done, the returned promise is fulfilled. There is no pulling mode.

**(B) 1:1 async pull + sync read**
  `pull()` (or `wailt()`) function returns a promise and it will be fulfilled when the pulling operation is done. `read()` function is synchronous and can be called only when the stream is readable.
  This is almost same as async read.

**(C) non-1:1 async pull + sync read**
  `pull()` (or `wait()`) function returns a promise and int will be fulfilled when the stream gets readable. For ReadableStream, it is essentially same as the current draft (only renaming `.ready` to `pull()`).

ReadableByteStream takes a mode (auto mode / manual mode) in construction. A ReadableByteStream with auto mode behaves just as a ReadableStream whose chunk is ArrayBufferView.
When ReadableByteStream runs in manual-mode, `pull()` takes an optional ArrayBufferView into which the data is written (when not specified, an automatically allocated ArrayBufferView is used).
The meaning of `pull()` depends on the mode (*pull as many chunks as the queue allows* in auto mode and *pull one chunk* in manual mode), but many "non-tricky" code for ReadableStream works with manual-mode ReadableByteStream, for example:
```
var results = [];
function consume(rs) {
  if (rs.state === 'closed' || rs.state === 'errored') {
    return rs.closed;
  }
  while (rs.state === 'readable') {
    results.push(rs.read());
  }
  rs.ready.then(() => consume(rs));
  return rs.closed;
}
```

**(D) ready + sync read (auto mode) and pull + ready + sync read (manual mode)**
No API change from the current draft for ReadableStream.
ReadableByteStream takes a mode in construction. When running in auto-mode, its API is same as ReadableStream's. When running in manual mode, it has `.ready`, synchronous `read()` and `pull()`. `pull()` is an operation to request one chunk to the source and doesn't have a return value. Instead, a user can use `.ready` to wait for the state transition.
Manual-mode ReadableByteStream is not subtype of ReadableStream any more.

Manual mode ReadableByteStream in (C) and (D) doesn't allow push sources, but it can be resolved with @tyoshino's ThinStream, because the proposal moves the queue from the ReadableStream to UnderlyingSource.

@tyoshino, I think your proposal at https://github.com/whatwg/streams/issues/253#issuecomment-76958542 is (D), is that correct?
@domenic, is your "async pull + sync read" (B) or (C)?

I still think (A) is better than (B). Both (A) and (C) are acceptable to me. For (D), I want pipeTo on UnderlyingSource as @tyoshino mentioned at https://github.com/whatwg/streams/issues/253#issuecomment-76958542 (I generally like it, but want it more eagerly with this option).


---
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/streams/issues/253#issuecomment-77140680

Received on Wednesday, 4 March 2015 11:17:03 UTC