1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef ReadableStreamImpl_h
6#define ReadableStreamImpl_h
7
8#include "bindings/core/v8/ExceptionState.h"
9#include "bindings/core/v8/ScriptState.h"
10#include "bindings/core/v8/ScriptValue.h"
11#include "bindings/core/v8/V8Binding.h"
12#include "core/streams/ReadableStream.h"
13#include "wtf/ArrayBuffer.h"
14#include "wtf/Deque.h"
15#include "wtf/Forward.h"
16#include "wtf/OwnPtr.h"
17#include "wtf/RefPtr.h"
18#include "wtf/text/WTFString.h"
19
20namespace blink {
21
22// We define the default ChunkTypeTraits for frequently used types.
23template<typename ChunkType>
24class ReadableStreamChunkTypeTraits { };
25
26template<>
27class ReadableStreamChunkTypeTraits<String> {
28public:
29    typedef String HoldType;
30    typedef const String& PassType;
31
32    static size_t size(const String& value) { return value.length(); }
33    static ScriptValue toScriptValue(ScriptState* scriptState, const HoldType& value)
34    {
35        return ScriptValue(scriptState, v8String(scriptState->isolate(), value));
36    }
37};
38
39template<>
40class ReadableStreamChunkTypeTraits<ArrayBuffer> {
41public:
42    typedef RefPtr<ArrayBuffer> HoldType;
43    typedef PassRefPtr<ArrayBuffer> PassType;
44
45    static size_t size(const PassType& value) { return value->byteLength(); }
46    static size_t size(const HoldType& value) { return value->byteLength(); }
47    static ScriptValue toScriptValue(ScriptState* scriptState, const HoldType& value)
48    {
49        return ScriptValue(scriptState, toV8NoInline(value.get(), scriptState->context()->Global(), scriptState->isolate()));
50    }
51};
52
53// ReadableStreamImpl<ChunkTypeTraits> is a ReadableStream subtype. It has a
54// queue whose type depends on ChunkTypeTraits and it implements queue-related
55// ReadableStream pure virtual methods.
56template <typename ChunkTypeTraits>
57class ReadableStreamImpl : public ReadableStream {
58public:
59    ReadableStreamImpl(ExecutionContext* executionContext, UnderlyingSource* source)
60        : ReadableStream(executionContext, source)
61        , m_totalQueueSize(0) { }
62    virtual ~ReadableStreamImpl() { }
63
64    // ReadableStream methods
65    virtual ScriptValue read(ScriptState*, ExceptionState&) OVERRIDE;
66
67    bool enqueue(typename ChunkTypeTraits::PassType);
68
69    virtual void trace(Visitor* visitor) OVERRIDE
70    {
71        ReadableStream::trace(visitor);
72    }
73
74private:
75    // ReadableStream methods
76    virtual bool isQueueEmpty() const OVERRIDE { return m_queue.isEmpty(); }
77    virtual void clearQueue() OVERRIDE
78    {
79        m_queue.clear();
80        m_totalQueueSize = 0;
81    }
82
83    Deque<typename ChunkTypeTraits::HoldType> m_queue;
84    size_t m_totalQueueSize;
85};
86
87template <typename ChunkTypeTraits>
88bool ReadableStreamImpl<ChunkTypeTraits>::enqueue(typename ChunkTypeTraits::PassType chunk)
89{
90    size_t size = ChunkTypeTraits::size(chunk);
91    if (!enqueuePreliminaryCheck(size))
92        return false;
93    m_queue.append(chunk);
94    m_totalQueueSize += size;
95    return enqueuePostAction(m_totalQueueSize);
96}
97
98template <typename ChunkTypeTraits>
99ScriptValue ReadableStreamImpl<ChunkTypeTraits>::read(ScriptState* scriptState, ExceptionState& exceptionState)
100{
101    readPreliminaryCheck(exceptionState);
102    if (exceptionState.hadException())
103        return ScriptValue();
104    ASSERT(state() == Readable);
105    ASSERT(!m_queue.isEmpty());
106    typename ChunkTypeTraits::HoldType chunk = m_queue.takeFirst();
107    m_totalQueueSize -= ChunkTypeTraits::size(chunk);
108    readPostAction();
109    return ChunkTypeTraits::toScriptValue(scriptState, chunk);
110}
111
112} // namespace blink
113
114#endif // ReadableStreamImpl_h
115
116