-
Notifications
You must be signed in to change notification settings - Fork 164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow other specifications to create readable byte streams #1130
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
index.bs
Outdated
1. Perform ! [$ReadableByteStreamControllerEnqueue$](|stream|.[=ReadableStream/[[controller]]=], | ||
|uint8Array|). | ||
1. Otherwise, | ||
1. Write |bytes| into |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need an assertion that it will fit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once we start using whatwg/webidl#987 there will be such an assertion transitively, but it can't hurt to add it here too.
Marking as "do not merge yet" pending #1121 and updating to use whatwg/webidl#987. |
Define pullAlgorithm and cancelAlgorithm, and set up ReceiveStream with them. This relies on whatwg/streams#1130. Fixes #185.
This is ready to merge but we're getting some good feedback in w3c/webtransport#297 (comment) so I'll hold off a bit... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yutakahirano, can you take a look at the latest commit? I should also update the Fetch and Web Serial PRs to make sure this works well for them too.
index.bs
Outdated
1. If |byobRequest| is non-null, and |view|.\[[ViewedArrayBuffer]].\[[ArrayBufferData]] is the same | ||
[=Data Block=] as |byobRequest|.\[[view]].\[[ViewedArrayBuffer]].\[[ArrayBufferData]], then: | ||
1. Assert: |view|.\[[ByteOffset]] is |byobRequest|.\[[view]].\[[ByteOffset]]. | ||
1. Assert: |view|.\[[ByteLength]] ≤ |byobRequest|.\[[view]].\[[ByteLength]]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made these asserts instead of if tests (compared to w3c/webtransport#297 (comment)) since it seems like it would be bad if the caller used the view but went past the requested bounds.
index.bs
Outdated
|view|.\[[ByteLength]]). | ||
1. Otherwise, perform ? | ||
[$ReadableByteStreamControllerRespondWithNewView$](|stream|.[=ReadableStream/[[controller]]=], | ||
|view|). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I handled the case where you transfer the backing Data Block here, which goes a bit beyond w3c/webtransport#297 (comment) but seems like a good idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, LGTM!
Almost done. Still TODO: update Fetch and Web Serial PRs for the new WebTransport-inspired model, to make sure this still works. |
Seems to work. There's a bit of boilerplate if you, like the Web Serial and Fetch specs, already have a byte sequence on hand. Then you need to branch as to whether there's a BYOB request (and, in the case of Fetch, whether the byte sequence fits). I considered adding a helper for this, which would put us back to "enqueue bytes given a byte sequence", but I think it's OK to be more explicit. In particular it's more obviously optimizable by reading the spec in question, instead of having to go to Streams. Still, to leave open the door for such a helper in the future, I'll rename the operation from "enqueue bytes" to "enqueue view". Any final reviews, of either this, WICG/serial#137, or whatwg/fetch#1246 would be appreciated. If there aren't any, I'll merge this tomorrow-ish. |
Co-authored-by: Mattias Buelens <[email protected]>
Co-authored-by: Mattias Buelens <[email protected]>
Co-authored-by: Mattias Buelens <[email protected]>
Okay, there's still an important problem. After a specification calls "close a readable stream" on a readable byte stream, the current BYOB request is still pending. We must somehow perform the equivalent of I suppose we have to extend "close a readable stream" to handle this? But then:
|
I think we can mandate that other specifications not transfer the current BYOB request view. Even if implementations do so (and then do the correspondingly-different ending dance), it wouldn't be observable, so we can write the specifications to assume they don't. Similarly I think we can require that other specifications not write into the current BYOB request view after closing the readable stream. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems reasonable. In that case, we need to do something similar as in the read request close steps of ReadableByteStreamTee
. (See suggestion below.)
Co-authored-by: Mattias Buelens <[email protected]>
Alright, this is ready to merge, but since previous waiting periods have turned up great finds, I'll give it another day before doing so. |
index.bs
Outdated
1. If |stream|.[=ReadableStream/[[controller]]=].[=ReadableByteStreamController/[[pendingPullIntos]]=] | ||
is not [=list/is empty|empty=], perform ! | ||
[$ReadableByteStreamControllerRespond$](|stream|.[=ReadableStream/[[controller]]=], 0). | ||
<p class="note">The caller has to make sure not to write into the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel some ambiguity here. How long before closing the stream is it okay to write into the view?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think this does not match my understanding of #1130 (comment) . Reviewing that, I think instead we want to say something like:
- The calling specification must never transfer the current BYOB request view. Note: implementations could do something equivalent to a transfer, but in that case they'd need to modify the steps in close to use RespondWithNewView instead of Respond(,0) to keep the same observable behavior as not transfering.
- The calling specification must not write into the current BYOB request view after closing the stream.
@MattiasBuelens, WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The calling specification must never transfer the current BYOB request view. Note: implementations could do something equivalent to a transfer, but in that case they'd need to modify the steps in close to use RespondWithNewView instead of Respond(,0) to keep the same observable behavior as not transfering.
That's correct.
Do we want to provide an algorithm for closing a readable byte stream after the calling specification has already transferred the current BYOB request view? Or maybe add an optional newByobBuffer
argument and switch on that to use either Respond(0)
or RespondWithNewView(emptyViewOnNewByobBuffer)
? (Kinda like the closeWithNewView()
method I suggested in #1123.)
The calling specification must not write into the current BYOB request view after closing the stream.
Makes sense. If they write into the BYOB request, they should enqueue it first, and then close the stream.
To <dfn export for="ReadableStream">error</dfn> a {{ReadableStream}} |stream| given a JavaScript | ||
value |e|: | ||
|
||
1. If |stream|.[=ReadableStream/[[controller]]=] [=implements=] {{ReadableByteStreamController}}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All this switching on controller type is unfortunate. If we had more types we might add some polymorphism to avoid it. But with only two types this is probably simpler.
index.bs
Outdated
1. Let |byobRequest| be ! | ||
[$ReadableByteStreamControllerGetBYOBRequest$](|stream|.[=ReadableStream/[[controller]]=]). | ||
1. If |byobRequest| is non-null, and |chunk|.\[[ViewedArrayBuffer]].\[[ArrayBufferData]] is the | ||
same [=Data Block=] as |byobRequest|.\[[view]].\[[ViewedArrayBuffer]].\[[ArrayBufferData]], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There may be a problem here. If the calling specification needs to transfer |byobRequest|.[[view]].[[ViewedArrayBuffer]]
for some reason, then it will be detached and not match.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, but [[ArrayBufferData]] will still match. That's the hidden internal slot that the ECMAScript spec uses to abstract the concept of "memory regions", so it will survive such transfers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But if it's transferred it will be detached, right? And if it's detached then [[ArrayBufferData]] is set to null: https://tc39.es/ecma262/#sec-detacharraybuffer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, dang, you're right. In that case we should probably solve it by, per the above discussion, prohibiting transferring at a spec level (but allowing it an implementation level as long as the implementation does appropriate behind-the-scenes contortions).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's fine. If someone finds they need to transfer the buffer we can revisit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
D'oh, how could I forget? I even explained this in #1123. 😛
We could make two separate algorithms: one for enqueuing a new chunk, and another for responding with a (transferred) BYOB request view. We still can't check if the given buffer is a transferred version of the BYOB request's buffer, so we'd have to rely on the calling specification to not mess this up.
Or yeah, we could just forbid transferring for now. 😁
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Closes #1121.
Users:
Preview | Diff