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_WritableStream_h
8 #define mozilla_dom_WritableStream_h
10 #include "js/TypeDecls.h"
12 #include "mozilla/Attributes.h"
13 #include "mozilla/ErrorResult.h"
14 #include "mozilla/dom/BindingDeclarations.h"
15 #include "mozilla/dom/QueuingStrategyBinding.h"
16 #include "mozilla/dom/WritableStreamDefaultController.h"
17 #include "mozilla/dom/WritableStreamDefaultWriter.h"
19 #include "nsCycleCollectionParticipant.h"
20 #include "nsWrapperCache.h"
22 namespace mozilla::dom
{
25 class WritableStreamDefaultController
;
26 class WritableStreamDefaultWriter
;
27 class UnderlyingSinkAlgorithmsBase
;
28 class UniqueMessagePortId
;
31 class WritableStream
: public nsISupports
, public nsWrapperCache
{
33 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
34 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WritableStream
)
36 friend class ReadableStream
;
39 virtual ~WritableStream();
41 virtual void LastRelease() {}
43 // If one extends WritableStream with another cycle collectable class,
44 // calling HoldJSObjects and DropJSObjects should happen using 'this' of
45 // that extending class. And in that case Explicit should be passed to the
46 // constructor of WriteableStream so that it doesn't make those calls.
47 // See also https://bugzilla.mozilla.org/show_bug.cgi?id=1801214.
48 enum class HoldDropJSObjectsCaller
{ Implicit
, Explicit
};
50 explicit WritableStream(const GlobalObject
& aGlobal
,
51 HoldDropJSObjectsCaller aHoldDropCaller
);
52 explicit WritableStream(nsIGlobalObject
* aGlobal
,
53 HoldDropJSObjectsCaller aHoldDropCaller
);
56 // Slot Getter/Setters:
57 bool Backpressure() const { return mBackpressure
; }
58 void SetBackpressure(bool aBackpressure
) { mBackpressure
= aBackpressure
; }
60 Promise
* GetCloseRequest() { return mCloseRequest
; }
61 void SetCloseRequest(Promise
* aRequest
) { mCloseRequest
= aRequest
; }
63 MOZ_KNOWN_LIVE WritableStreamDefaultController
* Controller() {
66 void SetController(WritableStreamDefaultController
& aController
) {
67 MOZ_ASSERT(!mController
);
68 mController
= &aController
;
71 Promise
* GetInFlightWriteRequest() const { return mInFlightWriteRequest
; }
73 Promise
* GetPendingAbortRequestPromise() const {
74 return mPendingAbortRequestPromise
;
77 void SetPendingAbortRequest(Promise
* aPromise
, JS::Handle
<JS::Value
> aReason
,
78 bool aWasAlreadyErroring
) {
79 mPendingAbortRequestPromise
= aPromise
;
80 mPendingAbortRequestReason
= aReason
;
81 mPendingAbortRequestWasAlreadyErroring
= aWasAlreadyErroring
;
84 WritableStreamDefaultWriter
* GetWriter() const { return mWriter
; }
85 void SetWriter(WritableStreamDefaultWriter
* aWriter
) { mWriter
= aWriter
; }
87 enum class WriterState
{ Writable
, Closed
, Erroring
, Errored
};
89 WriterState
State() const { return mState
; }
90 void SetState(const WriterState
& aState
) { mState
= aState
; }
92 JS::Value
StoredError() const { return mStoredError
; }
93 void SetStoredError(JS::Handle
<JS::Value
> aStoredError
) {
94 mStoredError
= aStoredError
;
97 void AppendWriteRequest(RefPtr
<Promise
>& aRequest
) {
98 mWriteRequests
.AppendElement(aRequest
);
101 // CreateWritableStream
102 MOZ_CAN_RUN_SCRIPT
static already_AddRefed
<WritableStream
> CreateAbstract(
103 JSContext
* aCx
, nsIGlobalObject
* aGlobal
,
104 UnderlyingSinkAlgorithmsBase
* aAlgorithms
, double aHighWaterMark
,
105 QueuingStrategySize
* aSizeAlgorithm
, ErrorResult
& aRv
);
107 // WritableStreamCloseQueuedOrInFlight
108 bool CloseQueuedOrInFlight() const {
109 return mCloseRequest
|| mInFlightCloseRequest
;
112 // WritableStreamDealWithRejection
113 MOZ_CAN_RUN_SCRIPT
void DealWithRejection(JSContext
* aCx
,
114 JS::Handle
<JS::Value
> aError
,
117 // WritableStreamFinishErroring
118 MOZ_CAN_RUN_SCRIPT
void FinishErroring(JSContext
* aCx
, ErrorResult
& aRv
);
120 // WritableStreamFinishInFlightClose
121 void FinishInFlightClose();
123 // WritableStreamFinishInFlightCloseWithError
124 MOZ_CAN_RUN_SCRIPT
void FinishInFlightCloseWithError(
125 JSContext
* aCx
, JS::Handle
<JS::Value
> aError
, ErrorResult
& aRv
);
127 // WritableStreamFinishInFlightWrite
128 void FinishInFlightWrite();
130 // WritableStreamFinishInFlightWriteWithError
131 MOZ_CAN_RUN_SCRIPT
void FinishInFlightWriteWithError(
132 JSContext
* aCX
, JS::Handle
<JS::Value
> aError
, ErrorResult
& aR
);
134 // WritableStreamHasOperationMarkedInFlight
135 bool HasOperationMarkedInFlight() const {
136 return mInFlightWriteRequest
|| mInFlightCloseRequest
;
139 // WritableStreamMarkCloseRequestInFlight
140 void MarkCloseRequestInFlight();
142 // WritableStreamMarkFirstWriteRequestInFlight
143 void MarkFirstWriteRequestInFlight();
145 // WritableStreamRejectCloseAndClosedPromiseIfNeeded
146 void RejectCloseAndClosedPromiseIfNeeded();
148 // WritableStreamStartErroring
149 MOZ_CAN_RUN_SCRIPT
void StartErroring(JSContext
* aCx
,
150 JS::Handle
<JS::Value
> aReason
,
153 // WritableStreamUpdateBackpressure
154 void UpdateBackpressure(bool aBackpressure
);
157 // https://html.spec.whatwg.org/multipage/structured-data.html#transfer-steps
158 MOZ_CAN_RUN_SCRIPT
bool Transfer(JSContext
* aCx
,
159 UniqueMessagePortId
& aPortId
);
160 // https://html.spec.whatwg.org/multipage/structured-data.html#transfer-receiving-steps
161 MOZ_CAN_RUN_SCRIPT
static already_AddRefed
<WritableStream
>
162 ReceiveTransferImpl(JSContext
* aCx
, nsIGlobalObject
* aGlobal
,
164 MOZ_CAN_RUN_SCRIPT
static bool ReceiveTransfer(
165 JSContext
* aCx
, nsIGlobalObject
* aGlobal
, MessagePort
& aPort
,
166 JS::MutableHandle
<JSObject
*> aReturnObject
);
168 // Public functions to implement other specs
169 // https://streams.spec.whatwg.org/#other-specs-ws
171 // https://streams.spec.whatwg.org/#writablestream-set-up
173 // Sets up the WritableStream. Intended for subclasses.
174 void SetUpNative(JSContext
* aCx
, UnderlyingSinkAlgorithmsWrapper
& aAlgorithms
,
175 Maybe
<double> aHighWaterMark
,
176 QueuingStrategySize
* aSizeAlgorithm
, ErrorResult
& aRv
);
179 // Creates and sets up a WritableStream. Use SetUpNative for this purpose in
181 static already_AddRefed
<WritableStream
> CreateNative(
182 JSContext
* aCx
, nsIGlobalObject
& aGlobal
,
183 UnderlyingSinkAlgorithmsWrapper
& aAlgorithms
,
184 Maybe
<double> aHighWaterMark
, QueuingStrategySize
* aSizeAlgorithm
,
187 // The following definitions must only be used on WritableStream instances
188 // initialized via the above set up algorithm:
190 // https://streams.spec.whatwg.org/#writablestream-error
191 MOZ_CAN_RUN_SCRIPT
void ErrorNative(JSContext
* aCx
,
192 JS::Handle
<JS::Value
> aError
,
195 // IDL layer functions
197 nsIGlobalObject
* GetParentObject() const { return mGlobal
; }
199 JSObject
* WrapObject(JSContext
* aCx
,
200 JS::Handle
<JSObject
*> aGivenProto
) override
;
204 // TODO: Use MOZ_CAN_RUN_SCRIPT when IDL constructors can use it (bug 1749042)
205 MOZ_CAN_RUN_SCRIPT_BOUNDARY
static already_AddRefed
<WritableStream
>
206 Constructor(const GlobalObject
& aGlobal
,
207 const Optional
<JS::Handle
<JSObject
*>>& aUnderlyingSink
,
208 const QueuingStrategy
& aStrategy
, ErrorResult
& aRv
);
210 bool Locked() const { return !!mWriter
; }
212 MOZ_CAN_RUN_SCRIPT already_AddRefed
<Promise
> Abort(
213 JSContext
* cx
, JS::Handle
<JS::Value
> aReason
, ErrorResult
& aRv
);
215 MOZ_CAN_RUN_SCRIPT already_AddRefed
<Promise
> Close(JSContext
* aCx
,
218 already_AddRefed
<WritableStreamDefaultWriter
> GetWriter(ErrorResult
& aRv
);
221 nsCOMPtr
<nsIGlobalObject
> mGlobal
;
225 bool mBackpressure
= false;
226 RefPtr
<Promise
> mCloseRequest
;
227 RefPtr
<WritableStreamDefaultController
> mController
;
228 RefPtr
<Promise
> mInFlightWriteRequest
;
229 RefPtr
<Promise
> mInFlightCloseRequest
;
231 // We inline all members of [[pendingAbortRequest]] in this class.
232 // The absence (i.e. undefined) of the [[pendingAbortRequest]]
233 // is indicated by mPendingAbortRequestPromise = nullptr.
234 RefPtr
<Promise
> mPendingAbortRequestPromise
;
235 JS::Heap
<JS::Value
> mPendingAbortRequestReason
;
236 bool mPendingAbortRequestWasAlreadyErroring
= false;
238 WriterState mState
= WriterState::Writable
;
239 JS::Heap
<JS::Value
> mStoredError
;
240 RefPtr
<WritableStreamDefaultWriter
> mWriter
;
241 nsTArray
<RefPtr
<Promise
>> mWriteRequests
;
243 HoldDropJSObjectsCaller mHoldDropCaller
;
246 namespace streams_abstract
{
248 inline bool IsWritableStreamLocked(WritableStream
* aStream
) {
249 return aStream
->Locked();
252 MOZ_CAN_RUN_SCRIPT already_AddRefed
<Promise
> WritableStreamAbort(
253 JSContext
* aCx
, WritableStream
* aStream
, JS::Handle
<JS::Value
> aReason
,
256 MOZ_CAN_RUN_SCRIPT already_AddRefed
<Promise
> WritableStreamClose(
257 JSContext
* aCx
, WritableStream
* aStream
, ErrorResult
& aRv
);
259 already_AddRefed
<Promise
> WritableStreamAddWriteRequest(
260 WritableStream
* aStream
);
262 already_AddRefed
<WritableStreamDefaultWriter
>
263 AcquireWritableStreamDefaultWriter(WritableStream
* aStream
, ErrorResult
& aRv
);
265 } // namespace streams_abstract
267 } // namespace mozilla::dom
269 #endif // mozilla_dom_WritableStream_h