summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/streams/ReadableStream.h
blob: c11596d3560641a6654ba49064fa7b3e940f078e (plain)
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
/* -*- 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/. */

/* Class ReadableStream. */

#ifndef builtin_streams_ReadableStream_h
#define builtin_streams_ReadableStream_h

#include "mozilla/Assertions.h"  // MOZ_ASSERT{,_IF}
#include "mozilla/Attributes.h"  // MOZ_MUST_USE

#include <stdint.h>  // uint32_t

#include "jstypes.h"        // JS_PUBLIC_API
#include "js/Class.h"       // JSClass, js::ClassSpec
#include "js/RootingAPI.h"  // JS::Handle
#include "js/Stream.h"      // JS::ReadableStream{Mode,UnderlyingSource}
#include "js/Value.h"  // JS::Int32Value, JS::ObjectValue, JS::UndefinedValue
#include "vm/NativeObject.h"  // js::NativeObject

class JS_PUBLIC_API JSObject;

namespace js {

class ReadableStreamController;

class ReadableStream : public NativeObject {
 public:
  /**
   * Memory layout of Stream instances.
   *
   * See https://streams.spec.whatwg.org/#rs-internal-slots for details on
   * the stored state. [[state]] and [[disturbed]] are stored in
   * StreamSlot_State as ReadableStream::State enum values.
   *
   * Of the stored values, Reader and StoredError might be cross-compartment
   * wrappers. This can happen if the Reader was created by applying a
   * different compartment's ReadableStream.prototype.getReader method.
   *
   * A stream's associated controller is always created from under the
   * stream's constructor and thus cannot be in a different compartment.
   */
  enum Slots {
    Slot_Controller,
    Slot_Reader,
    Slot_State,
    Slot_StoredError,
    SlotCount
  };

 private:
  enum StateBits {
    Readable = 0,
    Closed = 1,
    Errored = 2,
    StateMask = 0x000000ff,
    Disturbed = 0x00000100
  };

  uint32_t stateBits() const { return getFixedSlot(Slot_State).toInt32(); }
  void initStateBits(uint32_t stateBits) {
    MOZ_ASSERT((stateBits & ~Disturbed) <= Errored);
    setFixedSlot(Slot_State, JS::Int32Value(stateBits));
  }
  void setStateBits(uint32_t stateBits) {
#ifdef DEBUG
    bool wasDisturbed = disturbed();
    bool wasClosedOrErrored = closed() || errored();
#endif
    initStateBits(stateBits);
    MOZ_ASSERT_IF(wasDisturbed, disturbed());
    MOZ_ASSERT_IF(wasClosedOrErrored, !readable());
  }

  StateBits state() const { return StateBits(stateBits() & StateMask); }
  void setState(StateBits state) {
    MOZ_ASSERT(state <= Errored);
    uint32_t current = stateBits() & ~StateMask;
    setStateBits(current | state);
  }

 public:
  bool readable() const { return state() == Readable; }
  bool closed() const { return state() == Closed; }
  void setClosed() { setState(Closed); }
  bool errored() const { return state() == Errored; }
  void setErrored() { setState(Errored); }
  bool disturbed() const { return stateBits() & Disturbed; }
  void setDisturbed() { setStateBits(stateBits() | Disturbed); }

  bool hasController() const {
    return !getFixedSlot(Slot_Controller).isUndefined();
  }
  inline ReadableStreamController* controller() const;
  inline void setController(ReadableStreamController* controller);
  void clearController() {
    setFixedSlot(Slot_Controller, JS::UndefinedValue());
  }

  bool hasReader() const { return !getFixedSlot(Slot_Reader).isUndefined(); }
  void setReader(JSObject* reader) {
    setFixedSlot(Slot_Reader, JS::ObjectValue(*reader));
  }
  void clearReader() { setFixedSlot(Slot_Reader, JS::UndefinedValue()); }

  JS::Value storedError() const { return getFixedSlot(Slot_StoredError); }
  void setStoredError(JS::Handle<JS::Value> value) {
    setFixedSlot(Slot_StoredError, value);
  }

  JS::ReadableStreamMode mode() const;

  bool locked() const;

  static MOZ_MUST_USE ReadableStream* create(
      JSContext* cx, void* nsISupportsObject_alreadyAddreffed = nullptr,
      JS::Handle<JSObject*> proto = nullptr);
  static ReadableStream* createExternalSourceStream(
      JSContext* cx, JS::ReadableStreamUnderlyingSource* source,
      void* nsISupportsObject_alreadyAddreffed = nullptr,
      JS::Handle<JSObject*> proto = nullptr);

  static bool constructor(JSContext* cx, unsigned argc, Value* vp);
  static const ClassSpec classSpec_;
  static const JSClass class_;
  static const ClassSpec protoClassSpec_;
  static const JSClass protoClass_;
};

extern MOZ_MUST_USE bool SetUpExternalReadableByteStreamController(
    JSContext* cx, JS::Handle<ReadableStream*> stream,
    JS::ReadableStreamUnderlyingSource* source);

}  // namespace js

#endif  // builtin_streams_ReadableStream_h