1 | // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors |
2 | // Licensed under the MIT License: |
3 | // |
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | // of this software and associated documentation files (the "Software"), to deal |
6 | // in the Software without restriction, including without limitation the rights |
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
8 | // copies of the Software, and to permit persons to whom the Software is |
9 | // furnished to do so, subject to the following conditions: |
10 | // |
11 | // The above copyright notice and this permission notice shall be included in |
12 | // all copies or substantial portions of the Software. |
13 | // |
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
20 | // THE SOFTWARE. |
21 | |
22 | // This file is included from all generated headers. |
23 | |
24 | #pragma once |
25 | |
26 | #if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) |
27 | #pragma GCC system_header |
28 | #endif |
29 | |
30 | #include "raw-schema.h" |
31 | #include "layout.h" |
32 | #include "list.h" |
33 | #include "orphan.h" |
34 | #include "pointer-helpers.h" |
35 | #include "any.h" |
36 | #include <kj/string.h> |
37 | #include <kj/string-tree.h> |
38 | #include <kj/hash.h> |
39 | |
40 | namespace capnp { |
41 | |
42 | class MessageBuilder; // So that it can be declared a friend. |
43 | |
44 | template <typename T, Kind k = CAPNP_KIND(T)> |
45 | struct ToDynamic_; // Defined in dynamic.h, needs to be declared as everyone's friend. |
46 | |
47 | struct DynamicStruct; // So that it can be declared a friend. |
48 | |
49 | struct Capability; // To declare brandBindingFor<Capability>() |
50 | |
51 | namespace _ { // private |
52 | |
53 | #if !CAPNP_LITE |
54 | |
55 | template <typename T, typename CapnpPrivate = typename T::_capnpPrivate, bool = false> |
56 | inline const RawSchema& rawSchema() { |
57 | return *CapnpPrivate::schema; |
58 | } |
59 | template <typename T, uint64_t id = schemas::EnumInfo<T>::typeId> |
60 | inline const RawSchema& rawSchema() { |
61 | return *schemas::EnumInfo<T>::schema; |
62 | } |
63 | |
64 | template <typename T, typename CapnpPrivate = typename T::_capnpPrivate> |
65 | inline const RawBrandedSchema& rawBrandedSchema() { |
66 | return *CapnpPrivate::brand(); |
67 | } |
68 | template <typename T, uint64_t id = schemas::EnumInfo<T>::typeId> |
69 | inline const RawBrandedSchema& rawBrandedSchema() { |
70 | return schemas::EnumInfo<T>::schema->defaultBrand; |
71 | } |
72 | |
73 | template <typename TypeTag, typename... Params> |
74 | struct ChooseBrand; |
75 | // If all of `Params` are `AnyPointer`, return the type's default brand. Otherwise, return a |
76 | // specific brand instance. TypeTag is the _capnpPrivate struct for the type in question. |
77 | |
78 | template <typename TypeTag> |
79 | struct ChooseBrand<TypeTag> { |
80 | // All params were AnyPointer. No specific brand needed. |
81 | static constexpr _::RawBrandedSchema const* brand() { return &TypeTag::schema->defaultBrand; } |
82 | }; |
83 | |
84 | template <typename TypeTag, typename... Rest> |
85 | struct ChooseBrand<TypeTag, AnyPointer, Rest...>: public ChooseBrand<TypeTag, Rest...> {}; |
86 | // The first parameter is AnyPointer, so recurse to check the rest. |
87 | |
88 | template <typename TypeTag, typename First, typename... Rest> |
89 | struct ChooseBrand<TypeTag, First, Rest...> { |
90 | // At least one parameter is not AnyPointer, so use the specificBrand constant. |
91 | static constexpr _::RawBrandedSchema const* brand() { return &TypeTag::specificBrand; } |
92 | }; |
93 | |
94 | template <typename T, Kind k = kind<T>()> |
95 | struct BrandBindingFor_; |
96 | |
97 | #define HANDLE_TYPE(Type, which) \ |
98 | template <> \ |
99 | struct BrandBindingFor_<Type, Kind::PRIMITIVE> { \ |
100 | static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { \ |
101 | return { which, listDepth, nullptr }; \ |
102 | } \ |
103 | } |
104 | HANDLE_TYPE(Void, 0); |
105 | HANDLE_TYPE(bool, 1); |
106 | HANDLE_TYPE(int8_t, 2); |
107 | HANDLE_TYPE(int16_t, 3); |
108 | HANDLE_TYPE(int32_t, 4); |
109 | HANDLE_TYPE(int64_t, 5); |
110 | HANDLE_TYPE(uint8_t, 6); |
111 | HANDLE_TYPE(uint16_t, 7); |
112 | HANDLE_TYPE(uint32_t, 8); |
113 | HANDLE_TYPE(uint64_t, 9); |
114 | HANDLE_TYPE(float, 10); |
115 | HANDLE_TYPE(double, 11); |
116 | #undef HANDLE_TYPE |
117 | |
118 | template <> |
119 | struct BrandBindingFor_<Text, Kind::BLOB> { |
120 | static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { |
121 | return { 12, listDepth, nullptr }; |
122 | } |
123 | }; |
124 | |
125 | template <> |
126 | struct BrandBindingFor_<Data, Kind::BLOB> { |
127 | static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { |
128 | return { 13, listDepth, nullptr }; |
129 | } |
130 | }; |
131 | |
132 | template <typename T> |
133 | struct BrandBindingFor_<List<T>, Kind::LIST> { |
134 | static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { |
135 | return BrandBindingFor_<T>::get(listDepth + 1); |
136 | } |
137 | }; |
138 | |
139 | template <typename T> |
140 | struct BrandBindingFor_<T, Kind::ENUM> { |
141 | static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { |
142 | return { 15, listDepth, nullptr }; |
143 | } |
144 | }; |
145 | |
146 | template <typename T> |
147 | struct BrandBindingFor_<T, Kind::STRUCT> { |
148 | static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { |
149 | return { 16, listDepth, T::_capnpPrivate::brand() }; |
150 | } |
151 | }; |
152 | |
153 | template <typename T> |
154 | struct BrandBindingFor_<T, Kind::INTERFACE> { |
155 | static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { |
156 | return { 17, listDepth, T::_capnpPrivate::brand() }; |
157 | } |
158 | }; |
159 | |
160 | template <> |
161 | struct BrandBindingFor_<AnyPointer, Kind::OTHER> { |
162 | static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { |
163 | return { 18, listDepth, 0, 0 }; |
164 | } |
165 | }; |
166 | |
167 | template <> |
168 | struct BrandBindingFor_<AnyStruct, Kind::OTHER> { |
169 | static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { |
170 | return { 18, listDepth, 0, 1 }; |
171 | } |
172 | }; |
173 | |
174 | template <> |
175 | struct BrandBindingFor_<AnyList, Kind::OTHER> { |
176 | static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { |
177 | return { 18, listDepth, 0, 2 }; |
178 | } |
179 | }; |
180 | |
181 | template <> |
182 | struct BrandBindingFor_<Capability, Kind::OTHER> { |
183 | static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { |
184 | return { 18, listDepth, 0, 3 }; |
185 | } |
186 | }; |
187 | |
188 | template <typename T> |
189 | constexpr RawBrandedSchema::Binding brandBindingFor() { |
190 | return BrandBindingFor_<T>::get(0); |
191 | } |
192 | |
193 | kj::StringTree structString(StructReader reader, const RawBrandedSchema& schema); |
194 | kj::String enumString(uint16_t value, const RawBrandedSchema& schema); |
195 | // Declared here so that we can declare inline stringify methods on generated types. |
196 | // Defined in stringify.c++, which depends on dynamic.c++, which is allowed not to be linked in. |
197 | |
198 | template <typename T> |
199 | inline kj::StringTree structString(StructReader reader) { |
200 | return structString(reader, rawBrandedSchema<T>()); |
201 | } |
202 | template <typename T> |
203 | inline kj::String enumString(T value) { |
204 | return enumString(static_cast<uint16_t>(value), rawBrandedSchema<T>()); |
205 | } |
206 | |
207 | #endif // !CAPNP_LITE |
208 | |
209 | // TODO(cleanup): Unify ConstStruct and ConstList. |
210 | template <typename T> |
211 | class ConstStruct { |
212 | public: |
213 | ConstStruct() = delete; |
214 | KJ_DISALLOW_COPY(ConstStruct); |
215 | inline explicit constexpr ConstStruct(const word* ptr): ptr(ptr) {} |
216 | |
217 | inline typename T::Reader get() const { |
218 | return AnyPointer::Reader(PointerReader::getRootUnchecked(ptr)).getAs<T>(); |
219 | } |
220 | |
221 | inline operator typename T::Reader() const { return get(); } |
222 | inline typename T::Reader operator*() const { return get(); } |
223 | inline TemporaryPointer<typename T::Reader> operator->() const { return get(); } |
224 | |
225 | private: |
226 | const word* ptr; |
227 | }; |
228 | |
229 | template <typename T> |
230 | class ConstList { |
231 | public: |
232 | ConstList() = delete; |
233 | KJ_DISALLOW_COPY(ConstList); |
234 | inline explicit constexpr ConstList(const word* ptr): ptr(ptr) {} |
235 | |
236 | inline typename List<T>::Reader get() const { |
237 | return AnyPointer::Reader(PointerReader::getRootUnchecked(ptr)).getAs<List<T>>(); |
238 | } |
239 | |
240 | inline operator typename List<T>::Reader() const { return get(); } |
241 | inline typename List<T>::Reader operator*() const { return get(); } |
242 | inline TemporaryPointer<typename List<T>::Reader> operator->() const { return get(); } |
243 | |
244 | private: |
245 | const word* ptr; |
246 | }; |
247 | |
248 | template <size_t size> |
249 | class ConstText { |
250 | public: |
251 | ConstText() = delete; |
252 | KJ_DISALLOW_COPY(ConstText); |
253 | inline explicit constexpr ConstText(const word* ptr): ptr(ptr) {} |
254 | |
255 | inline Text::Reader get() const { |
256 | return Text::Reader(reinterpret_cast<const char*>(ptr), size); |
257 | } |
258 | |
259 | inline operator Text::Reader() const { return get(); } |
260 | inline Text::Reader operator*() const { return get(); } |
261 | inline TemporaryPointer<Text::Reader> operator->() const { return get(); } |
262 | |
263 | inline kj::StringPtr toString() const { |
264 | return get(); |
265 | } |
266 | |
267 | private: |
268 | const word* ptr; |
269 | }; |
270 | |
271 | template <size_t size> |
272 | inline kj::StringPtr KJ_STRINGIFY(const ConstText<size>& s) { |
273 | return s.get(); |
274 | } |
275 | |
276 | template <size_t size> |
277 | class ConstData { |
278 | public: |
279 | ConstData() = delete; |
280 | KJ_DISALLOW_COPY(ConstData); |
281 | inline explicit constexpr ConstData(const word* ptr): ptr(ptr) {} |
282 | |
283 | inline Data::Reader get() const { |
284 | return Data::Reader(reinterpret_cast<const byte*>(ptr), size); |
285 | } |
286 | |
287 | inline operator Data::Reader() const { return get(); } |
288 | inline Data::Reader operator*() const { return get(); } |
289 | inline TemporaryPointer<Data::Reader> operator->() const { return get(); } |
290 | |
291 | private: |
292 | const word* ptr; |
293 | }; |
294 | |
295 | template <size_t size> |
296 | inline auto KJ_STRINGIFY(const ConstData<size>& s) -> decltype(kj::toCharSequence(s.get())) { |
297 | return kj::toCharSequence(s.get()); |
298 | } |
299 | |
300 | } // namespace _ (private) |
301 | |
302 | template <typename T, typename CapnpPrivate = typename T::_capnpPrivate> |
303 | inline constexpr uint64_t typeId() { return CapnpPrivate::typeId; } |
304 | template <typename T, uint64_t id = schemas::EnumInfo<T>::typeId> |
305 | inline constexpr uint64_t typeId() { return id; } |
306 | // typeId<MyType>() returns the type ID as defined in the schema. Works with structs, enums, and |
307 | // interfaces. |
308 | |
309 | template <typename T> |
310 | inline constexpr uint sizeInWords() { |
311 | // Return the size, in words, of a Struct type, if allocated free-standing (not in a list). |
312 | // May be useful for pre-computing space needed in order to precisely allocate messages. |
313 | |
314 | return unbound((upgradeBound<uint>(_::structSize<T>().data) + |
315 | _::structSize<T>().pointers * WORDS_PER_POINTER) / WORDS); |
316 | } |
317 | |
318 | } // namespace capnp |
319 | |
320 | #if _MSC_VER |
321 | // MSVC doesn't understand floating-point constexpr yet. |
322 | // |
323 | // TODO(msvc): Remove this hack when MSVC is fixed. |
324 | #define CAPNP_NON_INT_CONSTEXPR_DECL_INIT(value) |
325 | #define CAPNP_NON_INT_CONSTEXPR_DEF_INIT(value) = value |
326 | #else |
327 | #define CAPNP_NON_INT_CONSTEXPR_DECL_INIT(value) = value |
328 | #define CAPNP_NON_INT_CONSTEXPR_DEF_INIT(value) |
329 | #endif |
330 | |
331 | #if _MSC_VER |
332 | // TODO(msvc): A little hack to allow MSVC to use C++14 return type deduction in cases where the |
333 | // explicit type exposes bugs in the compiler. |
334 | #define CAPNP_AUTO_IF_MSVC(...) auto |
335 | #else |
336 | #define CAPNP_AUTO_IF_MSVC(...) __VA_ARGS__ |
337 | #endif |
338 | |
339 | #if CAPNP_LITE |
340 | |
341 | #define CAPNP_DECLARE_SCHEMA(id) \ |
342 | extern ::capnp::word const* const bp_##id |
343 | |
344 | #define CAPNP_DECLARE_ENUM(type, id) \ |
345 | inline ::kj::String KJ_STRINGIFY(type##_##id value) { \ |
346 | return ::kj::str(static_cast<uint16_t>(value)); \ |
347 | } \ |
348 | template <> struct EnumInfo<type##_##id> { \ |
349 | struct IsEnum; \ |
350 | static constexpr uint64_t typeId = 0x##id; \ |
351 | static inline ::capnp::word const* encodedSchema() { return bp_##id; } \ |
352 | } |
353 | |
354 | #if _MSC_VER |
355 | // TODO(msvc): MSVC dosen't expect constexprs to have definitions. |
356 | #define CAPNP_DEFINE_ENUM(type, id) |
357 | #else |
358 | #define CAPNP_DEFINE_ENUM(type, id) \ |
359 | constexpr uint64_t EnumInfo<type>::typeId |
360 | #endif |
361 | |
362 | #define CAPNP_DECLARE_STRUCT_HEADER(id, dataWordSize_, pointerCount_) \ |
363 | struct IsStruct; \ |
364 | static constexpr uint64_t typeId = 0x##id; \ |
365 | static constexpr uint16_t dataWordSize = dataWordSize_; \ |
366 | static constexpr uint16_t pointerCount = pointerCount_; \ |
367 | static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } |
368 | |
369 | #else // CAPNP_LITE |
370 | |
371 | #define CAPNP_DECLARE_SCHEMA(id) \ |
372 | extern ::capnp::word const* const bp_##id; \ |
373 | extern const ::capnp::_::RawSchema s_##id |
374 | |
375 | #define CAPNP_DECLARE_ENUM(type, id) \ |
376 | inline ::kj::String KJ_STRINGIFY(type##_##id value) { \ |
377 | return ::capnp::_::enumString(value); \ |
378 | } \ |
379 | template <> struct EnumInfo<type##_##id> { \ |
380 | struct IsEnum; \ |
381 | static constexpr uint64_t typeId = 0x##id; \ |
382 | static inline ::capnp::word const* encodedSchema() { return bp_##id; } \ |
383 | static constexpr ::capnp::_::RawSchema const* schema = &s_##id; \ |
384 | } |
385 | #define CAPNP_DEFINE_ENUM(type, id) \ |
386 | constexpr uint64_t EnumInfo<type>::typeId; \ |
387 | constexpr ::capnp::_::RawSchema const* EnumInfo<type>::schema |
388 | |
389 | #define (id, dataWordSize_, pointerCount_) \ |
390 | struct IsStruct; \ |
391 | static constexpr uint64_t typeId = 0x##id; \ |
392 | static constexpr ::capnp::Kind kind = ::capnp::Kind::STRUCT; \ |
393 | static constexpr uint16_t dataWordSize = dataWordSize_; \ |
394 | static constexpr uint16_t pointerCount = pointerCount_; \ |
395 | static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } \ |
396 | static constexpr ::capnp::_::RawSchema const* schema = &::capnp::schemas::s_##id; |
397 | |
398 | #define (id) \ |
399 | struct IsInterface; \ |
400 | static constexpr uint64_t typeId = 0x##id; \ |
401 | static constexpr ::capnp::Kind kind = ::capnp::Kind::INTERFACE; \ |
402 | static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } \ |
403 | static constexpr ::capnp::_::RawSchema const* schema = &::capnp::schemas::s_##id; |
404 | |
405 | #endif // CAPNP_LITE, else |
406 | |