1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* ReadableStream readers and generic reader operations. */
#ifndef builtin_streams_ReadableStreamReader_h
#define builtin_streams_ReadableStreamReader_h
#include "mozilla/Attributes.h" // MOZ_MUST_USE
#include "jstypes.h" // JS_PUBLIC_API
#include "js/Class.h" // JSClass, js::ClassSpec
#include "js/RootingAPI.h" // JS::Handle
#include "js/Value.h" // JS::{,Boolean,Object,Undefined}Value
#include "vm/JSObject.h" // JSObject::is
#include "vm/List.h" // js::ListObject
#include "vm/NativeObject.h" // js::NativeObject
struct JS_PUBLIC_API JSContext;
namespace js {
class PromiseObject;
class ReadableStream;
/**
* Tells whether or not read() result objects inherit from Object.prototype.
* Generally, they should do so only if the reader was created by author code.
* See <https://streams.spec.whatwg.org/#readable-stream-create-read-result>.
*/
enum class ForAuthorCodeBool { No, Yes };
class ReadableStreamReader : public NativeObject {
public:
/**
* Memory layout of Stream Reader instances.
*
* See https://streams.spec.whatwg.org/#default-reader-internal-slots and
* https://streams.spec.whatwg.org/#byob-reader-internal-slots for details.
*
* Note that [[readRequests]] and [[readIntoRequests]] are treated the same
* in our implementation.
*
* Of the stored values, Stream and ClosedPromise might be
* cross-compartment wrapper wrappers.
*
* For Stream, this can happen if the Reader was created by applying a
* different compartment's ReadableStream.prototype.getReader method.
*
* For ClosedPromise, it can be caused by applying a different
* compartment's ReadableStream*Reader.prototype.releaseLock method.
*
* Requests is guaranteed to be in the same compartment as the Reader, but
* can contain wrapped request objects from other globals.
*/
enum Slots {
Slot_Stream,
Slot_Requests,
Slot_ClosedPromise,
Slot_ForAuthorCode,
SlotCount,
};
bool hasStream() const { return !getFixedSlot(Slot_Stream).isUndefined(); }
void setStream(JSObject* stream) {
setFixedSlot(Slot_Stream, JS::ObjectValue(*stream));
}
void clearStream() { setFixedSlot(Slot_Stream, JS::UndefinedValue()); }
bool isClosed() { return !hasStream(); }
/**
* Tells whether this reader was created by author code.
*
* This returns Yes for readers created using `stream.getReader()`, and No
* for readers created for the internal use of algorithms like
* `stream.tee()` and `new Response(stream)`.
*
* The standard does not have this field. Instead, eight algorithms take a
* forAuthorCode parameter, and a [[forAuthorCode]] field is part of each
* read request. But the behavior is always equivalent to treating readers
* created by author code as having a bit set on them. We implement it that
* way for simplicity.
*/
ForAuthorCodeBool forAuthorCode() const {
return getFixedSlot(Slot_ForAuthorCode).toBoolean() ? ForAuthorCodeBool::Yes
: ForAuthorCodeBool::No;
}
void setForAuthorCode(ForAuthorCodeBool value) {
setFixedSlot(Slot_ForAuthorCode,
JS::BooleanValue(value == ForAuthorCodeBool::Yes));
}
ListObject* requests() const {
return &getFixedSlot(Slot_Requests).toObject().as<ListObject>();
}
void clearRequests() { setFixedSlot(Slot_Requests, JS::UndefinedValue()); }
JSObject* closedPromise() const {
return &getFixedSlot(Slot_ClosedPromise).toObject();
}
void setClosedPromise(JSObject* wrappedPromise) {
setFixedSlot(Slot_ClosedPromise, JS::ObjectValue(*wrappedPromise));
}
static const JSClass class_;
};
class ReadableStreamDefaultReader : public ReadableStreamReader {
public:
static bool constructor(JSContext* cx, unsigned argc, JS::Value* vp);
static const ClassSpec classSpec_;
static const JSClass class_;
static const ClassSpec protoClassSpec_;
static const JSClass protoClass_;
};
extern MOZ_MUST_USE ReadableStreamDefaultReader*
CreateReadableStreamDefaultReader(JSContext* cx,
JS::Handle<ReadableStream*> unwrappedStream,
ForAuthorCodeBool forAuthorCode,
JS::Handle<JSObject*> proto = nullptr);
extern MOZ_MUST_USE JSObject* ReadableStreamReaderGenericCancel(
JSContext* cx, JS::Handle<ReadableStreamReader*> unwrappedReader,
JS::Handle<JS::Value> reason);
extern MOZ_MUST_USE bool ReadableStreamReaderGenericInitialize(
JSContext* cx, JS::Handle<ReadableStreamReader*> reader,
JS::Handle<ReadableStream*> unwrappedStream,
ForAuthorCodeBool forAuthorCode);
extern MOZ_MUST_USE bool ReadableStreamReaderGenericRelease(
JSContext* cx, JS::Handle<ReadableStreamReader*> unwrappedReader);
extern MOZ_MUST_USE PromiseObject* ReadableStreamDefaultReaderRead(
JSContext* cx, JS::Handle<ReadableStreamDefaultReader*> unwrappedReader);
} // namespace js
template <>
inline bool JSObject::is<js::ReadableStreamReader>() const {
return is<js::ReadableStreamDefaultReader>();
}
namespace js {
extern MOZ_MUST_USE JSObject* CreateReadableStreamBYOBReader(
JSContext* cx, JS::Handle<ReadableStream*> unwrappedStream,
ForAuthorCodeBool forAuthorCode, JS::Handle<JSObject*> proto = nullptr);
} // namespace js
#endif // builtin_streams_ReadableStreamReader_h
|