Update serializer and iterator binding generated code
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMIterator.h
1 /*
2  * Copyright (C) 2016 Canon, Inc. All rights reserved.
3  * Copyright (C) 2016 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY CANON INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CANON INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #ifndef JSDOMIterator_h
28 #define JSDOMIterator_h
29
30 #include "JSDOMBinding.h"
31 #include <runtime/IteratorPrototype.h>
32 #include <runtime/JSDestructibleObject.h>
33 #include <type_traits>
34
35 namespace WebCore {
36
37 void addValueIterableMethods(JSC::JSGlobalObject&, JSC::JSObject&);
38
39 template<typename JSWrapper>
40 class JSDOMIteratorPrototype : public JSC::JSNonFinalObject {
41 public:
42     using Base = JSC::JSNonFinalObject;
43     using DOMWrapped = typename JSWrapper::DOMWrapped;
44
45     static JSDOMIteratorPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
46     {
47         JSDOMIteratorPrototype* prototype = new (NotNull, JSC::allocateCell<JSDOMIteratorPrototype>(vm.heap)) JSDOMIteratorPrototype(vm, structure);
48         prototype->finishCreation(vm, globalObject);
49         return prototype;
50     }
51
52     DECLARE_INFO;
53
54     static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
55     {
56         return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
57     }
58
59     static JSC::EncodedJSValue JSC_HOST_CALL next(JSC::ExecState*);
60
61 private:
62     JSDOMIteratorPrototype(JSC::VM& vm, JSC::Structure* structure) : Base(vm, structure) { }
63
64     void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
65 };
66
67 template<typename IteratorValue>
68 class IteratorInspector {
69 private:
70     template<typename T> static constexpr auto test(int) -> decltype(std::declval<T>()->key, std::declval<T>()->value, bool()) { return true; }
71     template<typename T> static constexpr bool test(...) { return false; }
72 public:
73     static constexpr bool isMap = test<IteratorValue>(0);
74     static constexpr bool isSet = !isMap;
75 };
76
77 enum class IterationKind { Key, Value, KeyValue };
78
79 template<typename JSWrapper>
80 class JSDOMIterator: public JSDOMObject {
81 public:
82     using DOMWrapped = typename std::remove_reference<decltype(std::declval<JSWrapper>().wrapped())>::type;
83     using Base = JSDOMObject;
84
85     DECLARE_INFO;
86
87     static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
88     {
89         return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
90     }
91
92     static JSDOMIterator* create(JSC::VM& vm, JSC::Structure* structure, JSWrapper& iteratedObject, IterationKind kind)
93     {
94         JSDOMIterator* instance = new (NotNull, JSC::allocateCell<JSDOMIterator>(vm.heap)) JSDOMIterator(structure, iteratedObject, kind);
95         instance->finishCreation(vm);
96         return instance;
97     }
98
99     static JSDOMIteratorPrototype<JSWrapper>* createPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
100     {
101         return JSDOMIteratorPrototype<JSWrapper>::create(vm, globalObject,
102             JSDOMIteratorPrototype<JSWrapper>::createStructure(vm, globalObject, globalObject->iteratorPrototype()));
103     }
104
105     JSC::JSValue next(JSC::ExecState&);
106
107 private:
108     JSDOMIterator(JSC::Structure* structure, JSWrapper& iteratedObject, IterationKind kind)
109         : Base(structure, *iteratedObject.globalObject())
110         , m_iterator(iteratedObject.wrapped().createIterator())
111         , m_kind(kind)
112     {
113     }
114
115     template<typename IteratorValue> typename std::enable_if<IteratorInspector<IteratorValue>::isMap, JSC::JSValue>::type
116     asJS(JSC::ExecState&, IteratorValue&);
117     template<typename IteratorValue> typename std::enable_if<IteratorInspector<IteratorValue>::isSet, JSC::JSValue>::type
118     asJS(JSC::ExecState&, IteratorValue&);
119
120     static void destroy(JSC::JSCell*);
121
122     Optional<typename DOMWrapped::Iterator> m_iterator;
123     IterationKind m_kind;
124 };
125
126 template<typename JSWrapper>
127 JSC::JSValue iteratorCreate(JSWrapper&, IterationKind);
128 template<typename JSWrapper>
129 JSC::JSValue iteratorForEach(JSC::ExecState&, JSWrapper&, JSC::ThrowScope&);
130
131 template<typename JSWrapper>
132 JSC::JSValue iteratorCreate(JSWrapper& thisObject, IterationKind kind)
133 {
134     ASSERT(thisObject.globalObject());
135     JSDOMGlobalObject& globalObject = *thisObject.globalObject();
136     return JSDOMIterator<JSWrapper>::create(globalObject.vm(), getDOMStructure<JSDOMIterator<JSWrapper>>(globalObject.vm(), globalObject), thisObject, kind);
137 }
138
139 template<typename JSWrapper>
140 template<typename IteratorValue> inline typename std::enable_if<IteratorInspector<IteratorValue>::isMap, JSC::JSValue>::type
141 JSDOMIterator<JSWrapper>::asJS(JSC::ExecState& state, IteratorValue& value)
142 {
143     ASSERT(value);
144     if (m_kind != IterationKind::KeyValue)
145         return toJS(&state, globalObject(), (m_kind == IterationKind::Key) ? value->key : value->value);
146
147     return jsPair(state, globalObject(), value->key, value->value);
148 }
149
150 template<typename JSWrapper>
151 template<typename IteratorValue> inline typename std::enable_if<IteratorInspector<IteratorValue>::isSet, JSC::JSValue>::type
152 JSDOMIterator<JSWrapper>::asJS(JSC::ExecState& state, IteratorValue& value)
153 {
154     ASSERT(value);
155     JSC::JSValue result = toJS(&state, globalObject(), *value);
156     if (m_kind != IterationKind::KeyValue)
157         return result;
158
159     return jsPair(state, globalObject(), result, result);
160 }
161
162 template<typename IteratorValue> typename std::enable_if<IteratorInspector<IteratorValue>::isMap, void>::type
163 appendForEachArguments(JSC::ExecState& state, JSDOMGlobalObject* globalObject, JSC::MarkedArgumentBuffer& arguments, IteratorValue& value)
164 {
165     ASSERT(value);
166     arguments.append(toJS(&state, globalObject, value->value));
167     arguments.append(toJS(&state, globalObject, value->key));
168 }
169
170 template<typename IteratorValue> typename std::enable_if<IteratorInspector<IteratorValue>::isSet, void>::type
171 appendForEachArguments(JSC::ExecState& state, JSDOMGlobalObject* globalObject, JSC::MarkedArgumentBuffer& arguments, IteratorValue& value)
172 {
173     ASSERT(value);
174     JSC::JSValue argument = toJS(&state, globalObject, *value);
175     arguments.append(argument);
176     arguments.append(argument);
177 }
178
179 template<typename JSWrapper>
180 JSC::JSValue iteratorForEach(JSC::ExecState& state, JSWrapper& thisObject, JSC::ThrowScope& scope)
181 {
182     JSC::JSValue callback = state.argument(0);
183     JSC::JSValue thisValue = state.argument(1);
184
185     JSC::CallData callData;
186     JSC::CallType callType = JSC::getCallData(callback, callData);
187     if (callType == JSC::CallType::None)
188         return throwTypeError(&state, scope, ASCIILiteral("Cannot call callback"));
189
190     auto iterator = thisObject.wrapped().createIterator();
191     while (auto value = iterator.next()) {
192         JSC::MarkedArgumentBuffer arguments;
193         appendForEachArguments(state, thisObject.globalObject(), arguments, value);
194         arguments.append(&thisObject);
195         JSC::call(&state, callback, callType, callData, thisValue, arguments);
196         if (UNLIKELY(scope.exception()))
197             break;
198     }
199     return JSC::jsUndefined();
200 }
201
202 template<typename JSWrapper>
203 void JSDOMIterator<JSWrapper>::destroy(JSCell* cell)
204 {
205     JSDOMIterator<JSWrapper>* thisObject = JSC::jsCast<JSDOMIterator<JSWrapper>*>(cell);
206     thisObject->JSDOMIterator<JSWrapper>::~JSDOMIterator();
207 }
208
209 template<typename JSWrapper>
210 JSC::JSValue JSDOMIterator<JSWrapper>::next(JSC::ExecState& state)
211 {
212     if (m_iterator) {
213         auto iteratorValue = m_iterator->next();
214         if (iteratorValue)
215             return createIteratorResultObject(&state, asJS(state, iteratorValue), false);
216         m_iterator = Nullopt;
217     }
218     return createIteratorResultObject(&state, JSC::jsUndefined(), true);
219 }
220
221 template<typename JSWrapper>
222 JSC::EncodedJSValue JSC_HOST_CALL JSDOMIteratorPrototype<JSWrapper>::next(JSC::ExecState* state)
223 {
224     JSC::VM& vm = state->vm();
225     auto scope = DECLARE_THROW_SCOPE(vm);
226
227     auto iterator = JSC::jsDynamicCast<JSDOMIterator<JSWrapper>*>(state->thisValue());
228     if (!iterator)
229         return JSC::JSValue::encode(throwTypeError(state, scope, ASCIILiteral("Cannot call next() on a non-Iterator object")));
230
231     return JSC::JSValue::encode(iterator->next(*state));
232 }
233
234 template<typename JSWrapper>
235 void JSDOMIteratorPrototype<JSWrapper>::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
236 {
237     Base::finishCreation(vm);
238     ASSERT(inherits(info()));
239
240     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->next, next, 0, 0, JSC::NoIntrinsic);
241 }
242
243 }
244
245 #endif // !defined(JSDOMIterator_h)