Bug 1769952 - Fix running raptor on a Win10-64 VM r=sparky
[gecko.git] / dom / streams / ReadableStreamBYOBReader.cpp
blob055aff40ef32c8f82de7ee26217ac085d86d3118
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "js/ArrayBuffer.h"
8 #include "js/experimental/TypedData.h"
9 #include "mozilla/dom/ReadableStreamBYOBReader.h"
10 #include "mozilla/dom/ReadableStream.h"
11 #include "mozilla/dom/ReadableStreamBYOBReaderBinding.h"
12 #include "mozilla/dom/ReadableStreamGenericReader.h"
13 #include "mozilla/dom/ReadIntoRequest.h"
14 #include "mozilla/dom/RootedDictionary.h"
15 #include "nsCOMPtr.h"
16 #include "nsISupportsImpl.h"
18 // Temporary Includes
19 #include "mozilla/dom/ReadableByteStreamController.h"
20 #include "mozilla/dom/ReadableStreamBYOBRequest.h"
21 #include "mozilla/dom/ReadableStreamBYOBReader.h"
23 namespace mozilla::dom {
25 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_INHERITED(ReadableStreamBYOBReader,
26 ReadableStreamGenericReader,
27 mReadIntoRequests)
28 NS_IMPL_ADDREF_INHERITED(ReadableStreamBYOBReader, ReadableStreamGenericReader)
29 NS_IMPL_RELEASE_INHERITED(ReadableStreamBYOBReader, ReadableStreamGenericReader)
31 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadableStreamBYOBReader)
32 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
33 NS_INTERFACE_MAP_END_INHERITING(ReadableStreamGenericReader)
35 JSObject* ReadableStreamBYOBReader::WrapObject(
36 JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
37 return ReadableStreamBYOBReader_Binding::Wrap(aCx, this, aGivenProto);
40 // https://streams.spec.whatwg.org/#set-up-readable-stream-byob-reader
41 void SetUpReadableStreamBYOBReader(ReadableStreamBYOBReader* reader,
42 ReadableStream& stream, ErrorResult& rv) {
43 // Step 1. If !IsReadableStreamLocked(stream) is true, throw a TypeError
44 // exception.
45 if (IsReadableStreamLocked(&stream)) {
46 rv.ThrowTypeError("Trying to read locked stream");
47 return;
50 // Step 2. If stream.[[controller]] does not implement
51 // ReadableByteStreamController, throw a TypeError exception.
52 if (!stream.Controller()->IsByte()) {
53 rv.ThrowTypeError("Trying to read with incompatible controller");
54 return;
57 // Step 3. Perform ! ReadableStreamReaderGenericInitialize(reader, stream).
58 ReadableStreamReaderGenericInitialize(reader, &stream, rv);
59 if (rv.Failed()) {
60 return;
63 // Step 4. Set reader.[[readIntoRequests]] to a new empty list.
64 reader->ReadIntoRequests().clear();
67 // https://streams.spec.whatwg.org/#byob-reader-constructor
68 /* static */ already_AddRefed<ReadableStreamBYOBReader>
69 ReadableStreamBYOBReader::Constructor(const GlobalObject& global,
70 ReadableStream& stream, ErrorResult& rv) {
71 nsCOMPtr<nsIGlobalObject> globalObject =
72 do_QueryInterface(global.GetAsSupports());
73 RefPtr<ReadableStreamBYOBReader> reader =
74 new ReadableStreamBYOBReader(globalObject);
76 // Step 1.
77 SetUpReadableStreamBYOBReader(reader, stream, rv);
78 if (rv.Failed()) {
79 return nullptr;
82 return reader.forget();
85 struct Read_ReadIntoRequest final : public ReadIntoRequest {
86 NS_DECL_ISUPPORTS_INHERITED
87 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Read_ReadIntoRequest,
88 ReadIntoRequest)
90 RefPtr<Promise> mPromise;
92 explicit Read_ReadIntoRequest(Promise* aPromise) : mPromise(aPromise) {}
94 void ChunkSteps(JSContext* aCx, JS::Handle<JS::Value> aChunk,
95 ErrorResult& aRv) override {
96 MOZ_ASSERT(aChunk.isObject());
97 // https://streams.spec.whatwg.org/#byob-reader-read Step 6.
99 // chunk steps, given chunk:
100 // Resolve promise with «[ "value" → chunk, "done" → false ]».
102 // We need to wrap this as the chunk could have come from
103 // another compartment.
104 JS::Rooted<JSObject*> chunk(aCx, &aChunk.toObject());
105 if (!JS_WrapObject(aCx, &chunk)) {
106 aRv.StealExceptionFromJSContext(aCx);
107 return;
110 RootedDictionary<ReadableStreamReadResult> result(aCx);
111 result.mValue = aChunk;
112 result.mDone.Construct(false);
114 mPromise->MaybeResolve(result);
117 void CloseSteps(JSContext* aCx, JS::Handle<JS::Value> aChunk,
118 ErrorResult& aRv) override {
119 MOZ_ASSERT(aChunk.isObject() || aChunk.isUndefined());
120 // https://streams.spec.whatwg.org/#byob-reader-read Step 6.
122 // close steps, given chunk:
123 // Resolve promise with «[ "value" → chunk, "done" → true ]».
124 RootedDictionary<ReadableStreamReadResult> result(aCx);
125 if (aChunk.isObject()) {
126 // We need to wrap this as the chunk could have come from
127 // another compartment.
128 JS::Rooted<JSObject*> chunk(aCx, &aChunk.toObject());
129 if (!JS_WrapObject(aCx, &chunk)) {
130 aRv.StealExceptionFromJSContext(aCx);
131 return;
134 result.mValue = aChunk;
136 result.mDone.Construct(true);
138 mPromise->MaybeResolve(result);
141 void ErrorSteps(JSContext* aCx, JS::Handle<JS::Value> e,
142 ErrorResult& aRv) override {
143 // https://streams.spec.whatwg.org/#byob-reader-read Step 6.
145 // error steps, given e:
146 // Reject promise with e.
147 mPromise->MaybeReject(e);
150 protected:
151 ~Read_ReadIntoRequest() override = default;
154 NS_IMPL_CYCLE_COLLECTION(ReadIntoRequest)
155 NS_IMPL_CYCLE_COLLECTING_ADDREF(ReadIntoRequest)
156 NS_IMPL_CYCLE_COLLECTING_RELEASE(ReadIntoRequest)
157 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadIntoRequest)
158 NS_INTERFACE_MAP_ENTRY(nsISupports)
159 NS_INTERFACE_MAP_END
161 NS_IMPL_CYCLE_COLLECTION_INHERITED(Read_ReadIntoRequest, ReadIntoRequest,
162 mPromise)
163 NS_IMPL_ADDREF_INHERITED(Read_ReadIntoRequest, ReadIntoRequest)
164 NS_IMPL_RELEASE_INHERITED(Read_ReadIntoRequest, ReadIntoRequest)
166 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Read_ReadIntoRequest)
167 NS_INTERFACE_MAP_END_INHERITING(ReadIntoRequest)
169 // https://streams.spec.whatwg.org/#readable-stream-byob-reader-read
170 void ReadableStreamBYOBReaderRead(JSContext* aCx,
171 ReadableStreamBYOBReader* aReader,
172 JS::Handle<JSObject*> aView,
173 ReadIntoRequest* aReadIntoRequest,
174 ErrorResult& aRv) {
175 // Step 1.Let stream be reader.[[stream]].
176 ReadableStream* stream = aReader->GetStream();
178 // Step 2. Assert: stream is not undefined.
179 MOZ_ASSERT(stream);
181 // Step 3. Set stream.[[disturbed]] to true.
182 stream->SetDisturbed(true);
184 // Step 4. If stream.[[state]] is "errored", perform readIntoRequest’s error
185 // steps given stream.[[storedError]].
186 if (stream->State() == ReadableStream::ReaderState::Errored) {
187 JS::Rooted<JS::Value> error(aCx, stream->StoredError());
189 aReadIntoRequest->ErrorSteps(aCx, error, aRv);
190 return;
193 // Step 5. Otherwise, perform
194 // !ReadableByteStreamControllerPullInto(stream.[[controller]], view,
195 // readIntoRequest).
196 MOZ_ASSERT(stream->Controller()->IsByte());
197 RefPtr<ReadableByteStreamController> controller(
198 stream->Controller()->AsByte());
199 ReadableByteStreamControllerPullInto(aCx, controller, aView, aReadIntoRequest,
200 aRv);
203 // https://streams.spec.whatwg.org/#byob-reader-read
204 already_AddRefed<Promise> ReadableStreamBYOBReader::Read(
205 const ArrayBufferView& aArray, ErrorResult& aRv) {
206 AutoJSAPI jsapi;
207 if (!jsapi.Init(GetParentObject())) {
208 aRv.ThrowUnknownError("Internal error");
209 return nullptr;
211 JSContext* cx = jsapi.cx();
213 JS::Rooted<JSObject*> view(cx, aArray.Obj());
215 // Step 1. If view.[[ByteLength]] is 0, return a promise rejected with a
216 // TypeError exception.
217 if (JS_GetArrayBufferViewByteLength(view) == 0) {
218 // Binding code should convert this thrown value into a rejected promise.
219 aRv.ThrowTypeError("Zero Length View");
220 return nullptr;
223 // Step 2. If view.[[ViewedArrayBuffer]].[[ArrayBufferByteLength]] is 0,
224 // return a promise rejected with a TypeError exception.
225 bool isSharedMemory;
226 JS::Rooted<JSObject*> viewedArrayBuffer(
227 cx, JS_GetArrayBufferViewBuffer(cx, view, &isSharedMemory));
228 if (!viewedArrayBuffer) {
229 aRv.StealExceptionFromJSContext(cx);
230 return nullptr;
233 if (JS::GetArrayBufferByteLength(viewedArrayBuffer) == 0) {
234 aRv.ThrowTypeError("zero length viewed buffer");
235 return nullptr;
238 // Step 3. If ! IsDetachedBuffer(view.[[ViewedArrayBuffer]]) is true, return a
239 // promise rejected with a TypeError exception.
240 if (JS::IsDetachedArrayBufferObject(viewedArrayBuffer)) {
241 aRv.ThrowTypeError("Detatched Buffer");
242 return nullptr;
245 // Step 4. If this.[[stream]] is undefined, return a promise rejected with a
246 // TypeError exception.
247 if (!GetStream()) {
248 aRv.ThrowTypeError("Reader has undefined stream");
249 return nullptr;
252 // Step 5.
253 RefPtr<Promise> promise = Promise::Create(GetParentObject(), aRv);
254 if (aRv.Failed()) {
255 return nullptr;
258 // Step 6. Let readIntoRequest be a new read-into request with the following
259 // items:
260 RefPtr<ReadIntoRequest> readIntoRequest = new Read_ReadIntoRequest(promise);
262 // Step 7. Perform ! ReadableStreamBYOBReaderRead(this, view,
263 // readIntoRequest).
264 ReadableStreamBYOBReaderRead(cx, this, view, readIntoRequest, aRv);
265 if (aRv.Failed()) {
266 return nullptr;
269 // Step 8. Return promise.
270 return promise.forget();
273 // https://streams.spec.whatwg.org/#abstract-opdef-readablestreambyobreadererrorreadintorequests
274 void ReadableStreamBYOBReaderErrorReadIntoRequests(
275 JSContext* aCx, ReadableStreamBYOBReader* aReader,
276 JS::Handle<JS::Value> aError, ErrorResult& aRv) {
277 // Step 1. Let readIntoRequests be reader.[[readIntoRequests]].
278 LinkedList<RefPtr<ReadIntoRequest>> readIntoRequests =
279 std::move(aReader->ReadIntoRequests());
281 // Step 2. Set reader.[[readIntoRequests]] to a new empty list.
282 // Note: The std::move already cleared this anyway.
283 aReader->ReadIntoRequests().clear();
285 // Step 3. For each readIntoRequest of readIntoRequests,
286 while (RefPtr<ReadIntoRequest> readIntoRequest =
287 readIntoRequests.popFirst()) {
288 // Step 3.1. Perform readIntoRequest’s error steps, given e.
289 readIntoRequest->ErrorSteps(aCx, aError, aRv);
290 if (aRv.Failed()) {
291 return;
296 // https://streams.spec.whatwg.org/#abstract-opdef-readablestreambyobreaderrelease
297 void ReadableStreamBYOBReaderRelease(JSContext* aCx,
298 ReadableStreamBYOBReader* aReader,
299 ErrorResult& aRv) {
300 // Step 1. Perform ! ReadableStreamReaderGenericRelease(reader).
301 ReadableStreamReaderGenericRelease(aReader, aRv);
302 if (aRv.Failed()) {
303 return;
306 // Step 2. Let e be a new TypeError exception.
307 ErrorResult rv;
308 rv.ThrowTypeError("Releasing lock");
309 JS::Rooted<JS::Value> error(aCx);
310 MOZ_ALWAYS_TRUE(ToJSValue(aCx, std::move(rv), &error));
312 // Step 3. Perform ! ReadableStreamBYOBReaderErrorReadIntoRequests(reader, e).
313 ReadableStreamBYOBReaderErrorReadIntoRequests(aCx, aReader, error, aRv);
316 // https://streams.spec.whatwg.org/#byob-reader-release-lock
317 void ReadableStreamBYOBReader::ReleaseLock(ErrorResult& aRv) {
318 // Step 1. If this.[[stream]] is undefined, return.
319 if (!mStream) {
320 return;
323 AutoJSAPI jsapi;
324 if (!jsapi.Init(mGlobal)) {
325 return aRv.ThrowUnknownError("Internal error");
327 JSContext* cx = jsapi.cx();
329 // Step 2. Perform ! ReadableStreamBYOBReaderRelease(this).
330 RefPtr<ReadableStreamBYOBReader> thisRefPtr = this;
331 ReadableStreamBYOBReaderRelease(cx, thisRefPtr, aRv);
334 // https://streams.spec.whatwg.org/#acquire-readable-stream-byob-reader
335 already_AddRefed<ReadableStreamBYOBReader> AcquireReadableStreamBYOBReader(
336 ReadableStream* aStream, ErrorResult& aRv) {
337 // Step 1. Let reader be a new ReadableStreamBYOBReader.
338 RefPtr<ReadableStreamBYOBReader> reader =
339 new ReadableStreamBYOBReader(aStream->GetParentObject());
341 // Step 2. Perform ? SetUpReadableStreamBYOBReader(reader, stream).
342 SetUpReadableStreamBYOBReader(reader, *aStream, aRv);
343 if (aRv.Failed()) {
344 return nullptr;
347 // Step 3. Return reader.
348 return reader.forget();
351 } // namespace mozilla::dom