// Copyright (c) 2013, Kenton Varda <temporal@gmail.com> // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // This file is included form all generated headers. #ifndef CAPNP_GENERATED_HEADER_SUPPORT_H_ #define CAPNP_GENERATED_HEADER_SUPPORT_H_ #include "layout.h" #include "list.h" #include "orphan.h" #include <kj/string.h> #include <kj/string-tree.h> namespace capnp { class MessageBuilder; // So that it can be declared a friend. template <typename T, Kind k = kind<T>()> struct ToDynamic_; // Defined in dynamic.h, needs to be declared as everyone's friend. struct DynamicStruct; // So that it can be declared a friend. namespace _ { // private template <typename T> struct PointerHelpers<T, Kind::STRUCT> { static inline typename T::Reader get(StructReader reader, WirePointerCount index, const word* defaultValue = nullptr) { return typename T::Reader(reader.getStructField(index, defaultValue)); } static inline typename T::Builder get(StructBuilder builder, WirePointerCount index, const word* defaultValue = nullptr) { return typename T::Builder(builder.getStructField(index, structSize<T>(), defaultValue)); } static inline void set(StructBuilder builder, WirePointerCount index, typename T::Reader value) { builder.setStructField(index, value._reader); } static inline typename T::Builder init(StructBuilder builder, WirePointerCount index) { return typename T::Builder(builder.initStructField(index, structSize<T>())); } static inline void adopt(StructBuilder builder, WirePointerCount index, Orphan<T>&& value) { builder.adopt(index, kj::mv(value.builder)); } static inline Orphan<T> disown(StructBuilder builder, WirePointerCount index) { return Orphan<T>(builder.disown(index)); } }; template <typename T> struct PointerHelpers<List<T>, Kind::LIST> { static inline typename List<T>::Reader get(StructReader reader, WirePointerCount index, const word* defaultValue = nullptr) { return typename List<T>::Reader(List<T>::getAsFieldOf(reader, index, defaultValue)); } static inline typename List<T>::Builder get(StructBuilder builder, WirePointerCount index, const word* defaultValue = nullptr) { return typename List<T>::Builder(List<T>::getAsFieldOf(builder, index, defaultValue)); } static inline void set(StructBuilder builder, WirePointerCount index, typename List<T>::Reader value) { builder.setListField(index, value.reader); } template <typename U> static void set(StructBuilder builder, WirePointerCount index, std::initializer_list<U> value) { auto l = init(builder, index, value.size()); uint i = 0; for (auto& element: value) { l.set(i++, element); } } static inline typename List<T>::Builder init( StructBuilder builder, WirePointerCount index, uint size) { return typename List<T>::Builder(List<T>::initAsFieldOf(builder, index, size)); } static inline void adopt(StructBuilder builder, WirePointerCount index, Orphan<List<T>>&& value) { builder.adopt(index, kj::mv(value.builder)); } static inline Orphan<List<T>> disown(StructBuilder builder, WirePointerCount index) { return Orphan<List<T>>(builder.disown(index)); } }; template <typename T> struct PointerHelpers<T, Kind::BLOB> { static inline typename T::Reader get(StructReader reader, WirePointerCount index, const void* defaultValue = nullptr, uint defaultBytes = 0) { return reader.getBlobField<T>(index, defaultValue, defaultBytes * BYTES); } static inline typename T::Builder get(StructBuilder builder, WirePointerCount index, const void* defaultValue = nullptr, uint defaultBytes = 0) { return builder.getBlobField<T>(index, defaultValue, defaultBytes * BYTES); } static inline void set(StructBuilder builder, WirePointerCount index, typename T::Reader value) { builder.setBlobField<T>(index, value); } static inline typename T::Builder init(StructBuilder builder, WirePointerCount index, uint size) { return builder.initBlobField<T>(index, size * BYTES); } static inline void adopt(StructBuilder builder, WirePointerCount index, Orphan<T>&& value) { builder.adopt(index, kj::mv(value.builder)); } static inline Orphan<T> disown(StructBuilder builder, WirePointerCount index) { return Orphan<T>(builder.disown(index)); } }; struct UncheckedMessage { typedef const word* Reader; }; template <> struct PointerHelpers<UncheckedMessage> { // Reads an Object field as an unchecked message pointer. Requires that the containing message is // itself unchecked. This hack is currently private. It is used to locate default values within // encoded schemas. static inline const word* get(StructReader reader, WirePointerCount index) { return reader.getUncheckedPointer(index); } }; struct RawSchema { // The generated code defines a constant RawSchema for every compiled declaration. // // This is an internal structure which could change in the future. uint64_t id; const word* encodedNode; // Encoded SchemaNode, readable via readMessageUnchecked<schema::Node>(encodedNode). uint32_t encodedSize; // Size of encodedNode, in words. const RawSchema* const* dependencies; // Pointers to other types on which this one depends, sorted by ID. The schemas in this table // may be uninitialized -- you must call ensureInitialized() on the one you wish to use before // using it. // // TODO(someday): Make this a hashtable. struct MemberInfo { uint16_t unionIndex; // 0 = not in a union, >0 = parent union's index + 1 uint16_t index; // index of the member }; const MemberInfo* membersByName; // Indexes of members sorted by name. Used to implement name lookup. // TODO(someday): Make this a hashtable. uint32_t dependencyCount; uint32_t memberCount; // Sizes of above tables. const RawSchema* canCastTo; // Points to the RawSchema of a compiled-in type to which it is safe to cast any DynamicValue // with this schema. This is null for all compiled-in types; it is only set by SchemaLoader on // dynamically-loaded types. class Initializer { public: virtual void init(const RawSchema* schema) const = 0; }; const Initializer* lazyInitializer; // Lazy initializer, invoked by ensureInitialized(). inline void ensureInitialized() const { // Lazy initialization support. Invoke to ensure that initialization has taken place. This // is required in particular when traversing the dependency list. RawSchemas for compiled-in // types are always initialized; only dynamically-loaded schemas may be lazy. const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE); if (i != nullptr) i->init(this); } }; template <typename T> struct RawSchema_; template <typename T> inline const RawSchema& rawSchema() { return RawSchema_<T>::get(); } template <typename T> struct TypeId_; template <typename T> struct UnionMemberIndex_; template <typename T> inline uint unionMemberIndex() { return UnionMemberIndex_<T>::value; } template <typename T> struct UnionParentType_; template <typename T> using UnionParentType = typename UnionParentType_<T>::Type; kj::StringTree structString(StructReader reader, const RawSchema& schema); kj::StringTree unionString(StructReader reader, const RawSchema& schema, uint memberIndex); // Declared here so that we can declare inline stringify methods on generated types. // Defined in stringify.c++, which depends on dynamic.c++, which is allowed not to be linked in. template <typename T> inline kj::StringTree structString(StructReader reader) { return structString(reader, rawSchema<T>()); } template <typename T> inline kj::StringTree unionString(StructReader reader) { return unionString(reader, rawSchema<UnionParentType<T>>(), unionMemberIndex<T>()); } } // namespace _ (private) template <typename T> inline constexpr uint64_t typeId() { return _::TypeId_<T>::typeId; } // typeId<MyType>() returns the type ID as defined in the schema. Works with structs, enums, and // interfaces. } // namespace capnp #define CAPNP_DECLARE_ENUM(type, id) \ template <> struct Kind_<type> { static constexpr Kind kind = Kind::ENUM; }; \ template <> struct TypeId_<type> { static constexpr uint64_t typeId = 0x##id; }; \ template <> struct RawSchema_<type> { \ static inline const RawSchema& get() { return schemas::s_##id; } \ } #define CAPNP_DEFINE_ENUM(type) \ constexpr Kind Kind_<type>::kind; \ constexpr uint64_t TypeId_<type>::typeId; #define CAPNP_DECLARE_STRUCT(type, id, dataWordSize, pointerCount, preferredElementEncoding) \ template <> struct Kind_<type> { static constexpr Kind kind = Kind::STRUCT; }; \ template <> struct StructSize_<type> { \ static constexpr StructSize value = StructSize( \ dataWordSize * WORDS, pointerCount * POINTERS, FieldSize::preferredElementEncoding); \ }; \ template <> struct TypeId_<type> { static constexpr uint64_t typeId = 0x##id; }; \ template <> struct RawSchema_<type> { \ static inline const RawSchema& get() { return schemas::s_##id; } \ } #define CAPNP_DEFINE_STRUCT(type) \ constexpr Kind Kind_<type>::kind; \ constexpr StructSize StructSize_<type>::value; \ constexpr uint64_t TypeId_<type>::typeId; #define CAPNP_DECLARE_UNION(type, parentType, memberIndex) \ template <> struct Kind_<type> { static constexpr Kind kind = Kind::UNION; }; \ template <> struct UnionMemberIndex_<type> { static constexpr uint value = memberIndex; }; \ template <> struct UnionParentType_<type> { typedef parentType Type; } #define CAPNP_DEFINE_UNION(type) \ constexpr Kind Kind_<type>::kind; \ constexpr uint UnionMemberIndex_<type>::value; #define CAPNP_DECLARE_INTERFACE(type, id) \ template <> struct Kind_<type> { static constexpr Kind kind = Kind::INTERFACE; }; \ template <> struct TypeId_<type> { static constexpr uint64_t typeId = 0x##id; }; \ template <> struct RawSchema_<type> { \ static inline const RawSchema& get() { return schemas::s_##id; } \ } #define CAPNP_DEFINE_INTERFACE(type) \ constexpr Kind Kind_<type>::kind; \ constexpr uint64_t TypeId_<type>::typeId; #endif // CAPNP_GENERATED_HEADER_SUPPORT_H_