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
40namespace capnp {
41
42class MessageBuilder; // So that it can be declared a friend.
43
44template <typename T, Kind k = CAPNP_KIND(T)>
45struct ToDynamic_; // Defined in dynamic.h, needs to be declared as everyone's friend.
46
47struct DynamicStruct; // So that it can be declared a friend.
48
49struct Capability; // To declare brandBindingFor<Capability>()
50
51namespace _ { // private
52
53#if !CAPNP_LITE
54
55template <typename T, typename CapnpPrivate = typename T::_capnpPrivate, bool = false>
56inline const RawSchema& rawSchema() {
57 return *CapnpPrivate::schema;
58}
59template <typename T, uint64_t id = schemas::EnumInfo<T>::typeId>
60inline const RawSchema& rawSchema() {
61 return *schemas::EnumInfo<T>::schema;
62}
63
64template <typename T, typename CapnpPrivate = typename T::_capnpPrivate>
65inline const RawBrandedSchema& rawBrandedSchema() {
66 return *CapnpPrivate::brand();
67}
68template <typename T, uint64_t id = schemas::EnumInfo<T>::typeId>
69inline const RawBrandedSchema& rawBrandedSchema() {
70 return schemas::EnumInfo<T>::schema->defaultBrand;
71}
72
73template <typename TypeTag, typename... Params>
74struct 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
78template <typename TypeTag>
79struct ChooseBrand<TypeTag> {
80 // All params were AnyPointer. No specific brand needed.
81 static constexpr _::RawBrandedSchema const* brand() { return &TypeTag::schema->defaultBrand; }
82};
83
84template <typename TypeTag, typename... Rest>
85struct ChooseBrand<TypeTag, AnyPointer, Rest...>: public ChooseBrand<TypeTag, Rest...> {};
86// The first parameter is AnyPointer, so recurse to check the rest.
87
88template <typename TypeTag, typename First, typename... Rest>
89struct 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
94template <typename T, Kind k = kind<T>()>
95struct 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 }
104HANDLE_TYPE(Void, 0);
105HANDLE_TYPE(bool, 1);
106HANDLE_TYPE(int8_t, 2);
107HANDLE_TYPE(int16_t, 3);
108HANDLE_TYPE(int32_t, 4);
109HANDLE_TYPE(int64_t, 5);
110HANDLE_TYPE(uint8_t, 6);
111HANDLE_TYPE(uint16_t, 7);
112HANDLE_TYPE(uint32_t, 8);
113HANDLE_TYPE(uint64_t, 9);
114HANDLE_TYPE(float, 10);
115HANDLE_TYPE(double, 11);
116#undef HANDLE_TYPE
117
118template <>
119struct BrandBindingFor_<Text, Kind::BLOB> {
120 static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
121 return { 12, listDepth, nullptr };
122 }
123};
124
125template <>
126struct BrandBindingFor_<Data, Kind::BLOB> {
127 static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
128 return { 13, listDepth, nullptr };
129 }
130};
131
132template <typename T>
133struct BrandBindingFor_<List<T>, Kind::LIST> {
134 static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
135 return BrandBindingFor_<T>::get(listDepth + 1);
136 }
137};
138
139template <typename T>
140struct BrandBindingFor_<T, Kind::ENUM> {
141 static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
142 return { 15, listDepth, nullptr };
143 }
144};
145
146template <typename T>
147struct BrandBindingFor_<T, Kind::STRUCT> {
148 static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
149 return { 16, listDepth, T::_capnpPrivate::brand() };
150 }
151};
152
153template <typename T>
154struct BrandBindingFor_<T, Kind::INTERFACE> {
155 static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
156 return { 17, listDepth, T::_capnpPrivate::brand() };
157 }
158};
159
160template <>
161struct BrandBindingFor_<AnyPointer, Kind::OTHER> {
162 static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
163 return { 18, listDepth, 0, 0 };
164 }
165};
166
167template <>
168struct BrandBindingFor_<AnyStruct, Kind::OTHER> {
169 static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
170 return { 18, listDepth, 0, 1 };
171 }
172};
173
174template <>
175struct BrandBindingFor_<AnyList, Kind::OTHER> {
176 static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
177 return { 18, listDepth, 0, 2 };
178 }
179};
180
181template <>
182struct BrandBindingFor_<Capability, Kind::OTHER> {
183 static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
184 return { 18, listDepth, 0, 3 };
185 }
186};
187
188template <typename T>
189constexpr RawBrandedSchema::Binding brandBindingFor() {
190 return BrandBindingFor_<T>::get(0);
191}
192
193kj::StringTree structString(StructReader reader, const RawBrandedSchema& schema);
194kj::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
198template <typename T>
199inline kj::StringTree structString(StructReader reader) {
200 return structString(reader, rawBrandedSchema<T>());
201}
202template <typename T>
203inline 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.
210template <typename T>
211class ConstStruct {
212public:
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
225private:
226 const word* ptr;
227};
228
229template <typename T>
230class ConstList {
231public:
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
244private:
245 const word* ptr;
246};
247
248template <size_t size>
249class ConstText {
250public:
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
267private:
268 const word* ptr;
269};
270
271template <size_t size>
272inline kj::StringPtr KJ_STRINGIFY(const ConstText<size>& s) {
273 return s.get();
274}
275
276template <size_t size>
277class ConstData {
278public:
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
291private:
292 const word* ptr;
293};
294
295template <size_t size>
296inline auto KJ_STRINGIFY(const ConstData<size>& s) -> decltype(kj::toCharSequence(s.get())) {
297 return kj::toCharSequence(s.get());
298}
299
300} // namespace _ (private)
301
302template <typename T, typename CapnpPrivate = typename T::_capnpPrivate>
303inline constexpr uint64_t typeId() { return CapnpPrivate::typeId; }
304template <typename T, uint64_t id = schemas::EnumInfo<T>::typeId>
305inline 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
309template <typename T>
310inline 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 CAPNP_DECLARE_STRUCT_HEADER(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 CAPNP_DECLARE_INTERFACE_HEADER(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