Chromium Code Reviews| 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..f31ba4454eff593a3e11b1517b5a51516736b173 |
| --- /dev/null |
| +++ b/Source/core/streams/ExclusiveStreamReader.cpp |
| @@ -0,0 +1,190 @@ |
| +// 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 |
| +{ |
| + return isActive(); |
|
tyoshino (SeeGerritForStatus)
2015/02/02 08:38:24
can you write some comment explaining why we need
yhirano
2015/02/02 10:21:20
Done.
|
| +} |
| + |
| +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 |