Re: [whatwg/streams] Adding generic seek or read/write-at-offset abilities to readable/writable streams (#1128)

**Here is the start of a proposal for a seek-based API:**

- Underlying sources/sinks can supply a promise-returning `seek` method. If supplied, then the stream's readers/writers support seeking; otherwise they don't.

- We add `seek()` methods and `canSeek` getters to `ReadableStreamDefaultReader` / `ReadableStreamBYOBReader` / `WritableStreamDefaultWriter`. The `seek()` method forwards to the underlying source/sink after doing some basic argument validation (nonnegative, finite).

- Seeks are queued up (i.e. not yet forwarded to the underlying source/sink) if there are any outstanding read requests or write requests. So e.g. even without `await`s, `writer.write(c1); writer.seek(10); writer.write(c2)` writes `c2` at position 10.

- If you seek while a readable stream's queue is non-empty, the queue gets emptied; all the buffered-up chunks are lost since they're no longer relevant.

In this model, the underlying source/sink is responsible for knowing what seek means, and how it interacts with reads/writes. The expectation is that they implement things so that reads/writes advance the current position, e.g. `writer.seek(10); writer.write(size5Chunk); writer.write(chunk)` writes `chunk` at position 15. But this is not enforced by the streams mechanisms.

**Here is the start of a proposal for an offset-based API:**

- Underlying sources/sinks can set `supportsRandomAccess: true`.

- For such streams, `defaultReader.read({ at })`, `byobReader.read(view, { at })`, and `defaultWriter.write(chunk, { at })` work. (For streams without that boolean set, supplying any value for `at` rejects the promise.) They perform basic validation on `at`.

- We add `reader.supportsAt` and `writer.supportsAt` booleans.

- For writable streams, the underlying sink's `write()` method gets forwarded the `at` value from the `writer.write()` call, which it can use as it sees fit. The existing queuing mechanisms for writes ensure that the stream is never asked to write to two different locations concurrently.

  - If no `at` is supplied, we can either omit it from the call to the underlying sink, or we can auto-compute it based on the size of the chunks. Not sure which is best.

- For readable streams, the situation is similar, except with the underlying source's `pull()` instead of the underlying sink's `write()`. The automatic calls to `pull()` which occur based on `highWaterMark` would take place at an auto-computed or omitted `at`, and would not be able to fulfill read requests with mismatching `at`s. The simplest thing to do here might be to empty the queue if a read request comes in with an `at` mismatching what was expected; otherwise the "queue" starts becoming a non-queue.

On balance the offset-based API seems a bit cleaner.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/streams/issues/1128#issuecomment-849000992

Received on Wednesday, 26 May 2021 18:04:17 UTC