Index: Source/core/streams/ExclusiveStreamReader.cpp |
diff --git a/Source/core/streams/ExclusiveStreamReader.cpp b/Source/core/streams/ExclusiveStreamReader.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9615cefa95d93f7447ffc970bc89626a9a5654e4 |
--- /dev/null |
+++ b/Source/core/streams/ExclusiveStreamReader.cpp |
@@ -0,0 +1,198 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "config.h" |
+#include "core/streams/ExclusiveStreamReader.h" |
+ |
+#include "bindings/core/v8/ExceptionState.h" |
+#include "bindings/core/v8/ScriptFunction.h" |
+#include "bindings/core/v8/ScriptPromiseResolver.h" |
+#include "core/dom/DOMException.h" |
+#include "core/streams/ReadableStream.h" |
+ |
+namespace blink { |
+ |
+namespace { |
+ |
+class PromiseRaceFulfillHandler : public ScriptFunction { |
+public: |
+ static v8::Handle<v8::Function> create(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver) |
+ { |
+ return (new PromiseRaceFulfillHandler(resolver))->bindToV8Function(); |
+ } |
+ |
+ void trace(Visitor* visitor) |
+ { |
+ visitor->trace(m_resolver); |
+ ScriptFunction::trace(visitor); |
+ } |
+ |
+private: |
+ explicit PromiseRaceFulfillHandler(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver) |
+ : ScriptFunction(resolver->scriptState()) |
+ , m_resolver(resolver) { } |
+ ScriptValue call(ScriptValue value) override |
+ { |
+ m_resolver->resolve(value); |
+ return ScriptValue(scriptState(), v8::Undefined(scriptState()->isolate())); |
+ } |
+ |
+ RefPtrWillBeMember<ScriptPromiseResolver> m_resolver; |
+}; |
+ |
+class PromiseRaceRejectHandler : public ScriptFunction { |
+public: |
+ static v8::Handle<v8::Function> create(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver) |
+ { |
+ return (new PromiseRaceRejectHandler(resolver))->bindToV8Function(); |
+ } |
+ |
+ void trace(Visitor* visitor) |
+ { |
+ visitor->trace(m_resolver); |
+ ScriptFunction::trace(visitor); |
+ } |
+ |
+private: |
+ explicit PromiseRaceRejectHandler(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver) |
+ : ScriptFunction(resolver->scriptState()) |
+ , m_resolver(resolver) { } |
+ ScriptValue call(ScriptValue value) override |
+ { |
+ m_resolver->reject(value); |
+ return ScriptValue(scriptState(), v8::Undefined(scriptState()->isolate())); |
+ } |
+ |
+ RefPtrWillBeMember<ScriptPromiseResolver> m_resolver; |
+}; |
+ |
+ScriptPromise race(ScriptState* scriptState, const Vector<ScriptPromise>& promises) |
+{ |
+ RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState); |
+ for (ScriptPromise promise : promises) { |
+ promise.then(PromiseRaceFulfillHandler::create(resolver), PromiseRaceRejectHandler::create(resolver)); |
+ } |
+ return resolver->promise(); |
+} |
+ |
+} // namespace |
+ |
+ExclusiveStreamReader::ExclusiveStreamReader(ReadableStream* stream) |
+ : ActiveDOMObject(stream->executionContext()) |
+ , m_stream(stream) |
+ , m_released(new ReleasedPromise(stream->executionContext(), this, ReleasedPromise::Released)) |
+ , m_stateAfterRelease(ReadableStream::Closed) |
+{ |
+ suspendIfNeeded(); |
+ ASSERT(m_stream->isLockedTo(nullptr)); |
+ m_stream->setReader(this); |
+} |
+ |
+ScriptPromise ExclusiveStreamReader::closed(ScriptState* scriptState) |
+{ |
+ if (isActive()) { |
+ Vector<ScriptPromise> promises; |
+ promises.append(m_stream->closed(scriptState)); |
+ promises.append(m_released->promise(scriptState->world())); |
+ return race(scriptState, promises); |
+ } |
+ ASSERT(m_released); |
+ return m_closedAfterRelease->promise(scriptState->world()); |
+} |
+ |
+bool ExclusiveStreamReader::isActive() const |
+{ |
+ return m_stream->isLockedTo(this); |
+} |
+ |
+ScriptPromise ExclusiveStreamReader::ready(ScriptState* scriptState) |
+{ |
+ if (isActive()) { |
+ Vector<ScriptPromise> promises; |
+ promises.append(m_stream->readyInternal(scriptState)); |
+ promises.append(m_released->promise(scriptState->world())); |
+ return race(scriptState, promises); |
+ } |
+ ASSERT(m_readyAfterRelease); |
+ return m_readyAfterRelease->promise(scriptState->world()); |
+} |
+ |
+String ExclusiveStreamReader::state() const |
+{ |
+ if (isActive()) |
+ return ReadableStream::stateToString(m_stream->stateInternal()); |
+ return ReadableStream::stateToString(m_stateAfterRelease); |
+} |
+ |
+ScriptPromise ExclusiveStreamReader::cancel(ScriptState* scriptState, ScriptValue reason) |
+{ |
+ if (isActive()) { |
+ releaseLock(); |
+ return m_stream->cancel(scriptState, reason); |
+ } |
+ return m_closedAfterRelease->promise(scriptState->world()); |
+} |
+ |
+ScriptValue ExclusiveStreamReader::read(ScriptState* scriptState, ExceptionState& es) |
+{ |
+ if (!isActive()) { |
+ es.throwTypeError("The stream is not locked to this reader"); |
+ return ScriptValue(); |
+ } |
+ return m_stream->readInternal(scriptState, es); |
+} |
+ |
+void ExclusiveStreamReader::releaseLock() |
+{ |
+ if (!isActive()) |
+ return; |
+ |
+ m_stream->setReader(nullptr); |
+ |
+ m_readyAfterRelease = new ReadyPromise(executionContext(), this, ReadyPromise::Ready); |
+ m_readyAfterRelease->resolve(ToV8UndefinedGenerator()); |
+ m_closedAfterRelease = new ClosedPromise(executionContext(), this, ReadyPromise::Closed); |
+ |
+ if (m_stream->stateInternal() == ReadableStream::Closed) { |
+ m_stateAfterRelease = ReadableStream::Closed; |
+ m_closedAfterRelease->resolve(ToV8UndefinedGenerator()); |
+ } else if (m_stream->stateInternal() == ReadableStream::Errored) { |
+ m_stateAfterRelease = ReadableStream::Errored; |
+ m_closedAfterRelease->reject(m_stream->storedException()); |
+ } else { |
+ m_stateAfterRelease = ReadableStream::Closed; |
+ m_closedAfterRelease->resolve(ToV8UndefinedGenerator()); |
+ } |
+ m_released->resolve(ToV8UndefinedGenerator()); |
+ ASSERT(!isActive()); |
+} |
+ |
+ScriptPromise ExclusiveStreamReader::released(ScriptState* scriptState) |
+{ |
+ return m_released->promise(scriptState->world()); |
+} |
+ |
+bool ExclusiveStreamReader::hasPendingActivity() const |
+{ |
+ // We need to extend ExclusiveStreamReader's wrapper's life while it is |
+ // active in order to call resolve / reject on ScriptPromiseProperties. |
+ return isActive(); |
+} |
+ |
+void ExclusiveStreamReader::stop() |
+{ |
+ releaseLock(); |
+ ActiveDOMObject::stop(); |
+} |
+ |
+void ExclusiveStreamReader::trace(Visitor* visitor) |
+{ |
+ visitor->trace(m_stream); |
+ visitor->trace(m_released); |
+ visitor->trace(m_closedAfterRelease); |
+ visitor->trace(m_readyAfterRelease); |
+ ActiveDOMObject::trace(visitor); |
+} |
+ |
+} // namespace blink |