1/*
2 * Copyright (C) 2013 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2011 The Chromium Authors. 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 APPLE 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 APPLE 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 InspectorTypeBuilder_h
28#define InspectorTypeBuilder_h
29
30#if ENABLE(INSPECTOR)
31
32#include "InspectorValues.h"
33#include <wtf/Assertions.h>
34#include <wtf/PassRefPtr.h>
35
36namespace Inspector {
37
38namespace TypeBuilder {
39
40template<typename T>
41class OptOutput {
42public:
43    OptOutput() : m_assigned(false) { }
44
45    void operator=(T value)
46    {
47        m_value = value;
48        m_assigned = true;
49    }
50
51    bool isAssigned() const { return m_assigned; }
52
53    T getValue()
54    {
55        ASSERT(isAssigned());
56        return m_value;
57    }
58
59private:
60    T m_value;
61    bool m_assigned;
62
63    WTF_MAKE_NONCOPYABLE(OptOutput);
64};
65
66
67// A small transient wrapper around int type, that can be used as a funciton parameter type
68// cleverly disallowing C++ implicit casts from float or double.
69class ExactlyInt {
70public:
71    template<typename T>
72    ExactlyInt(T t) : m_value(cast_to_int<T>(t)) { }
73    ExactlyInt() { }
74
75    operator int() { return m_value; }
76
77private:
78    int m_value;
79
80    template<typename T>
81    static int cast_to_int(T) { return T::default_case_cast_is_not_supported(); }
82};
83
84template<>
85inline int ExactlyInt::cast_to_int<int>(int i) { return i; }
86
87template<>
88inline int ExactlyInt::cast_to_int<unsigned int>(unsigned int i) { return i; }
89
90#if !ASSERT_DISABLED
91class RuntimeCastHelper {
92public:
93    template<InspectorValue::Type TYPE>
94    static void assertType(InspectorValue* value)
95    {
96        ASSERT(value->type() == TYPE);
97    }
98
99    static void assertAny(InspectorValue*)
100    {
101    }
102
103    static void assertInt(InspectorValue* value)
104    {
105        double v;
106        bool castRes = value->asNumber(&v);
107        ASSERT_UNUSED(castRes, castRes);
108        ASSERT(static_cast<double>(static_cast<int>(v)) == v);
109    }
110};
111#endif
112
113
114// This class provides "Traits" type for the input type T. It is programmed using C++ template specialization
115// technique. By default it simply takes "ItemTraits" type from T, but it doesn't work with the base types.
116template<typename T>
117struct ArrayItemHelper {
118    typedef typename T::ItemTraits Traits;
119};
120
121template<typename T>
122class Array : public InspectorArrayBase {
123private:
124    Array() { }
125
126    InspectorArray* openAccessors()
127    {
128        COMPILE_ASSERT(sizeof(InspectorArray) == sizeof(Array<T>), cannot_cast);
129        return static_cast<InspectorArray*>(static_cast<InspectorArrayBase*>(this));
130    }
131
132public:
133    void addItem(PassRefPtr<T> value)
134    {
135        ArrayItemHelper<T>::Traits::pushRefPtr(this->openAccessors(), value);
136    }
137
138    void addItem(T value)
139    {
140        ArrayItemHelper<T>::Traits::pushRaw(this->openAccessors(), value);
141    }
142
143    static PassRefPtr<Array<T>> create()
144    {
145        return adoptRef(new Array<T>());
146    }
147
148    static PassRefPtr<Array<T>> runtimeCast(PassRefPtr<InspectorValue> value)
149    {
150        RefPtr<InspectorArray> array;
151        bool castRes = value->asArray(&array);
152        ASSERT_UNUSED(castRes, castRes);
153#if !ASSERT_DISABLED
154        assertCorrectValue(array.get());
155#endif // !ASSERT_DISABLED
156        COMPILE_ASSERT(sizeof(Array<T>) == sizeof(InspectorArray), type_cast_problem);
157        return static_cast<Array<T>*>(static_cast<InspectorArrayBase*>(array.get()));
158    }
159
160#if !ASSERT_DISABLED
161    static void assertCorrectValue(InspectorValue* value)
162    {
163        RefPtr<InspectorArray> array;
164        bool castRes = value->asArray(&array);
165        ASSERT_UNUSED(castRes, castRes);
166        for (unsigned i = 0; i < array->length(); i++)
167            ArrayItemHelper<T>::Traits::template assertCorrectValue<T>(array->get(i).get());
168    }
169#endif // !ASSERT_DISABLED
170};
171
172struct StructItemTraits {
173    static void pushRefPtr(InspectorArray* array, PassRefPtr<InspectorValue> value)
174    {
175        array->pushValue(value);
176    }
177
178#if !ASSERT_DISABLED
179    template<typename T>
180    static void assertCorrectValue(InspectorValue* value)
181    {
182        T::assertCorrectValue(value);
183    }
184#endif // !ASSERT_DISABLED
185};
186
187template<>
188struct ArrayItemHelper<String> {
189    struct Traits {
190        static void pushRaw(InspectorArray* array, const String& value)
191        {
192            array->pushString(value);
193        }
194
195#if !ASSERT_DISABLED
196        template<typename T>
197        static void assertCorrectValue(InspectorValue* value)
198        {
199            RuntimeCastHelper::assertType<InspectorValue::TypeString>(value);
200        }
201#endif // !ASSERT_DISABLED
202    };
203};
204
205template<>
206struct ArrayItemHelper<int> {
207    struct Traits {
208        static void pushRaw(InspectorArray* array, int value)
209        {
210            array->pushInt(value);
211        }
212
213#if !ASSERT_DISABLED
214        template<typename T>
215        static void assertCorrectValue(InspectorValue* value)
216        {
217            RuntimeCastHelper::assertInt(value);
218        }
219#endif // !ASSERT_DISABLED
220    };
221};
222
223template<>
224struct ArrayItemHelper<double> {
225    struct Traits {
226        static void pushRaw(InspectorArray* array, double value)
227        {
228            array->pushNumber(value);
229        }
230
231#if !ASSERT_DISABLED
232        template<typename T>
233        static void assertCorrectValue(InspectorValue* value)
234        {
235            RuntimeCastHelper::assertType<InspectorValue::TypeNumber>(value);
236        }
237#endif // !ASSERT_DISABLED
238    };
239};
240
241template<>
242struct ArrayItemHelper<bool> {
243    struct Traits {
244        static void pushRaw(InspectorArray* array, bool value)
245        {
246            array->pushBoolean(value);
247        }
248
249#if !ASSERT_DISABLED
250        template<typename T>
251        static void assertCorrectValue(InspectorValue* value)
252        {
253            RuntimeCastHelper::assertType<InspectorValue::TypeBoolean>(value);
254        }
255#endif // !ASSERT_DISABLED
256    };
257};
258
259template<>
260struct ArrayItemHelper<InspectorValue> {
261    struct Traits {
262        static void pushRefPtr(InspectorArray* array, PassRefPtr<InspectorValue> value)
263        {
264            array->pushValue(value);
265        }
266
267#if !ASSERT_DISABLED
268        template<typename T>
269        static void assertCorrectValue(InspectorValue* value)
270        {
271            RuntimeCastHelper::assertAny(value);
272        }
273#endif // !ASSERT_DISABLED
274    };
275};
276
277template<>
278struct ArrayItemHelper<InspectorObject> {
279    struct Traits {
280        static void pushRefPtr(InspectorArray* array, PassRefPtr<InspectorValue> value)
281        {
282            array->pushValue(value);
283        }
284
285#if !ASSERT_DISABLED
286        template<typename T>
287        static void assertCorrectValue(InspectorValue* value)
288        {
289            RuntimeCastHelper::assertType<InspectorValue::TypeObject>(value);
290        }
291#endif // !ASSERT_DISABLED
292    };
293};
294
295template<>
296struct ArrayItemHelper<InspectorArray> {
297    struct Traits {
298        static void pushRefPtr(InspectorArray* array, PassRefPtr<InspectorArray> value)
299        {
300            array->pushArray(value);
301        }
302
303#if !ASSERT_DISABLED
304        template<typename T>
305        static void assertCorrectValue(InspectorValue* value)
306        {
307            RuntimeCastHelper::assertType<InspectorValue::TypeArray>(value);
308        }
309#endif // !ASSERT_DISABLED
310    };
311};
312
313template<typename T>
314struct ArrayItemHelper<TypeBuilder::Array<T>> {
315    struct Traits {
316        static void pushRefPtr(InspectorArray* array, PassRefPtr<TypeBuilder::Array<T>> value)
317        {
318            array->pushValue(value);
319        }
320
321#if !ASSERT_DISABLED
322        template<typename S>
323        static void assertCorrectValue(InspectorValue* value)
324        {
325            S::assertCorrectValue(value);
326        }
327#endif // !ASSERT_DISABLED
328    };
329};
330
331} // namespace TypeBuilder
332
333} // namespace Inspector
334
335#endif // ENABLE(INSPECTOR)
336
337#endif // !defined(InspectorTypeBuilder_h)
338