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 #ifndef mozilla_dom_ReadableByteStreamController_h
8 #define mozilla_dom_ReadableByteStreamController_h
11 #include "UnderlyingSourceCallbackHelpers.h"
12 #include "js/RootingAPI.h"
13 #include "js/TypeDecls.h"
14 #include "mozilla/Attributes.h"
15 #include "mozilla/ErrorResult.h"
16 #include "mozilla/dom/BindingDeclarations.h"
17 #include "mozilla/dom/QueuingStrategyBinding.h"
18 #include "mozilla/dom/QueueWithSizes.h"
19 #include "mozilla/dom/ReadableStream.h"
20 #include "mozilla/dom/ReadRequest.h"
21 #include "mozilla/dom/ReadableStreamBYOBRequest.h"
22 #include "mozilla/dom/ReadableStreamController.h"
23 #include "mozilla/dom/TypedArray.h"
24 #include "nsCycleCollectionParticipant.h"
25 #include "nsWrapperCache.h"
26 #include "mozilla/dom/Nullable.h"
28 #include "nsISupportsImpl.h"
30 namespace mozilla::dom
{
32 // https://streams.spec.whatwg.org/#pull-into-descriptor-reader-type
33 // Indicates what type of readable stream reader initiated this request,
34 // or None if the initiating reader was released.
35 enum ReaderType
{ Default
, BYOB
, None
};
37 struct PullIntoDescriptor
;
38 struct ReadableByteStreamQueueEntry
;
39 struct ReadIntoRequest
;
41 class ReadableByteStreamController final
: public ReadableStreamController
,
42 public nsWrapperCache
{
44 NS_DECL_ISUPPORTS_INHERITED
45 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
46 ReadableByteStreamController
, ReadableStreamController
)
49 explicit ReadableByteStreamController(nsIGlobalObject
* aGlobal
);
52 ~ReadableByteStreamController() override
;
55 bool IsDefault() override
{ return false; }
56 bool IsByte() override
{ return true; }
57 ReadableStreamDefaultController
* AsDefault() override
{ return nullptr; }
58 ReadableByteStreamController
* AsByte() override
{ return this; }
60 JSObject
* WrapObject(JSContext
* aCx
,
61 JS::Handle
<JSObject
*> aGivenProto
) override
;
63 already_AddRefed
<ReadableStreamBYOBRequest
> GetByobRequest(JSContext
* aCx
,
66 Nullable
<double> GetDesiredSize() const;
68 MOZ_CAN_RUN_SCRIPT
void Close(JSContext
* aCx
, ErrorResult
& aRv
);
70 MOZ_CAN_RUN_SCRIPT
void Enqueue(JSContext
* aCx
, const ArrayBufferView
& aChunk
,
73 void Error(JSContext
* aCx
, JS::Handle
<JS::Value
> aErrorValue
,
76 MOZ_CAN_RUN_SCRIPT already_AddRefed
<Promise
> CancelSteps(
77 JSContext
* aCx
, JS::Handle
<JS::Value
> aReason
, ErrorResult
& aRv
) override
;
78 MOZ_CAN_RUN_SCRIPT
void PullSteps(JSContext
* aCx
, ReadRequest
* aReadRequest
,
79 ErrorResult
& aRv
) override
;
80 void ReleaseSteps() override
;
82 // Internal Slot Accessors
83 Maybe
<uint64_t> AutoAllocateChunkSize() { return mAutoAllocateChunkSize
; }
84 void SetAutoAllocateChunkSize(Maybe
<uint64_t>& aSize
) {
85 mAutoAllocateChunkSize
= aSize
;
88 ReadableStreamBYOBRequest
* GetByobRequest() const { return mByobRequest
; }
89 void SetByobRequest(ReadableStreamBYOBRequest
* aByobRequest
) {
90 mByobRequest
= aByobRequest
;
93 LinkedList
<RefPtr
<PullIntoDescriptor
>>& PendingPullIntos() {
94 return mPendingPullIntos
;
96 void ClearPendingPullIntos();
98 ReadableStream
* Stream() const { return mStream
; }
99 void SetStream(ReadableStream
* aStream
) { mStream
= aStream
; }
101 double QueueTotalSize() const { return mQueueTotalSize
; }
102 void SetQueueTotalSize(double aQueueTotalSize
) {
103 mQueueTotalSize
= aQueueTotalSize
;
105 void AddToQueueTotalSize(double aLength
) { mQueueTotalSize
+= aLength
; }
107 double StrategyHWM() const { return mStrategyHWM
; }
108 void SetStrategyHWM(double aStrategyHWM
) { mStrategyHWM
= aStrategyHWM
; }
110 bool CloseRequested() const { return mCloseRequested
; }
111 void SetCloseRequested(bool aCloseRequested
) {
112 mCloseRequested
= aCloseRequested
;
115 UnderlyingSourceAlgorithmsBase
* GetAlgorithms() { return mAlgorithms
; }
116 void SetAlgorithms(UnderlyingSourceAlgorithmsBase
* aAlgorithms
) {
117 mAlgorithms
= aAlgorithms
;
120 LinkedList
<RefPtr
<ReadableByteStreamQueueEntry
>>& Queue() { return mQueue
; }
123 bool Started() const { return mStarted
; }
124 void SetStarted(bool aStarted
) { mStarted
= aStarted
; }
126 bool Pulling() const { return mPulling
; }
127 void SetPulling(bool aPulling
) { mPulling
= aPulling
; }
129 bool PullAgain() const { return mPullAgain
; }
130 void SetPullAgain(bool aPullAgain
) { mPullAgain
= aPullAgain
; }
133 // A boolean flag indicating whether the stream has been closed by its
134 // underlying byte source, but still has chunks in its internal queue that
135 // have not yet been read
136 bool mCloseRequested
= false;
138 // A boolean flag set to true if the stream’s mechanisms requested a call
139 // to the underlying byte source's pull algorithm to pull more data, but the
140 // pull could not yet be done since a previous call is still executing
141 bool mPullAgain
= false;
143 // A boolean flag indicating whether the underlying byte source has finished
145 bool mStarted
= false;
147 // A boolean flag set to true while the underlying byte source's pull
148 // algorithm is executing and the returned promise has not yet fulfilled,
149 // used to prevent reentrant calls
150 bool mPulling
= false;
152 // A positive integer, when the automatic buffer allocation feature is
153 // enabled. In that case, this value specifies the size of buffer to allocate.
154 // It is undefined otherwise.
155 Maybe
<uint64_t> mAutoAllocateChunkSize
;
157 // A ReadableStreamBYOBRequest instance representing the current BYOB pull
158 // request, or null if there are no pending requests
159 RefPtr
<ReadableStreamBYOBRequest
> mByobRequest
;
161 // The algorithms for the underlying byte source
162 RefPtr
<UnderlyingSourceAlgorithmsBase
> mAlgorithms
;
164 // A list of pull-into descriptors
165 LinkedList
<RefPtr
<PullIntoDescriptor
>> mPendingPullIntos
;
167 // A list of readable byte stream queue entries representing the stream’s
168 // internal queue of chunks
170 // This is theoretically supposed to be a QueueWithSizes, but it is
171 // mostly not actually manipulated or used like QueueWithSizes, so instead we
173 LinkedList
<RefPtr
<ReadableByteStreamQueueEntry
>> mQueue
;
175 // The total size, in bytes, of all the chunks stored in [[queue]] (see § 8.1
177 double mQueueTotalSize
= 0.0;
179 // A number supplied to the constructor as part of the stream’s queuing
180 // strategy, indicating the point at which the stream will apply backpressure
181 // to its underlying byte source
182 double mStrategyHWM
= 0.0;
184 RefPtr
<ReadableStream
> mStream
;
187 // https://streams.spec.whatwg.org/#readable-byte-stream-queue-entry
188 // Important: These list elements need to be traced by the owning structure.
189 struct ReadableByteStreamQueueEntry
190 : LinkedListElement
<RefPtr
<ReadableByteStreamQueueEntry
>> {
191 NS_INLINE_DECL_REFCOUNTING(mozilla::dom::ReadableByteStreamQueueEntry
)
193 friend class ReadableByteStreamController::cycleCollection
;
195 ReadableByteStreamQueueEntry(JS::Handle
<JSObject
*> aBuffer
,
196 size_t aByteOffset
, size_t aByteLength
)
197 : LinkedListElement
<RefPtr
<ReadableByteStreamQueueEntry
>>(),
199 mByteOffset(aByteOffset
),
200 mByteLength(aByteLength
) {}
202 JSObject
* Buffer() const { return mBuffer
; }
203 void SetBuffer(JS::Handle
<JSObject
*> aBuffer
) { mBuffer
= aBuffer
; }
205 size_t ByteOffset() const { return mByteOffset
; }
206 void SetByteOffset(size_t aByteOffset
) { mByteOffset
= aByteOffset
; }
208 size_t ByteLength() const { return mByteLength
; }
209 void SetByteLength(size_t aByteLength
) { mByteLength
= aByteLength
; }
211 void ClearBuffer() { mBuffer
= nullptr; }
214 // An ArrayBuffer, which will be a transferred version of the one originally
215 // supplied by the underlying byte source.
217 // This is traced by the list owner (see ReadableByteStreamController's
219 JS::Heap
<JSObject
*> mBuffer
;
221 // A nonnegative integer number giving the byte offset derived from the view
222 // originally supplied by the underlying byte source
223 size_t mByteOffset
= 0;
225 // A nonnegative integer number giving the byte length derived from the view
226 // originally supplied by the underlying byte source
227 size_t mByteLength
= 0;
229 ~ReadableByteStreamQueueEntry() = default;
232 // Important: These list elments need to be traced by the owning structure.
233 struct PullIntoDescriptor final
234 : LinkedListElement
<RefPtr
<PullIntoDescriptor
>> {
235 NS_INLINE_DECL_REFCOUNTING(mozilla::dom::PullIntoDescriptor
)
239 #define DEFINE_TYPED_CONSTRUCTOR_ENUM_NAMES(ExternalT, NativeT, Name) Name,
240 JS_FOR_EACH_TYPED_ARRAY(DEFINE_TYPED_CONSTRUCTOR_ENUM_NAMES
)
241 #undef DEFINE_TYPED_CONSTRUCTOR_ENUM_NAMES
244 static Constructor
constructorFromScalar(JS::Scalar::Type type
) {
246 #define REMAP_PULL_INTO_DESCRIPTOR_TYPE(ExternalT, NativeT, Name) \
247 case JS::Scalar::Name: \
248 return Constructor::Name;
249 JS_FOR_EACH_TYPED_ARRAY(REMAP_PULL_INTO_DESCRIPTOR_TYPE
)
252 case JS::Scalar::Int64
:
253 case JS::Scalar::Simd128
:
254 case JS::Scalar::MaxTypedArrayViewType
:
257 MOZ_CRASH("Unexpected Scalar::Type");
260 friend class ReadableByteStreamController::cycleCollection
;
262 PullIntoDescriptor(JS::Handle
<JSObject
*> aBuffer
, uint64_t aBufferByteLength
,
263 uint64_t aByteOffset
, uint64_t aByteLength
,
264 uint64_t aBytesFilled
, uint64_t aElementSize
,
265 Constructor aViewConstructor
, ReaderType aReaderType
)
266 : LinkedListElement
<RefPtr
<PullIntoDescriptor
>>(),
268 mBufferByteLength(aBufferByteLength
),
269 mByteOffset(aByteOffset
),
270 mByteLength(aByteLength
),
271 mBytesFilled(aBytesFilled
),
272 mElementSize(aElementSize
),
273 mViewConstructor(aViewConstructor
),
274 mReaderType(aReaderType
) {}
276 JSObject
* Buffer() const { return mBuffer
; }
277 void SetBuffer(JS::Handle
<JSObject
*> aBuffer
) { mBuffer
= aBuffer
; }
279 uint64_t BufferByteLength() const { return mBufferByteLength
; }
280 void SetBufferByteLength(const uint64_t aBufferByteLength
) {
281 mBufferByteLength
= aBufferByteLength
;
284 uint64_t ByteOffset() const { return mByteOffset
; }
285 void SetByteOffset(const uint64_t aByteOffset
) { mByteOffset
= aByteOffset
; }
287 uint64_t ByteLength() const { return mByteLength
; }
288 void SetByteLength(const uint64_t aByteLength
) { mByteLength
= aByteLength
; }
290 uint64_t BytesFilled() const { return mBytesFilled
; }
291 void SetBytesFilled(const uint64_t aBytesFilled
) {
292 mBytesFilled
= aBytesFilled
;
295 uint64_t ElementSize() const { return mElementSize
; }
296 void SetElementSize(const uint64_t aElementSize
) {
297 mElementSize
= aElementSize
;
300 Constructor
ViewConstructor() const { return mViewConstructor
; }
302 // Note: Named GetReaderType to avoid name conflict with type.
303 ReaderType
GetReaderType() const { return mReaderType
; }
304 void SetReaderType(const ReaderType aReaderType
) {
305 mReaderType
= aReaderType
;
308 void ClearBuffer() { mBuffer
= nullptr; }
311 // This is traced by the list owner (see ReadableByteStreamController's
313 JS::Heap
<JSObject
*> mBuffer
;
314 uint64_t mBufferByteLength
= 0;
315 uint64_t mByteOffset
= 0;
316 uint64_t mByteLength
= 0;
317 uint64_t mBytesFilled
= 0;
318 uint64_t mElementSize
= 0;
319 Constructor mViewConstructor
;
320 ReaderType mReaderType
;
322 ~PullIntoDescriptor() = default;
325 MOZ_CAN_RUN_SCRIPT
void ReadableByteStreamControllerRespond(
326 JSContext
* aCx
, ReadableByteStreamController
* aController
,
327 uint64_t aBytesWritten
, ErrorResult
& aRv
);
329 MOZ_CAN_RUN_SCRIPT
void ReadableByteStreamControllerRespondInternal(
330 JSContext
* aCx
, ReadableByteStreamController
* aController
,
331 uint64_t aBytesWritten
, ErrorResult
& aRv
);
333 MOZ_CAN_RUN_SCRIPT
void ReadableByteStreamControllerRespondWithNewView(
334 JSContext
* aCx
, ReadableByteStreamController
* aController
,
335 JS::Handle
<JSObject
*> aView
, ErrorResult
& aRv
);
337 MOZ_CAN_RUN_SCRIPT
void ReadableByteStreamControllerPullInto(
338 JSContext
* aCx
, ReadableByteStreamController
* aController
,
339 JS::Handle
<JSObject
*> aView
, ReadIntoRequest
* aReadIntoRequest
,
342 void ReadableByteStreamControllerError(
343 ReadableByteStreamController
* aController
, JS::Handle
<JS::Value
> aValue
,
346 MOZ_CAN_RUN_SCRIPT
void ReadableByteStreamControllerEnqueue(
347 JSContext
* aCx
, ReadableByteStreamController
* aController
,
348 JS::Handle
<JSObject
*> aChunk
, ErrorResult
& aRv
);
350 already_AddRefed
<ReadableStreamBYOBRequest
>
351 ReadableByteStreamControllerGetBYOBRequest(
352 JSContext
* aCx
, ReadableByteStreamController
* aController
,
355 MOZ_CAN_RUN_SCRIPT
void ReadableByteStreamControllerClose(
356 JSContext
* aCx
, ReadableByteStreamController
* aController
,
359 MOZ_CAN_RUN_SCRIPT
void SetUpReadableByteStreamController(
360 JSContext
* aCx
, ReadableStream
* aStream
,
361 ReadableByteStreamController
* aController
,
362 UnderlyingSourceAlgorithmsBase
* aAlgorithms
, double aHighWaterMark
,
363 Maybe
<uint64_t> aAutoAllocateChunkSize
, ErrorResult
& aRv
);
365 MOZ_CAN_RUN_SCRIPT
void ReadableByteStreamControllerCallPullIfNeeded(
366 JSContext
* aCx
, ReadableByteStreamController
* aController
,
369 MOZ_CAN_RUN_SCRIPT
void SetUpReadableByteStreamControllerFromUnderlyingSource(
370 JSContext
* aCx
, ReadableStream
* aStream
,
371 JS::Handle
<JSObject
*> aUnderlyingSource
,
372 UnderlyingSource
& aUnderlyingSourceDict
, double aHighWaterMark
,
375 void ReadableByteStreamControllerClearAlgorithms(
376 ReadableByteStreamController
* aController
);
378 } // namespace mozilla::dom